Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ validate := validator.New(validator.WithRequiredStructEnabled())
| base64 | Base64 String |
| base64url | Base64URL String |
| base64rawurl | Base64RawURL String |
| bic | Business Identifier Code (ISO 9362) |
| bic_iso_9362_2014 | Business Identifier Code (ISO 9362:2014) |
| bic | Business Identifier Code (ISO 9362:2022) |
| bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
Expand Down
16 changes: 12 additions & 4 deletions baked_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ var (
"bcp47_language_tag": isBCP47LanguageTag,
"postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
"bic": isIsoBicFormat,
"bic_iso_9362_2014": isIsoBic2014Format,
"bic": isIsoBic2022Format,
"semver": isSemverFormat,
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
"credit_card": isCreditCard,
Expand Down Expand Up @@ -2943,11 +2944,18 @@ func isBCP47LanguageTag(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}

// isIsoBicFormat is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362
func isIsoBicFormat(fl FieldLevel) bool {
// isIsoBic2014Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2014
func isIsoBic2014Format(fl FieldLevel) bool {
bicString := fl.Field().String()

return bicRegex().MatchString(bicString)
return bic2014Regex().MatchString(bicString)
}

// isIsoBic2022Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2022
func isIsoBic2022Format(fl FieldLevel) bool {
bicString := fl.Field().String()

return bic2022Regex().MatchString(bicString)
}

// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0
Expand Down
6 changes: 4 additions & 2 deletions regexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ const (
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
splitParamsRegexString = `'[^']*'|\S+`
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
bic2014RegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
bic2022RegexString = `^[A-Z0-9]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?$`
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/
dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9])?$"
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
Expand Down Expand Up @@ -153,7 +154,8 @@ var (
hTMLRegex = lazyRegexCompile(hTMLRegexString)
jWTRegex = lazyRegexCompile(jWTRegexString)
splitParamsRegex = lazyRegexCompile(splitParamsRegexString)
bicRegex = lazyRegexCompile(bicRegexString)
bic2014Regex = lazyRegexCompile(bic2014RegexString)
bic2022Regex = lazyRegexCompile(bic2022RegexString)
semverRegex = lazyRegexCompile(semverRegexString)
dnsRegexRFC1035Label = lazyRegexCompile(dnsRegexStringRFC1035Label)
cveRegex = lazyRegexCompile(cveRegexString)
Expand Down
78 changes: 76 additions & 2 deletions validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13202,7 +13202,47 @@ func TestBCP47LanguageTagValidation(t *testing.T) {
}, "Bad field type int")
}

func TestBicIsoFormatValidation(t *testing.T) {
func TestBicIso2014FormatValidation(t *testing.T) {
tests := []struct {
value string `validate:"bic_iso_9362_2014"`
tag string
expected bool
}{
{"SBICKEN1345", "bic_iso_9362_2014", true},
{"SBICKEN1", "bic_iso_9362_2014", true},
{"SBICKENY", "bic_iso_9362_2014", true},
{"SBICKEN1YYP", "bic_iso_9362_2014", true},
{"SBIC23NXXX", "bic_iso_9362_2014", false},
{"S23CKENXXXX", "bic_iso_9362_2014", false},
{"SBICKENXX", "bic_iso_9362_2014", false},
{"SBICKENXX9", "bic_iso_9362_2014", false},
{"SBICKEN13458", "bic_iso_9362_2014", false},
{"SBICKEN", "bic_iso_9362_2014", false},
}

validate := New()

for i, test := range tests {
errs := validate.Var(test.value, test.tag)

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != "bic_iso_9362_2014" {
t.Fatalf("Index: %d bic_iso_9362_2014 failed Error: %s", i, errs)
}
}
}
}
}

func TestBicIso2022FormatValidation(t *testing.T) {
tests := []struct {
value string `validate:"bic"`
tag string
Expand All @@ -13212,12 +13252,46 @@ func TestBicIsoFormatValidation(t *testing.T) {
{"SBICKEN1", "bic", true},
{"SBICKENY", "bic", true},
{"SBICKEN1YYP", "bic", true},
{"E097AEXX", "bic", true}, // valid under https://www.iso.org/standard/84108.html
{"SBIC23NXXX", "bic", false},
{"S23CKENXXXX", "bic", false},
{"S23CKENXXXX", "bic", true},
{"SBICKENXX", "bic", false},
{"SBICKENXX9", "bic", false},
{"SBICKEN13458", "bic", false},
{"SBICKEN", "bic", false},
{"DEUTDEFF", "bic", true}, // 8-char classic (Germany)
{"DEUTDEFF500", "bic", true}, // 11-char with numeric branch
{"A1B2US33", "bic", true}, // digits allowed in 4!c (bank code)
{"1234US33", "bic", true}, // all digits in 4!c (2022)
{"ZZZ1USAA", "bic", true}, // mixed alnum bank + alnum location
{"AB12AE00", "bic", true}, // UAE 8-char
{"AB12AE009Z9", "bic", true}, // UAE 11-char with mixed branch
{"WG11US335AB", "bic", true}, // example-style with digits in branch
{"BNPAFRPP", "bic", true}, // France (BNP Paribas style)
{"BOFAUS3NXXX", "bic", true}, // US with default XXX branch
{"HSBCHKHHXXX", "bic", true}, // Hong Kong, default branch
{"NEDSZAJJ", "bic", true}, // South Africa 8-char
{"BARCGB22", "bic", true}, // GB 8-char
{"BARCGB22XXX", "bic", true}, // GB 11-char with XXX branch
{"0000GB00", "bic", true}, // 4!c all digits + 2!c all digits (allowed)
{"A1B2GB00XXX", "bic", true}, // valid 11-char with numeric location and XXX
{"TATRAEBX", "bic", true}, // UAE 8-char
{"TATRSABX", "bic", true}, // Saudi 8-char
{"TATREGBX", "bic", true}, // Egypt 8-char
{"TATRBHBX", "bic", true}, // Bahrain 8-char

{"DEUTDEFFF", "bic", false}, // 9-char (invalid length)
{"DEUTDEFF5", "bic", false}, // 9-char (invalid length)
{"DEUTDE", "bic", false}, // 6-char (invalid length)
{"DEUTDEFF50", "bic", false}, // 10-char (invalid length)
{"DEUTDEFF5000", "bic", false}, // 12-char (invalid length)
{"deUTDEFF", "bic", false}, // lowercase not allowed
{"DEUTDEfF", "bic", false}, // lowercase in location
{"DEU@DEFF", "bic", false}, // special char in bank
{"ABCD12FF", "bic", false}, // digits in 2!a country (invalid)
{"ABCDDE1-", "bic", false}, // hyphen in location
{"ABCDDE1_", "bic", false}, // underscore in location
{"ABCDDE١٢", "bic", false}, // non-ASCII digits in location
}

validate := New()
Expand Down