From 29d50ba9634f850e9535ae850eb763c010175cd3 Mon Sep 17 00:00:00 2001 From: Yasoob Haider Date: Mon, 20 Mar 2023 01:05:00 +0530 Subject: [PATCH] add validation for base64 url without = padding (#1024) Co-authored-by: Yasoob Haider Co-authored-by: Dean Karn --- README.md | 1 + baked_in.go | 6 + cache.go | 2 +- doc.go | 315 ++++++++++++++++++++++-------------------- regexes.go | 2 + validator.go | 1 - validator_instance.go | 19 +-- validator_test.go | 47 +++++++ 8 files changed, 229 insertions(+), 164 deletions(-) diff --git a/README.md b/README.md index 284092b..3d52c73 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/baked_in.go b/baked_in.go index 1e6e00d..9ce2282 100644 --- a/baked_in.go +++ b/baked_in.go @@ -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() diff --git a/cache.go b/cache.go index 7b84c91..bbfd2a4 100644 --- a/cache.go +++ b/cache.go @@ -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) diff --git a/doc.go b/doc.go index ba4639c..2b44b53 100644 --- a/doc.go +++ b/doc.go @@ -7,7 +7,7 @@ and has the ability to dive into arrays and maps of any type. see more examples https://github.com/go-playground/validator/tree/master/_examples -Singleton +# Singleton Validator is designed to be thread-safe and used as a singleton instance. It caches information about your struct and validations, @@ -15,7 +15,7 @@ in essence only parsing your validation tags once per struct type. Using multiple instances neglects the benefit of caching. The not thread-safe functions are explicitly marked as such in the documentation. -Validation Functions Return Type error +# Validation Functions Return Type error Doing things this way is actually the way the standard library does, see the file.Open method here: @@ -34,7 +34,7 @@ if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so err.(validator.ValidationErrors). -Custom Validation Functions +# Custom Validation Functions Custom Validation functions can be added. Example: @@ -52,21 +52,21 @@ Custom Validation functions can be added. Example: // NOTES: using the same tag name as an existing function // will overwrite the existing one -Cross-Field Validation +# Cross-Field Validation Cross-Field Validation can be done via the following tags: - - eqfield - - nefield - - gtfield - - gtefield - - ltfield - - ltefield - - eqcsfield - - necsfield - - gtcsfield - - gtecsfield - - ltcsfield - - ltecsfield + - eqfield + - nefield + - gtfield + - gtefield + - ltfield + - ltefield + - eqcsfield + - necsfield + - gtcsfield + - gtecsfield + - ltcsfield + - ltecsfield If, however, some custom cross-field validation is required, it can be done using a custom validation. @@ -106,7 +106,7 @@ used "eqcsfield" it could be multiple levels down. Example: // whatever you pass, struct, field... // when calling validate.Field(field, tag) val will be nil -Multiple Validators +# Multiple Validators Multiple validators on a field will process in the order defined. Example: @@ -124,7 +124,7 @@ Bad Validator definitions are not handled by the library. Example: // this definition of min max will never succeed -Using Validator Tags +# Using Validator Tags Baked In Cross-Field validation only compares fields on the same struct. If Cross-Field + Cross-Struct validation is needed you should implement your @@ -150,20 +150,18 @@ so the above will become excludesall=0x7C Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation. } - -Baked In Validators and Tags +# Baked In Validators and Tags Here is a list of the current built in validators: - -Skip Field +# Skip Field Tells the validation to skip this struct field; this is particularly handy in ignoring embedded structs from being validated. (Usage: -) - Usage: - + Usage: - -Or Operator +# Or Operator This is the 'or' operator allowing multiple validators to be used and accepted. (Usage: rgb|rgba) <-- this would allow either rgb or rgba @@ -172,7 +170,7 @@ colors to be accepted. This can also be combined with 'and' for example Usage: | -StructOnly +# StructOnly When a field that is a nested struct is encountered, and contains this flag any validation on the nested struct will be run, but none of the nested @@ -182,13 +180,13 @@ NOTE: only "required" and "omitempty" can be used on a struct itself. Usage: structonly -NoStructLevel +# NoStructLevel Same as structonly tag except that any struct level validations will not run. Usage: nostructlevel -Omit Empty +# Omit Empty Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation @@ -196,7 +194,7 @@ such as min or max won't run, but if a value is set validation will run. Usage: omitempty -Dive +# Dive This tells the validator to dive into a slice, array or map and validate that level of the slice, array or map with the validation tags that follow. @@ -244,7 +242,7 @@ Example #2 // eq=1|eq=2 will be applied to each array element in the the map keys // required will be applied to map values -Required +# Required This validates that the value is not the data types default zero value. For numbers ensures value is not zero. For strings ensures value is @@ -253,7 +251,7 @@ ensures the value is not nil. Usage: required -Required If +# Required If The field under validation must be present and not empty only if all the other specified fields are equal to the value following the specified @@ -270,7 +268,7 @@ Examples: // require the field if the Field1 and Field2 is equal to the value respectively: Usage: required_if=Field1 foo Field2 bar -Required Unless +# Required Unless The field under validation must be present and not empty unless all the other specified fields are equal to the value following the specified @@ -287,7 +285,7 @@ Examples: // require the field unless the Field1 and Field2 is equal to the value respectively: Usage: required_unless=Field1 foo Field2 bar -Required With +# Required With The field under validation must be present and not empty only if any of the other specified fields are present. For strings ensures value is @@ -304,7 +302,7 @@ Examples: // require the field if the Field1 or Field2 is present: Usage: required_with=Field1 Field2 -Required With All +# Required With All The field under validation must be present and not empty only if all of the other specified fields are present. For strings ensures value is @@ -318,7 +316,7 @@ Example: // require the field if the Field1 and Field2 is present: Usage: required_with_all=Field1 Field2 -Required Without +# Required Without The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is @@ -335,7 +333,7 @@ Examples: // require the field if the Field1 or Field2 is not present: Usage: required_without=Field1 Field2 -Required Without All +# Required Without All The field under validation must be present and not empty only when all of the other specified fields are not present. For strings ensures value is @@ -349,7 +347,7 @@ Example: // require the field if the Field1 and Field2 is not present: Usage: required_without_all=Field1 Field2 -Excluded If +# Excluded If The field under validation must not be present or not empty only if all the other specified fields are equal to the value following the specified @@ -366,7 +364,7 @@ Examples: // exclude the field if the Field1 and Field2 is equal to the value respectively: Usage: excluded_if=Field1 foo Field2 bar -Excluded Unless +# Excluded Unless The field under validation must not be present or empty unless all the other specified fields are equal to the value following the specified @@ -383,14 +381,14 @@ Examples: // exclude the field unless the Field1 and Field2 is equal to the value respectively: Usage: excluded_unless=Field1 foo Field2 bar -Is Default +# Is Default This validates that the value is the default value and is almost the opposite of required. Usage: isdefault -Length +# Length For numbers, length will ensure that the value is equal to the parameter given. For strings, it checks that @@ -408,7 +406,7 @@ in the parameter. Usage: len=1h30m -Maximum +# Maximum For numbers, max will ensure that the value is less than or equal to the parameter given. For strings, it checks @@ -426,7 +424,7 @@ duration given in the parameter. Usage: max=1h30m -Minimum +# Minimum For numbers, min will ensure that the value is greater or equal to the parameter given. For strings, it checks that @@ -444,7 +442,7 @@ the duration given in the parameter. Usage: min=1h30m -Equals +# Equals For strings & numbers, eq will ensure that the value is equal to the parameter given. For slices, arrays, and maps, @@ -461,7 +459,7 @@ in the parameter. Usage: eq=1h30m -Not Equal +# Not Equal For strings & numbers, ne will ensure that the value is not equal to the parameter given. For slices, arrays, and maps, @@ -478,7 +476,7 @@ given in the parameter. Usage: ne=1h30m -One Of +# One Of For strings, ints, and uints, oneof will ensure that the value is one of the values in the parameter. The parameter should be @@ -486,11 +484,11 @@ a list of values separated by whitespace. Values may be strings or numbers. To match strings with spaces in them, include the target string between single quotes. - Usage: oneof=red green - oneof='red green' 'blue yellow' - oneof=5 7 9 + Usage: oneof=red green + oneof='red green' 'blue yellow' + oneof=5 7 9 -Greater Than +# Greater Than For numbers, this will ensure that the value is greater than the parameter given. For strings, it checks that the string length @@ -514,7 +512,7 @@ given in the parameter. Usage: gt=1h30m -Greater Than or Equal +# Greater Than or Equal Same as 'min' above. Kept both to make terminology with 'len' easier. @@ -535,7 +533,7 @@ the duration given in the parameter. Usage: gte=1h30m -Less Than +# Less Than For numbers, this will ensure that the value is less than the parameter given. For strings, it checks that the string length is less than that number of @@ -558,7 +556,7 @@ in the parameter. Usage: lt=1h30m -Less Than or Equal +# Less Than or Equal Same as 'max' above. Kept both to make terminology with 'len' easier. @@ -579,7 +577,7 @@ duration given in the parameter. Usage: lte=1h30m -Field Equals Another Field +# Field Equals Another Field This will validate the field value against another fields value either within a struct or passed in field. @@ -601,7 +599,7 @@ to the top level struct. Usage: eqcsfield=InnerStructField.Field) -Field Does Not Equal Another Field +# Field Does Not Equal Another Field This will validate the field value against another fields value either within a struct or passed in field. @@ -623,7 +621,7 @@ relative to the top level struct. Usage: necsfield=InnerStructField.Field -Field Greater Than Another Field +# Field Greater Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -639,14 +637,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "gtfield") -Field Greater Than Another Relative Field +# Field Greater Than Another Relative Field This does the same as gtfield except that it validates the field provided relative to the top level struct. Usage: gtcsfield=InnerStructField.Field -Field Greater Than or Equal To Another Field +# Field Greater Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -662,14 +660,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "gtefield") -Field Greater Than or Equal To Another Relative Field +# Field Greater Than or Equal To Another Relative Field This does the same as gtefield except that it validates the field provided relative to the top level struct. Usage: gtecsfield=InnerStructField.Field -Less Than Another Field +# Less Than Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -685,14 +683,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "ltfield") -Less Than Another Relative Field +# Less Than Another Relative Field This does the same as ltfield except that it validates the field provided relative to the top level struct. Usage: ltcsfield=InnerStructField.Field -Less Than or Equal To Another Field +# Less Than or Equal To Another Field Only valid for Numbers, time.Duration and time.Time types, this will validate the field value against another fields value either within a struct or passed in @@ -708,14 +706,14 @@ Example #2: // Validating by field: validate.VarWithValue(start, end, "ltefield") -Less Than or Equal To Another Relative Field +# Less Than or Equal To Another Relative Field This does the same as ltefield except that it validates the field provided relative to the top level struct. Usage: ltecsfield=InnerStructField.Field -Field Contains Another Field +# Field Contains Another Field This does the same as contains except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on @@ -723,7 +721,7 @@ other types. Usage: containsfield=InnerStructField.Field -Field Excludes Another Field +# Field Excludes Another Field This does the same as excludes except for struct fields. It should only be used with string types. See the behavior of reflect.Value.String() for behavior on @@ -731,7 +729,7 @@ other types. Usage: excludesfield=InnerStructField.Field -Unique +# Unique For arrays & slices, unique will ensure that there are no duplicates. For maps, unique will ensure that there are no duplicate values. @@ -744,44 +742,44 @@ in a field of the struct specified via a parameter. // For slices of struct: Usage: unique=field -Alpha Only +# Alpha Only This validates that a string value contains ASCII alpha characters only Usage: alpha -Alphanumeric +# Alphanumeric This validates that a string value contains ASCII alphanumeric characters only Usage: alphanum -Alpha Unicode +# Alpha Unicode This validates that a string value contains unicode alpha characters only Usage: alphaunicode -Alphanumeric Unicode +# Alphanumeric Unicode This validates that a string value contains unicode alphanumeric characters only Usage: alphanumunicode -Boolean +# Boolean This validates that a string value can successfully be parsed into a boolean with strconv.ParseBool Usage: boolean -Number +# Number This validates that a string value contains number values only. For integers or float it returns true. Usage: number -Numeric +# Numeric This validates that a string value contains a basic numeric value. basic excludes exponents etc... @@ -789,63 +787,63 @@ for integers or float it returns true. Usage: numeric -Hexadecimal String +# Hexadecimal String This validates that a string value contains a valid hexadecimal. Usage: hexadecimal -Hexcolor String +# Hexcolor String This validates that a string value contains a valid hex color including hashtag (#) - Usage: hexcolor + Usage: hexcolor -Lowercase String +# Lowercase String This validates that a string value contains only lowercase characters. An empty string is not a valid lowercase string. Usage: lowercase -Uppercase String +# Uppercase String This validates that a string value contains only uppercase characters. An empty string is not a valid uppercase string. Usage: uppercase -RGB String +# RGB String This validates that a string value contains a valid rgb color Usage: rgb -RGBA String +# RGBA String This validates that a string value contains a valid rgba color Usage: rgba -HSL String +# HSL String This validates that a string value contains a valid hsl color Usage: hsl -HSLA String +# HSLA String This validates that a string value contains a valid hsla color Usage: hsla -E.164 Phone Number String +# E.164 Phone Number String This validates that a string value contains a valid E.164 Phone number https://en.wikipedia.org/wiki/E.164 (ex. +1123456789) Usage: e164 -E-mail String +# E-mail String This validates that a string value contains a valid email This may not conform to all possibilities of any rfc standard, but neither @@ -853,19 +851,19 @@ does any email provider accept all possibilities. Usage: email -JSON String +# JSON String This validates that a string value is valid JSON Usage: json -JWT String +# JWT String This validates that a string value is a valid JWT Usage: jwt -File path +# File path This validates that a string value contains a valid file path and that the file exists on the machine. @@ -873,7 +871,7 @@ This is done using os.Stat, which is a platform independent function. Usage: file -URL String +# URL String This validates that a string value contains a valid url This will accept any url the golang request uri accepts but must contain @@ -881,21 +879,21 @@ a schema for example http:// or rtmp:// Usage: url -URI String +# URI String This validates that a string value contains a valid uri This will accept any uri the golang request uri accepts Usage: uri -Urn RFC 2141 String +# Urn RFC 2141 String This validataes that a string value contains a valid URN according to the RFC 2141 spec. Usage: urn_rfc2141 -Base64 String +# Base64 String This validates that a string value contains a valid base64 value. Although an empty string is valid base64 this will report an empty string @@ -904,7 +902,7 @@ this with the omitempty tag. Usage: base64 -Base64URL String +# Base64URL String This validates that a string value contains a valid base64 URL safe value according the the RFC4648 spec. @@ -914,7 +912,17 @@ you can use this with the omitempty tag. Usage: base64url -Bitcoin Address +# Base64RawURL String + +This validates that a string value contains a valid base64 URL safe value, +but without = padding, according the the RFC4648 spec, section 3.2. +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 + +# Bitcoin Address This validates that a string value contains a valid bitcoin address. The format of the string is checked to ensure it matches one of the three formats @@ -930,266 +938,266 @@ Special thanks to Pieter Wuille for providng reference implementations. Usage: btc_addr_bech32 -Ethereum Address +# Ethereum Address This validates that a string value contains a valid ethereum address. The format of the string is checked to ensure it matches the standard Ethereum address format. Usage: eth_addr -Contains +# Contains This validates that a string value contains the substring value. Usage: contains=@ -Contains Any +# Contains Any This validates that a string value contains any Unicode code points in the substring value. Usage: containsany=!@#? -Contains Rune +# Contains Rune This validates that a string value contains the supplied rune value. Usage: containsrune=@ -Excludes +# Excludes This validates that a string value does not contain the substring value. Usage: excludes=@ -Excludes All +# Excludes All This validates that a string value does not contain any Unicode code points in the substring value. Usage: excludesall=!@#? -Excludes Rune +# Excludes Rune This validates that a string value does not contain the supplied rune value. Usage: excludesrune=@ -Starts With +# Starts With This validates that a string value starts with the supplied string value Usage: startswith=hello -Ends With +# Ends With This validates that a string value ends with the supplied string value Usage: endswith=goodbye -Does Not Start With +# Does Not Start With This validates that a string value does not start with the supplied string value Usage: startsnotwith=hello -Does Not End With +# Does Not End With This validates that a string value does not end with the supplied string value Usage: endsnotwith=goodbye -International Standard Book Number +# International Standard Book Number This validates that a string value contains a valid isbn10 or isbn13 value. Usage: isbn -International Standard Book Number 10 +# International Standard Book Number 10 This validates that a string value contains a valid isbn10 value. Usage: isbn10 -International Standard Book Number 13 +# International Standard Book Number 13 This validates that a string value contains a valid isbn13 value. Usage: isbn13 -Universally Unique Identifier UUID +# Universally Unique Identifier UUID This validates that a string value contains a valid UUID. Uppercase UUID values will not pass - use `uuid_rfc4122` instead. Usage: uuid -Universally Unique Identifier UUID v3 +# Universally Unique Identifier UUID v3 This validates that a string value contains a valid version 3 UUID. Uppercase UUID values will not pass - use `uuid3_rfc4122` instead. Usage: uuid3 -Universally Unique Identifier UUID v4 +# Universally Unique Identifier UUID v4 This validates that a string value contains a valid version 4 UUID. Uppercase UUID values will not pass - use `uuid4_rfc4122` instead. Usage: uuid4 -Universally Unique Identifier UUID v5 +# Universally Unique Identifier UUID v5 This validates that a string value contains a valid version 5 UUID. Uppercase UUID values will not pass - use `uuid5_rfc4122` instead. Usage: uuid5 -Universally Unique Lexicographically Sortable Identifier ULID +# Universally Unique Lexicographically Sortable Identifier ULID This validates that a string value contains a valid ULID value. Usage: ulid -ASCII +# ASCII This validates that a string value contains only ASCII characters. NOTE: if the string is blank, this validates as true. Usage: ascii -Printable ASCII +# Printable ASCII This validates that a string value contains only printable ASCII characters. NOTE: if the string is blank, this validates as true. Usage: printascii -Multi-Byte Characters +# Multi-Byte Characters This validates that a string value contains one or more multibyte characters. NOTE: if the string is blank, this validates as true. Usage: multibyte -Data URL +# Data URL This validates that a string value contains a valid DataURI. NOTE: this will also validate that the data portion is valid base64 Usage: datauri -Latitude +# Latitude This validates that a string value contains a valid latitude. Usage: latitude -Longitude +# Longitude This validates that a string value contains a valid longitude. Usage: longitude -Social Security Number SSN +# Social Security Number SSN This validates that a string value contains a valid U.S. Social Security Number. Usage: ssn -Internet Protocol Address IP +# Internet Protocol Address IP This validates that a string value contains a valid IP Address. Usage: ip -Internet Protocol Address IPv4 +# Internet Protocol Address IPv4 This validates that a string value contains a valid v4 IP Address. Usage: ipv4 -Internet Protocol Address IPv6 +# Internet Protocol Address IPv6 This validates that a string value contains a valid v6 IP Address. Usage: ipv6 -Classless Inter-Domain Routing CIDR +# Classless Inter-Domain Routing CIDR This validates that a string value contains a valid CIDR Address. Usage: cidr -Classless Inter-Domain Routing CIDRv4 +# Classless Inter-Domain Routing CIDRv4 This validates that a string value contains a valid v4 CIDR Address. Usage: cidrv4 -Classless Inter-Domain Routing CIDRv6 +# Classless Inter-Domain Routing CIDRv6 This validates that a string value contains a valid v6 CIDR Address. Usage: cidrv6 -Transmission Control Protocol Address TCP +# Transmission Control Protocol Address TCP This validates that a string value contains a valid resolvable TCP Address. Usage: tcp_addr -Transmission Control Protocol Address TCPv4 +# Transmission Control Protocol Address TCPv4 This validates that a string value contains a valid resolvable v4 TCP Address. Usage: tcp4_addr -Transmission Control Protocol Address TCPv6 +# Transmission Control Protocol Address TCPv6 This validates that a string value contains a valid resolvable v6 TCP Address. Usage: tcp6_addr -User Datagram Protocol Address UDP +# User Datagram Protocol Address UDP This validates that a string value contains a valid resolvable UDP Address. Usage: udp_addr -User Datagram Protocol Address UDPv4 +# User Datagram Protocol Address UDPv4 This validates that a string value contains a valid resolvable v4 UDP Address. Usage: udp4_addr -User Datagram Protocol Address UDPv6 +# User Datagram Protocol Address UDPv6 This validates that a string value contains a valid resolvable v6 UDP Address. Usage: udp6_addr -Internet Protocol Address IP +# Internet Protocol Address IP This validates that a string value contains a valid resolvable IP Address. Usage: ip_addr -Internet Protocol Address IPv4 +# Internet Protocol Address IPv4 This validates that a string value contains a valid resolvable v4 IP Address. Usage: ip4_addr -Internet Protocol Address IPv6 +# Internet Protocol Address IPv6 This validates that a string value contains a valid resolvable v6 IP Address. Usage: ip6_addr -Unix domain socket end point Address +# Unix domain socket end point Address This validates that a string value contains a valid Unix Address. Usage: unix_addr -Media Access Control Address MAC +# Media Access Control Address MAC This validates that a string value contains a valid MAC Address. @@ -1199,13 +1207,13 @@ Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 -Hostname RFC 952 +# Hostname RFC 952 This validates that a string value is a valid Hostname according to RFC 952 https://tools.ietf.org/html/rfc952 Usage: hostname -Hostname RFC 1123 +# Hostname RFC 1123 This validates that a string value is a valid Hostname according to RFC 1123 https://tools.ietf.org/html/rfc1123 @@ -1217,28 +1225,28 @@ This validates that a string value contains a valid FQDN. Usage: fqdn -HTML Tags +# HTML Tags This validates that a string value appears to be an HTML element tag including those described at https://developer.mozilla.org/en-US/docs/Web/HTML/Element Usage: html -HTML Encoded +# HTML Encoded This validates that a string value is a proper character reference in decimal or hexadecimal format Usage: html_encoded -URL Encoded +# URL Encoded This validates that a string value is percent-encoded (URL encoded) according to https://tools.ietf.org/html/rfc3986#section-2.1 Usage: url_encoded -Directory +# Directory This validates that a string value contains a valid directory and that it exists on the machine. @@ -1246,42 +1254,42 @@ This is done using os.Stat, which is a platform independent function. Usage: dir -HostPort +# HostPort This validates that a string value contains a valid DNS hostname and port that can be used to valiate fields typically passed to sockets and connections. Usage: hostname_port -Datetime +# Datetime This validates that a string value is a valid datetime based on the supplied datetime format. Supplied format must match the official Go time format layout as documented in https://golang.org/pkg/time/ Usage: datetime=2006-01-02 -Iso3166-1 alpha-2 +# Iso3166-1 alpha-2 This validates that a string value is a valid country code based on iso3166-1 alpha-2 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha2 -Iso3166-1 alpha-3 +# Iso3166-1 alpha-3 This validates that a string value is a valid country code based on iso3166-1 alpha-3 standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 -Iso3166-1 alpha-numeric +# Iso3166-1 alpha-numeric This validates that a string value is a valid country code based on iso3166-1 alpha-numeric standard. see: https://www.iso.org/iso-3166-country-codes.html Usage: iso3166_1_alpha3 -BCP 47 Language Tag +# BCP 47 Language Tag This validates that a string value is a valid BCP 47 language tag, as parsed by language.Parse. More information on https://pkg.go.dev/golang.org/x/text/language @@ -1295,14 +1303,14 @@ More information on https://www.iso.org/standard/60390.html Usage: bic -RFC 1035 label +# RFC 1035 label This validates that a string value is a valid dns RFC 1035 label, defined in RFC 1035. More information on https://datatracker.ietf.org/doc/html/rfc1035 Usage: dns_rfc1035_label -TimeZone +# TimeZone This validates that a string value is a valid time zone based on the time zone database present on the system. Although empty value and Local value are allowed by time.LoadLocation golang function, they are not allowed by this validator. @@ -1310,20 +1318,21 @@ More information on https://golang.org/pkg/time/#LoadLocation Usage: timezone -Semantic Version +# Semantic Version This validates that a string value is a valid semver version, defined in Semantic Versioning 2.0.0. More information on https://semver.org/ Usage: semver -Credit Card +# Credit Card This validates that a string value contains a valid credit card number using Luhn algoritm. Usage: credit_card -Cron + +# Cron This validates that a string value contains a valid cron expression. @@ -1360,7 +1369,7 @@ Validator notes: And the best reason, you can submit a pull request and we can keep on adding to the validation library of this package! -Non standard validators +# Non standard validators A collection of validation rules that are frequently needed but are more complex than the ones found in the baked in validators. @@ -1389,7 +1398,7 @@ Here is a list of the current non standard validators: Usage: notblank -Panics +# Panics This package panics when bad input is provided, this is by design, bad code like that should not make it to production. diff --git a/regexes.go b/regexes.go index 5436e3f..029dd91 100644 --- a/regexes.go +++ b/regexes.go @@ -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) diff --git a/validator.go b/validator.go index 80da095..6f6d53a 100644 --- a/validator.go +++ b/validator.go @@ -452,7 +452,6 @@ OUTER: v.ct = ct if !ct.fn(ctx, v) { - v.str1 = string(append(ns, cf.altName...)) if v.v.hasTagNameFunc { diff --git a/validator_instance.go b/validator_instance.go index 9493da4..51ae1aa 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -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 diff --git a/validator_test.go b/validator_test.go index fdf8a54..ec7e3aa 100644 --- a/validator_test.go +++ b/validator_test.go @@ -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()