Skip to content

Commit ab370b6

Browse files
authored
MongoDB validator improved (#1196)
## Enhances Added MongoDB connection string validation **Make sure that you've checked the boxes below before you submit PR:** - [x] Tests exist or have been written that cover this particular change. @go-playground/validator-maintainers
1 parent e20b948 commit ab370b6

File tree

5 files changed

+78
-8
lines changed

5 files changed

+78
-8
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ validate := validator.New(validator.WithRequiredStructEnabled())
163163
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
164164
| credit_card | Credit Card Number |
165165
| mongodb | MongoDB ObjectID |
166+
| mongodb_connection_string | MongoDB Connection String |
166167
| cron | Cron |
167168
| spicedb | SpiceDb ObjectID/Permission/Type |
168169
| datetime | Datetime |

baked_in.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ var (
235235
"credit_card": isCreditCard,
236236
"cve": isCveFormat,
237237
"luhn_checksum": hasLuhnChecksum,
238-
"mongodb": isMongoDB,
238+
"mongodb": isMongoDBObjectId,
239+
"mongodb_connection_string": isMongoDBConnectionString,
239240
"cron": isCron,
240241
"spicedb": isSpiceDB,
241242
}
@@ -2926,10 +2927,16 @@ func digitsHaveLuhnChecksum(digits []string) bool {
29262927
return (sum % 10) == 0
29272928
}
29282929

2929-
// isMongoDB is the validation function for validating if the current field's value is valid mongoDB objectID
2930-
func isMongoDB(fl FieldLevel) bool {
2930+
// isMongoDBObjectId is the validation function for validating if the current field's value is valid MongoDB ObjectID
2931+
func isMongoDBObjectId(fl FieldLevel) bool {
29312932
val := fl.Field().String()
2932-
return mongodbRegex.MatchString(val)
2933+
return mongodbIdRegex.MatchString(val)
2934+
}
2935+
2936+
// isMongoDBConnectionString is the validation function for validating if the current field's value is valid MongoDB Connection String
2937+
func isMongoDBConnectionString(fl FieldLevel) bool {
2938+
val := fl.Field().String()
2939+
return mongodbConnectionRegex.MatchString(val)
29332940
}
29342941

29352942
// isSpiceDB is the validation function for validating if the current field's value is valid for use with Authzed SpiceDB in the indicated way

doc.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,11 +1386,19 @@ This validates that a string value contains a valid credit card number using Luh
13861386
13871387
This validates that a string or (u)int value contains a valid checksum using the Luhn algorithm.
13881388
1389-
# MongoDb ObjectID
1389+
# MongoDB
13901390
1391-
This validates that a string is a valid 24 character hexadecimal string.
1391+
This validates that a string is a valid 24 character hexadecimal string or valid connection string.
13921392
13931393
Usage: mongodb
1394+
mongodb_connection_string
1395+
1396+
Example:
1397+
1398+
type Test struct {
1399+
ObjectIdField string `validate:"mongodb"`
1400+
ConnectionStringField string `validate:"mongodb_connection_string"`
1401+
}
13941402
13951403
# Cron
13961404

regexes.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ const (
6868
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/
6969
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9]){0,62}$"
7070
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
71-
mongodbRegexString = "^[a-f\\d]{24}$"
71+
mongodbIdRegexString = "^[a-f\\d]{24}$"
72+
mongodbConnStringRegexString = "^mongodb(\\+srv)?:\\/\\/(([a-zA-Z\\d]+):([a-zA-Z\\d$:\\/?#\\[\\]@]+)@)?(([a-z\\d.-]+)(:[\\d]+)?)((,(([a-z\\d.-]+)(:(\\d+))?))*)?(\\/[a-zA-Z-_]{1,64})?(\\?(([a-zA-Z]+)=([a-zA-Z\\d]+))(&(([a-zA-Z\\d]+)=([a-zA-Z\\d]+))?)*)?$"
7273
cronRegexString = `(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|(@every (\d+(ns|us|µs|ms|s|m|h))+)|((((\d+,)+\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})`
7374
spicedbIDRegexString = `^(([a-zA-Z0-9/_|\-=+]{1,})|\*)$`
7475
spicedbPermissionRegexString = "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$"
@@ -139,7 +140,8 @@ var (
139140
semverRegex = regexp.MustCompile(semverRegexString)
140141
dnsRegexRFC1035Label = regexp.MustCompile(dnsRegexStringRFC1035Label)
141142
cveRegex = regexp.MustCompile(cveRegexString)
142-
mongodbRegex = regexp.MustCompile(mongodbRegexString)
143+
mongodbIdRegex = regexp.MustCompile(mongodbIdRegexString)
144+
mongodbConnectionRegex = regexp.MustCompile(mongodbConnStringRegexString)
143145
cronRegex = regexp.MustCompile(cronRegexString)
144146
spicedbIDRegex = regexp.MustCompile(spicedbIDRegexString)
145147
spicedbPermissionRegex = regexp.MustCompile(spicedbPermissionRegexString)

validator_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13386,6 +13386,58 @@ func TestMongoDBObjectIDFormatValidation(t *testing.T) {
1338613386
}
1338713387
}
1338813388
}
13389+
func TestMongoDBConnectionStringFormatValidation(t *testing.T) {
13390+
tests := []struct {
13391+
value string `validate:"mongodb_connection_string"`
13392+
tag string
13393+
expected bool
13394+
}{
13395+
{"mongodb://username:[email protected]:20017/database?replicaSet=test&connectTimeoutMS=300000&ssl=true", "mongodb_connection_string", true},
13396+
{"mongodb+srv://username:[email protected]:20017/database?replicaSet=test&connectTimeoutMS=300000&ssl=true", "mongodb_connection_string", true},
13397+
{"mongodb+srv://username:[email protected]:20017,server.example.com,server.example.com:20017/database?replicaSet=test&connectTimeoutMS=300000&ssl=true", "mongodb_connection_string", true},
13398+
{"mongodb+srv://username:[email protected]:20017,server.example.com,server.example.com:20017?replicaSet=test&connectTimeoutMS=300000&ssl=true", "mongodb_connection_string", true},
13399+
{"mongodb://username:[email protected]:20017,server.example.com,server.example.com:20017/database?replicaSet=test&connectTimeoutMS=300000&ssl=true", "mongodb_connection_string", true},
13400+
{"mongodb://localhost", "mongodb_connection_string", true},
13401+
{"mongodb://localhost:27017", "mongodb_connection_string", true},
13402+
{"localhost", "mongodb_connection_string", false},
13403+
{"mongodb://", "mongodb_connection_string", false},
13404+
{"mongodb+srv://", "mongodb_connection_string", false},
13405+
{"mongodbsrv://localhost", "mongodb_connection_string", false},
13406+
{"mongodb+srv://localhost", "mongodb_connection_string", true},
13407+
{"mongodb+srv://localhost:27017", "mongodb_connection_string", true},
13408+
{"mongodb+srv://localhost?replicaSet=test", "mongodb_connection_string", true},
13409+
{"mongodb+srv://localhost:27017?replicaSet=test", "mongodb_connection_string", true},
13410+
{"mongodb+srv://localhost:27017?", "mongodb_connection_string", false},
13411+
{"mongodb+srv://localhost:27017?replicaSet", "mongodb_connection_string", false},
13412+
{"mongodb+srv://localhost/database", "mongodb_connection_string", true},
13413+
{"mongodb+srv://localhost:27017/database", "mongodb_connection_string", true},
13414+
{"mongodb+srv://username@localhost", "mongodb_connection_string", false},
13415+
{"mongodb+srv://username:password@localhost", "mongodb_connection_string", true},
13416+
{"mongodb+srv://username:password@localhost:27017", "mongodb_connection_string", true},
13417+
{"mongodb+srv://username:password@localhost:27017,192.0.0.7,192.0.0.9:27018,server.example.com", "mongodb_connection_string", true},
13418+
}
13419+
13420+
validate := New()
13421+
13422+
for i, test := range tests {
13423+
errs := validate.Var(test.value, test.tag)
13424+
13425+
if test.expected {
13426+
if !IsEqual(errs, nil) {
13427+
t.Fatalf("Index: %d mongodb_connection_string failed Error: %s", i, errs)
13428+
}
13429+
} else {
13430+
if IsEqual(errs, nil) {
13431+
t.Fatalf("Index: %d mongodb_connection_string failed Error: %s", i, errs)
13432+
} else {
13433+
val := getError(errs, "", "")
13434+
if val.Tag() != "mongodb_connection_string" {
13435+
t.Fatalf("Index: %d mongodb_connection_string failed Error: %s", i, errs)
13436+
}
13437+
}
13438+
}
13439+
}
13440+
}
1338913441

1339013442
func TestSpiceDBValueFormatValidation(t *testing.T) {
1339113443
tests := []struct {

0 commit comments

Comments
 (0)