Add validation for base64 URL safe values

pull/351/head
Kyriakos Georgiou 7 years ago
parent 8ce234ff02
commit 030800a855
  1. 6
      baked_in.go
  2. 9
      doc.go
  3. 2
      regexes.go
  4. 48
      validator_test.go

@ -96,6 +96,7 @@ var (
"url": isURL,
"uri": isURI,
"base64": isBase64,
"base64url": isBase64URL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
@ -845,6 +846,11 @@ func isBase64(fl FieldLevel) bool {
return base64Regex.MatchString(fl.Field().String())
}
// IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
func isBase64URL(fl FieldLevel) bool {
return base64URLRegex.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 {

@ -609,6 +609,15 @@ this with the omitempty tag.
Usage: base64
Base64URL String
This validates that a string value contains a valid base64 URL safe value.
Although an empty string is a valid base64 URL safe value, this will report
an empty string as an error, if you wish to accept an empty string as valid
you can use this with the omitempty tag.
Usage: base64url
Contains
This validates that a string value contains the substring value.

@ -17,6 +17,7 @@ const (
hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:\\(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22)))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
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})$"
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}$"
@ -49,6 +50,7 @@ var (
hslaRegex = regexp.MustCompile(hslaRegexString)
emailRegex = regexp.MustCompile(emailRegexString)
base64Regex = regexp.MustCompile(base64RegexString)
base64URLRegex = regexp.MustCompile(base64URLRegexString)
iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
uUID3Regex = regexp.MustCompile(uUID3RegexString)

@ -5,6 +5,7 @@ import (
"context"
"database/sql"
"database/sql/driver"
"encoding/base64"
"encoding/json"
"fmt"
"reflect"
@ -4398,6 +4399,53 @@ func TestBase64Validation(t *testing.T) {
AssertError(t, errs, "", "", "", "", "base64")
}
func TestBase64URLValidation(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
{"f", "Zg==", true},
{"fo", "Zm8=", true},
// base64 without padding
{"foo", "Zm9v", true},
{"", "Zg", false},
{"", "Zm8", 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, "base64url")
if tc.success {
Equal(t, err, nil)
// make sure encoded value is decoded back to the expected value
d, err := base64.URLEncoding.DecodeString(tc.encoded)
Equal(t, err, 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.URLEncoding.DecodeString(tc.encoded)
NotEqual(t, err, nil)
}
}
}
}
func TestNoStructLevelValidation(t *testing.T) {
type Inner struct {

Loading…
Cancel
Save