Implement sort_regexp_validator_groups

This commit is contained in:
nemunaire 2022-01-21 08:28:39 +01:00
parent 081ad1f928
commit 5a79343af8
7 changed files with 42 additions and 26 deletions

View File

@ -399,16 +399,17 @@ func deleteExerciceHint(hint *fic.EHint, _ []byte) (interface{}, error) {
}
type uploadedFlag struct {
Type string
Label string
Placeholder string
IgnoreCase bool
Multiline bool
NoTrim bool
ValidatorRe *string `json:"validator_regexp"`
Flag string
Value []byte
ChoicesCost int64 `json:"choices_cost"`
Type string
Label string
Placeholder string
IgnoreCase bool
Multiline bool
NoTrim bool
ValidatorRe *string `json:"validator_regexp"`
SortReGroups bool `json:"sort_re_grps"`
Flag string
Value []byte
ChoicesCost int64 `json:"choices_cost"`
}
func createExerciceFlag(exercice *fic.Exercice, body []byte) (interface{}, error) {
@ -426,7 +427,7 @@ func createExerciceFlag(exercice *fic.Exercice, body []byte) (interface{}, error
vre = uk.ValidatorRe
}
return exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.NoTrim, uk.Multiline, vre, []byte(uk.Flag), uk.ChoicesCost)
return exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.NoTrim, uk.Multiline, vre, uk.SortReGroups, []byte(uk.Flag), uk.ChoicesCost)
}
func showExerciceFlag(flag *fic.FlagKey, _ *fic.Exercice, body []byte) (interface{}, error) {

View File

@ -40,6 +40,7 @@ type ExerciceFlag struct {
CaseSensitive bool `toml:",omitempty"`
NoTrim bool `toml:",omitempty"`
ValidatorRe string `toml:"validator_regexp,omitempty"`
SortReGroups bool `toml:"sort_validator_regexp_groups,omitempty"`
Placeholder string `toml:",omitempty"`
Help string `toml:",omitempty"`
ChoicesCost int64 `toml:"choices_cost,omitempty"`

View File

@ -124,7 +124,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
errs = append(errs, fmt.Sprintf("%q: WARNING flag #%d: non-printable characters in flag, is this really expected?", path.Base(exercice.Path), flagline))
}
hashedFlag, err := fic.ComputeHashedFlag([]byte(raw), !flag.CaseSensitive, flag.NoTrim, validatorRegexp(flag.ValidatorRe))
hashedFlag, err := fic.ComputeHashedFlag([]byte(raw), !flag.CaseSensitive, flag.NoTrim, validatorRegexp(flag.ValidatorRe), flag.SortReGroups)
if err != nil {
errs = append(errs, fmt.Sprintf("%q: flag #%d: %s", path.Base(exercice.Path), flagline, err.Error()))
return
@ -140,6 +140,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
IgnoreCase: !flag.CaseSensitive,
Multiline: flag.Type == "text",
ValidatorRegexp: validatorRegexp(flag.ValidatorRe),
SortReGroups: flag.SortReGroups,
Checksum: hashedFlag[:],
ChoicesCost: flag.ChoicesCost,
})

View File

@ -193,6 +193,7 @@ CREATE TABLE IF NOT EXISTS exercice_flags(
notrim BOOLEAN NOT NULL DEFAULT 0,
multiline BOOLEAN NOT NULL DEFAULT 0,
validator_regexp VARCHAR(255) NULL,
sort_re_grps BOOLEAN NOT NULL DEFAULT 0,
cksum BINARY(64) NOT NULL,
choices_cost INTEGER NOT NULL,
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)

View File

@ -332,7 +332,7 @@ func (f *EFile) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil {
return nil, err
}
deps = append(deps, &FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, false, nil, []byte{}, 0})
deps = append(deps, &FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, false, nil, false, []byte{}, 0})
}
if err := rows.Err(); err != nil {
return nil, err

View File

@ -5,6 +5,8 @@ import (
"errors"
"fmt"
"regexp"
"sort"
"strings"
"time"
"golang.org/x/crypto/blake2b"
@ -35,6 +37,8 @@ type FlagKey struct {
Multiline bool `json:"multiline"`
// ValidatorRegexp extracts a subset of the player's answer, that will be checked.
ValidatorRegexp *string `json:"validator_regexp"`
// SortReGroups indicates if groups resulting of the validator regexp should be sorted.
SortReGroups bool `json:"sort_re_grps"`
// Checksum is the expected hashed flag
Checksum []byte `json:"value"`
// ChoicesCost is the number of points lost to display choices.
@ -43,7 +47,7 @@ type FlagKey struct {
// GetFlagKeys returns a list of key's flags comming with the challenge.
func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
return nil, err
} else {
defer rows.Close()
@ -53,7 +57,7 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
k := &FlagKey{}
k.IdExercice = e.Id
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil {
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost); err != nil {
return nil, err
}
@ -70,19 +74,19 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
// GetFlagKey returns a list of flags comming with the challenge.
func GetFlagKey(id int) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.NoTrim, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.NoTrim, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost)
return
}
// GetFlagKeyByLabel returns a flag matching the given label.
func (e *Exercice) GetFlagKeyByLabel(label string) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost)
return
}
// ComputeHashedFlag calculates the expected checksum for the given raw_value.
func ComputeHashedFlag(raw_value []byte, ignorecase bool, notrim bool, validator_regexp *string) (hash [blake2b.Size]byte, err error) {
func ComputeHashedFlag(raw_value []byte, ignorecase bool, notrim bool, validator_regexp *string, sortregroups bool) (hash [blake2b.Size]byte, err error) {
if ignorecase {
raw_value = bytes.ToLower(raw_value)
}
@ -93,7 +97,7 @@ func ComputeHashedFlag(raw_value []byte, ignorecase bool, notrim bool, validator
// Check that raw value passes through the regexp
if validator_regexp != nil {
if raw_value, err = ExecValidatorRegexp(*validator_regexp, raw_value, ignorecase); err != nil {
if raw_value, err = ExecValidatorRegexp(*validator_regexp, raw_value, ignorecase, sortregroups); err != nil {
return
}
}
@ -107,7 +111,7 @@ func ComputeHashedFlag(raw_value []byte, ignorecase bool, notrim bool, validator
return
}
func ExecValidatorRegexp(vre string, val []byte, ignorecase bool) ([]byte, error) {
func ExecValidatorRegexp(vre string, val []byte, ignorecase bool, sortregroups bool) ([]byte, error) {
if ignorecase {
vre = "(?i)" + vre
}
@ -115,14 +119,21 @@ func ExecValidatorRegexp(vre string, val []byte, ignorecase bool) ([]byte, error
return val, err
} else if res := re.FindSubmatch(val); res == nil {
return val, errors.New("expected flag doesn't pass through the validator_regexp")
} else if sortregroups && len(res) > 2 {
var tab []string
for _, v := range res[1:] {
tab = append(tab, string(v))
}
sort.Strings(tab)
return []byte(strings.Join(tab, "+")), nil
} else {
return bytes.Join(res[1:], []byte("+")), nil
}
}
// AddRawFlagKey creates and fills a new struct FlagKey, from a non-hashed flag, and registers it into the database.
func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, notrim bool, validator_regexp *string, raw_value []byte, choicescost int64) (*FlagKey, error) {
hash, err := ComputeHashedFlag(raw_value, ignorecase, notrim, validator_regexp)
func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, notrim bool, validator_regexp *string, sortregroups bool, raw_value []byte, choicescost int64) (*FlagKey, error) {
hash, err := ComputeHashedFlag(raw_value, ignorecase, notrim, validator_regexp, sortregroups)
if err != nil {
return nil, err
}
@ -135,6 +146,7 @@ func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, igno
NoTrim: notrim,
Multiline: multiline,
ValidatorRegexp: validator_regexp,
SortReGroups: sortregroups,
Checksum: hash[:],
ChoicesCost: choicescost,
}
@ -166,7 +178,7 @@ func (k *FlagKey) Create(e *Exercice) (Flag, error) {
}
}
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost); err != nil {
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost); err != nil {
return k, err
} else if kid, err := res.LastInsertId(); err != nil {
return k, err
@ -179,7 +191,7 @@ func (k *FlagKey) Create(e *Exercice) (Flag, error) {
// ComputeChecksum calculates the checksum for a given value.
func (k *FlagKey) ComputeChecksum(val []byte) ([]byte, error) {
cksum, err := ComputeHashedFlag(val, k.IgnoreCase, k.NoTrim, k.ValidatorRegexp)
cksum, err := ComputeHashedFlag(val, k.IgnoreCase, k.NoTrim, k.ValidatorRegexp, k.SortReGroups)
return cksum[:], err
}
@ -191,7 +203,7 @@ func (k *FlagKey) Update() (int64, error) {
}
}
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, ordre = ?, label = ?, type = ?, placeholder = ?, help = ?, unit = ?, ignorecase = ?, notrim = ?, multiline = ?, validator_regexp = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost, k.Id); err != nil {
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, ordre = ?, label = ?, type = ?, placeholder = ?, help = ?, unit = ?, ignorecase = ?, notrim = ?, multiline = ?, validator_regexp = ?, sort_re_grps = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost, k.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err

View File

@ -356,7 +356,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
}
if t == nil {
h, _ := ComputeHashedFlag([]byte(soluce), false, false, nil)
h, _ := ComputeHashedFlag([]byte(soluce), false, false, nil, false)
m.Soluce = hex.EncodeToString(h[:])
}