Skip to content

Commit b43d437

Browse files
feat: ✨ add cve validator (#983)
1 parent 58d420d commit b43d437

File tree

9 files changed

+86
-0
lines changed

9 files changed

+86
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ Baked-in Validations
207207
| tiger192 | TIGER192 hash |
208208
| semver | Semantic Versioning 2.0.0 |
209209
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
210+
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) |
210211

211212
### Comparisons:
212213
| Tag | Description |

baked_in.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ var (
223223
"semver": isSemverFormat,
224224
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
225225
"credit_card": isCreditCard,
226+
"cve": isCveFormat,
226227
"luhn_checksum": hasLuhnChecksum,
227228
"mongodb": isMongoDB,
228229
"cron": isCron,
@@ -2674,6 +2675,13 @@ func isSemverFormat(fl FieldLevel) bool {
26742675
return semverRegex.MatchString(semverString)
26752676
}
26762677

2678+
// isCveFormat is the validation function for validating if the current field's value is a valid cve id, defined in CVE mitre org
2679+
func isCveFormat(fl FieldLevel) bool {
2680+
cveString := fl.Field().String()
2681+
2682+
return cveRegex.MatchString(cveString)
2683+
}
2684+
26772685
// isDnsRFC1035LabelFormat is the validation function
26782686
// for validating if the current field's value is
26792687
// a valid dns RFC 1035 label, defined in RFC 1035.

doc.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,15 @@ More information on https://semver.org/
13501350
13511351
Usage: semver
13521352
1353+
1354+
# CVE Identifier
1355+
1356+
This validates that a string value is a valid cve id, defined in cve mitre.
1357+
More information on https://cve.mitre.org/
1358+
1359+
Usage: cve
1360+
1361+
13531362
# Credit Card
13541363
13551364
This validates that a string value contains a valid credit card number using Luhn algoritm.

regexes.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const (
6565
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
6666
semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` // numbered capture groups https://semver.org/
6767
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
68+
cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^0]\d{1}|0\d{2}[^0]|[1-9]{1}\d{3,})$` // CVE Format Id https://cve.mitre.org/cve/identifiers/syntaxchange.html
6869
mongodbRegexString = "^[a-f\\d]{24}$"
6970
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
7071
)
@@ -130,6 +131,7 @@ var (
130131
bicRegex = regexp.MustCompile(bicRegexString)
131132
semverRegex = regexp.MustCompile(semverRegexString)
132133
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
134+
cveRegex = regexp.MustCompile(cveRegexString)
133135
mongodbRegex = regexp.MustCompile(mongodbRegexString)
134136
cronRegex = regexp.MustCompile(cronRegexString)
135137
)

translations/en/en.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
13661366
translation: "{0} must be a valid boolean value",
13671367
override: false,
13681368
},
1369+
{
1370+
tag: "cve",
1371+
translation: "{0} must be a valid cve identifier",
1372+
override: false,
1373+
},
13691374
}
13701375

13711376
for _, t := range translations {

translations/en/en_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ func TestTranslations(t *testing.T) {
153153
PostCodeCountry string
154154
PostCodeByField string `validate:"postcode_iso3166_alpha2_field=PostCodeCountry"`
155155
BooleanString string `validate:"boolean"`
156+
CveString string `validate:"cve"`
156157
}
157158

158159
var test Test
@@ -206,6 +207,7 @@ func TestTranslations(t *testing.T) {
206207
test.UniqueMap = map[string]string{"key1": "1234", "key2": "1234"}
207208
test.Datetime = "2008-Feb-01"
208209
test.BooleanString = "A"
210+
test.CveString = "A"
209211

210212
test.Inner.RequiredIf = "abcd"
211213

@@ -695,6 +697,10 @@ func TestTranslations(t *testing.T) {
695697
ns: "Test.BooleanString",
696698
expected: "BooleanString must be a valid boolean value",
697699
},
700+
{
701+
ns: "Test.CveString",
702+
expected: "CveString must be a valid cve identifier",
703+
},
698704
}
699705

700706
for _, tt := range tests {

translations/pt_BR/pt_BR.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
13211321
translation: "{0} deve ser um valor booleano válido",
13221322
override: false,
13231323
},
1324+
{
1325+
tag: "cve",
1326+
translation: "{0} deve ser um identificador cve válido",
1327+
override: false,
1328+
},
13241329
}
13251330

13261331
for _, t := range translations {

translations/pt_BR/pt_BR_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ func TestTranslations(t *testing.T) {
140140
OneOfString string `validate:"oneof=red green"`
141141
OneOfInt int `validate:"oneof=5 63"`
142142
BooleanString string `validate:"boolean"`
143+
CveString string `validate:"cve"`
143144
}
144145

145146
var test Test
@@ -173,6 +174,7 @@ func TestTranslations(t *testing.T) {
173174
test.NumericString = "12E.00"
174175
test.NumberString = "12E"
175176
test.BooleanString = "A"
177+
test.CveString = "A"
176178

177179
test.Excludes = "este é um texto de teste"
178180
test.ExcludesAll = "Isso é Ótimo!"
@@ -625,6 +627,10 @@ func TestTranslations(t *testing.T) {
625627
ns: "Test.BooleanString",
626628
expected: "BooleanString deve ser um valor booleano válido",
627629
},
630+
{
631+
ns: "Test.CveString",
632+
expected: "CveString deve ser um identificador cve válido",
633+
},
628634
}
629635

630636
for _, tt := range tests {

validator_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12374,6 +12374,50 @@ func TestSemverFormatValidation(t *testing.T) {
1237412374
}
1237512375
}
1237612376

12377+
func TestCveFormatValidation(t *testing.T) {
12378+
12379+
tests := []struct {
12380+
value string `validate:"cve"`
12381+
tag string
12382+
expected bool
12383+
}{
12384+
{"CVE-1999-0001", "cve", true},
12385+
{"CVE-1998-0001", "cve", false},
12386+
{"CVE-2000-0001", "cve", true},
12387+
{"CVE-2222-0001", "cve", true},
12388+
{"2222-0001", "cve", false},
12389+
{"-2222-0001", "cve", false},
12390+
{"CVE22220001", "cve", false},
12391+
{"CVE-2222-000001", "cve", false},
12392+
{"CVE-2222-100001", "cve", true},
12393+
{"CVE-2222-99999999999", "cve", true},
12394+
{"CVE-3000-0001", "cve", false},
12395+
{"CVE-1999-0000", "cve", false},
12396+
{"CVE-2099-0000", "cve", false},
12397+
}
12398+
12399+
validate := New()
12400+
12401+
for i, test := range tests {
12402+
errs := validate.Var(test.value, test.tag)
12403+
12404+
if test.expected {
12405+
if !IsEqual(errs, nil) {
12406+
t.Fatalf("Index: %d cve failed Error: %s", i, errs)
12407+
}
12408+
} else {
12409+
if IsEqual(errs, nil) {
12410+
t.Fatalf("Index: %d cve failed Error: %s", i, errs)
12411+
} else {
12412+
val := getError(errs, "", "")
12413+
if val.Tag() != "cve" {
12414+
t.Fatalf("Index: %d cve failed Error: %s", i, errs)
12415+
}
12416+
}
12417+
}
12418+
}
12419+
}
12420+
1237712421
func TestRFC1035LabelFormatValidation(t *testing.T) {
1237812422
tests := []struct {
1237912423
value string `validate:"dns_rfc1035_label"`

0 commit comments

Comments
 (0)