Skip to content

Commit e40bece

Browse files
authored
Add support for jwt validation (#783)
1 parent 8cfa1e9 commit e40bece

File tree

7 files changed

+61
-0
lines changed

7 files changed

+61
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ Baked-in Validations
159159
| isbn10 | International Standard Book Number 10 |
160160
| isbn13 | International Standard Book Number 13 |
161161
| json | JSON |
162+
| jwt | JSON Web Token (JWT) |
162163
| latitude | Latitude |
163164
| longitude | Longitude |
164165
| rgb | RGB String |

baked_in.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ var (
181181
"url_encoded": isURLEncoded,
182182
"dir": isDir,
183183
"json": isJSON,
184+
"jwt": isJWT,
184185
"hostname_port": isHostnamePort,
185186
"lowercase": isLowercase,
186187
"uppercase": isUppercase,
@@ -2235,6 +2236,11 @@ func isJSON(fl FieldLevel) bool {
22352236
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
22362237
}
22372238

2239+
// isJWT is the validation function for validating if the current field's value is a valid JWT string.
2240+
func isJWT(fl FieldLevel) bool {
2241+
return jWTRegex.MatchString(fl.Field().String())
2242+
}
2243+
22382244
// isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
22392245
func isHostnamePort(fl FieldLevel) bool {
22402246
val := fl.Field().String()

doc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,12 @@ This validates that a string value is valid JSON
811811
812812
Usage: json
813813
814+
JWT String
815+
816+
This validates that a string value is a valid JWT
817+
818+
Usage: jwt
819+
814820
File path
815821
816822
This validates that a string value contains a valid file path and that

regexes.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848
uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
4949
hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(&gt)|(&lt)|(&quot)|(&amp)+[;]?`
5050
hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
51+
jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$"
5152
splitParamsRegexString = `'[^']*'|\S+`
5253
bicRegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$`
5354
)
@@ -98,6 +99,7 @@ var (
9899
uRLEncodedRegex = regexp.MustCompile(uRLEncodedRegexString)
99100
hTMLEncodedRegex = regexp.MustCompile(hTMLEncodedRegexString)
100101
hTMLRegex = regexp.MustCompile(hTMLRegexString)
102+
jWTRegex = regexp.MustCompile(jWTRegexString)
101103
splitParamsRegex = regexp.MustCompile(splitParamsRegexString)
102104
bicRegex = regexp.MustCompile(bicRegexString)
103105
)

translations/en/en.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,11 @@ func RegisterDefaultTranslations(v *validator.Validate, trans ut.Translator) (er
12841284
translation: "{0} must be a valid json string",
12851285
override: false,
12861286
},
1287+
{
1288+
tag: "jwt",
1289+
translation: "{0} must be a valid jwt string",
1290+
override: false,
1291+
},
12871292
{
12881293
tag: "lowercase",
12891294
translation: "{0} must be a lowercase string",

translations/en/en_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ func TestTranslations(t *testing.T) {
141141
UniqueArray [3]string `validate:"unique"`
142142
UniqueMap map[string]string `validate:"unique"`
143143
JSONString string `validate:"json"`
144+
JWTString string `validate:"jwt"`
144145
LowercaseString string `validate:"lowercase"`
145146
UppercaseString string `validate:"uppercase"`
146147
Datetime string `validate:"datetime=2006-01-02"`
@@ -646,6 +647,10 @@ func TestTranslations(t *testing.T) {
646647
ns: "Test.JSONString",
647648
expected: "JSONString must be a valid json string",
648649
},
650+
{
651+
ns: "Test.JWTString",
652+
expected: "JWTString must be a valid jwt string",
653+
},
649654
{
650655
ns: "Test.LowercaseString",
651656
expected: "LowercaseString must be a lowercase string",

validator_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10787,6 +10787,42 @@ func TestJSONValidation(t *testing.T) {
1078710787
}, "Bad field type int")
1078810788
}
1078910789

10790+
func TestJWTValidation(t *testing.T) {
10791+
tests := []struct {
10792+
param string
10793+
expected bool
10794+
}{
10795+
{"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiZ29waGVyIn0.O_bROM_szPq9qBql-XDHMranHwP48ODdoLICWzqBr_U", true},
10796+
{"acb123-_.def456-_.ghi789-_", true},
10797+
{"eyJhbGciOiJOT05FIn0.e30.", true},
10798+
{"eyJhbGciOiJOT05FIn0.e30.\n", false},
10799+
{"\x00.\x00.\x00", false},
10800+
{"", false},
10801+
}
10802+
10803+
validate := New()
10804+
10805+
for i, test := range tests {
10806+
10807+
errs := validate.Var(test.param, "jwt")
10808+
10809+
if test.expected {
10810+
if !IsEqual(errs, nil) {
10811+
t.Fatalf("Index: %d jwt failed Error: %s", i, errs)
10812+
}
10813+
} else {
10814+
if IsEqual(errs, nil) {
10815+
t.Fatalf("Index: %d jwt failed Error: %s", i, errs)
10816+
} else {
10817+
val := getError(errs, "", "")
10818+
if val.Tag() != "jwt" {
10819+
t.Fatalf("Index: %d jwt failed Error: %s", i, errs)
10820+
}
10821+
}
10822+
}
10823+
}
10824+
}
10825+
1079010826
func Test_hostnameport_validator(t *testing.T) {
1079110827
type Host struct {
1079210828
Addr string `validate:"hostname_port"`

0 commit comments

Comments
 (0)