diff --git a/README.md b/README.md index 7dcc5af..cdbb805 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ Baked-in Validations | isbn10 | International Standard Book Number 10 | | isbn13 | International Standard Book Number 13 | | json | JSON | +| jwt | JSON Web Token (JWT) | | latitude | Latitude | | longitude | Longitude | | rgb | RGB String | diff --git a/baked_in.go b/baked_in.go index 224a1c2..b22c01a 100644 --- a/baked_in.go +++ b/baked_in.go @@ -181,6 +181,7 @@ var ( "url_encoded": isURLEncoded, "dir": isDir, "json": isJSON, + "jwt": isJWT, "hostname_port": isHostnamePort, "lowercase": isLowercase, "uppercase": isUppercase, @@ -2235,6 +2236,11 @@ func isJSON(fl FieldLevel) bool { panic(fmt.Sprintf("Bad field type %T", field.Interface())) } +// isJWT is the validation function for validating if the current field's value is a valid JWT string. +func isJWT(fl FieldLevel) bool { + return jWTRegex.MatchString(fl.Field().String()) +} + // isHostnamePort validates a : combination for fields typically used for socket address. func isHostnamePort(fl FieldLevel) bool { val := fl.Field().String() diff --git a/doc.go b/doc.go index eafad0d..cf1376b 100644 --- a/doc.go +++ b/doc.go @@ -811,6 +811,12 @@ This validates that a string value is valid JSON Usage: json +JWT String + +This validates that a string value is a valid JWT + + Usage: jwt + File path This validates that a string value contains a valid file path and that diff --git a/regexes.go b/regexes.go index ddcf785..df00c4e 100644 --- a/regexes.go +++ b/regexes.go @@ -48,6 +48,7 @@ const ( uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$` hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(")|(&)+[;]?` 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})?$` ) @@ -98,6 +99,7 @@ var ( uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString) hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString) hTMLRegex = regexp.MustCompile(hTMLRegexString) + jWTRegex = regexp.MustCompile(jWTRegexString) splitParamsRegex = regexp.MustCompile(splitParamsRegexString) bicRegex = regexp.MustCompile(bicRegexString) ) diff --git a/translations/en/en.go b/translations/en/en.go index 3bbca51..b95f7dd 100644 --- a/translations/en/en.go +++ b/translations/en/en.go @@ -1284,6 +1284,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er translation: "{0} must be a valid json string", override: false, }, + { + tag: "jwt", + translation: "{0} must be a valid jwt string", + override: false, + }, { tag: "lowercase", translation: "{0} must be a lowercase string", diff --git a/translations/en/en_test.go b/translations/en/en_test.go index fd8df77..0f20768 100644 --- a/translations/en/en_test.go +++ b/translations/en/en_test.go @@ -141,6 +141,7 @@ func TestTranslations(t *testing.T) { UniqueArray [3]string `validate:"unique"` UniqueMap map[string]string `validate:"unique"` JSONString string `validate:"json"` + JWTString string `validate:"jwt"` LowercaseString string `validate:"lowercase"` UppercaseString string `validate:"uppercase"` Datetime string `validate:"datetime=2006-01-02"` @@ -646,6 +647,10 @@ func TestTranslations(t *testing.T) { ns: "Test.JSONString", expected: "JSONString must be a valid json string", }, + { + ns: "Test.JWTString", + expected: "JWTString must be a valid jwt string", + }, { ns: "Test.LowercaseString", expected: "LowercaseString must be a lowercase string", diff --git a/validator_test.go b/validator_test.go index 3f0ea8d..8e9dc03 100644 --- a/validator_test.go +++ b/validator_test.go @@ -10787,6 +10787,42 @@ func TestJSONValidation(t *testing.T) { }, "Bad field type int") } +func TestJWTValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiZ29waGVyIn0.O_bROM_szPq9qBql-XDHMranHwP48ODdoLICWzqBr_U", true}, + {"acb123-_.def456-_.ghi789-_", true}, + {"eyJhbGciOiJOT05FIn0.e30.", true}, + {"eyJhbGciOiJOT05FIn0.e30.\n", false}, + {"\x00.\x00.\x00", false}, + {"", false}, + } + + validate := New() + + for i, test := range tests { + + errs := validate.Var(test.param, "jwt") + + if test.expected { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d jwt failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d jwt failed Error: %s", i, errs) + } else { + val := getError(errs, "", "") + if val.Tag() != "jwt" { + t.Fatalf("Index: %d jwt failed Error: %s", i, errs) + } + } + } + } +} + func Test_hostnameport_validator(t *testing.T) { type Host struct { Addr string `validate:"hostname_port"`