add validation for base64 url without = padding (#1024)

Co-authored-by: Yasoob Haider <yasoob.haider@zomato.com>
Co-authored-by: Dean Karn <Dean.Karn@gmail.com>
pull/1081/head
Yasoob Haider 1 year ago committed by GitHub
parent 1c1f70d35b
commit 29d50ba963
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      README.md
  2. 6
      baked_in.go
  3. 2
      cache.go
  4. 315
      doc.go
  5. 2
      regexes.go
  6. 1
      validator.go
  7. 19
      validator_instance.go
  8. 47
      validator_test.go

@ -150,6 +150,7 @@ Baked-in Validations
| - | - |
| base64 | Base64 String |
| base64url | Base64URL String |
| base64rawurl | Base64RawURL String |
| bic | Business Identifier Code (ISO 9362) |
| bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address |

@ -129,6 +129,7 @@ var (
"file": isFile,
"base64": isBase64,
"base64url": isBase64URL,
"base64rawurl": isBase64RawURL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
@ -1364,6 +1365,11 @@ func isBase64URL(fl FieldLevel) bool {
return base64URLRegex.MatchString(fl.Field().String())
}
// isBase64RawURL is the validation function for validating if the current field's value is a valid base64 URL safe string without '=' padding.
func isBase64RawURL(fl FieldLevel) bool {
return base64RawURLRegex.MatchString(fl.Field().String())
}
// isURI is the validation function for validating if the current field's value is a valid URI.
func isURI(fl FieldLevel) bool {
field := fl.Field()

@ -120,7 +120,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr
var fld reflect.StructField
var tag string
var customName string
for i := 0; i < numFields; i++ {
fld = typ.Field(i)

315
doc.go

File diff suppressed because it is too large Load Diff

@ -19,6 +19,7 @@ const (
e164RegexString = "^\\+[1-9]?[0-9]{7,14}$"
base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=|[A-Za-z0-9-_]{4})$"
base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2,4})$"
iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
@ -84,6 +85,7 @@ var (
emailRegex = regexp.MustCompile(emailRegexString)
base64Regex = regexp.MustCompile(base64RegexString)
base64URLRegex = regexp.MustCompile(base64URLRegexString)
base64RawURLRegex = regexp.MustCompile(base64RawURLRegexString)
iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
uUID3Regex = regexp.MustCompile(uUID3RegexString)

@ -452,7 +452,6 @@ OUTER:
v.ct = ct
if !ct.fn(ctx, v) {
v.str1 = string(append(ns, cf.altName...))
if v.v.hasTagNameFunc {

@ -190,14 +190,14 @@ func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]int
//
// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
//
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
// // skip if tag key says it should be ignored
// if name == "-" {
// return ""
// }
// return name
// })
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
// // skip if tag key says it should be ignored
// if name == "-" {
// return ""
// }
// return name
// })
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
v.tagNameFunc = fn
v.hasTagNameFunc = true
@ -613,7 +613,7 @@ func (v *Validate) Var(field interface{}, tag string) error {
}
// VarCtx validates a single variable using tag style validation and allows passing of contextual
// validation validation information via context.Context.
// validation information via context.Context.
// eg.
// var i int
// validate.Var(i, "gt=1,lt=10")
@ -632,6 +632,7 @@ func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag string) (e
}
ctag := v.fetchCacheTag(tag)
val := reflect.ValueOf(field)
vd := v.pool.Get().(*validate)
vd.top = val

@ -5652,6 +5652,53 @@ func TestBase64URLValidation(t *testing.T) {
}
}
func TestBase64RawURLValidation(t *testing.T) {
validate := New()
testCases := []struct {
decoded, encoded string
success bool
}{
// empty string, although a valid base64 string, should fail
{"", "", false},
// invalid length
{"", "a", false},
// base64 with padding should fail
{"f", "Zg==", false},
{"fo", "Zm8=", false},
// base64 without padding
{"foo", "Zm9v", true},
{"hello", "aGVsbG8", true},
{"", "aGVsb", false},
// // base64 URL safe encoding with invalid, special characters '+' and '/'
{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+", false},
{"\x14\xfb\x9c\x03\xf9\x73", "FPucA/lz", false},
// // base64 URL safe encoding with valid, special characters '-' and '_'
{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l-", true},
{"\x14\xfb\x9c\x03\xf9\x73", "FPucA_lz", true},
// non base64 characters
{"", "@mc=", false},
{"", "Zm 9", false},
}
for _, tc := range testCases {
err := validate.Var(tc.encoded, "base64rawurl")
if tc.success {
Equal(t, err, nil)
// make sure encoded value is decoded back to the expected value
d, innerErr := base64.RawURLEncoding.DecodeString(tc.encoded)
Equal(t, innerErr, nil)
Equal(t, tc.decoded, string(d))
} else {
NotEqual(t, err, nil)
if len(tc.encoded) > 0 {
// make sure that indeed the encoded value was faulty
_, err := base64.RawURLEncoding.DecodeString(tc.encoded)
NotEqual(t, err, nil)
}
}
}
}
func TestFileValidation(t *testing.T) {
validate := New()

Loading…
Cancel
Save