2015-02-12 20:49:57 -05:00
package validator
2015-02-12 22:42:16 -05:00
import (
2018-05-04 13:20:05 +01:00
"bytes"
2017-07-29 20:49:32 -07:00
"context"
2018-05-04 13:20:05 +01:00
"crypto/sha256"
2015-02-14 21:26:15 -05:00
"fmt"
2015-07-27 22:31:33 -04:00
"net"
2015-07-14 22:45:37 -04:00
"net/url"
2018-06-27 12:03:42 +03:00
"os"
2015-02-12 22:42:16 -05:00
"reflect"
2018-02-16 11:05:31 -06:00
"strconv"
2015-07-14 22:45:37 -04:00
"strings"
2018-02-16 11:05:31 -06:00
"sync"
2015-03-10 15:07:00 -04:00
"time"
2015-05-22 22:28:40 -04:00
"unicode/utf8"
2019-01-27 21:00:13 -08:00
urn "github.com/leodido/go-urn"
2015-02-12 22:42:16 -05:00
)
2015-02-12 20:49:57 -05:00
2017-08-29 18:44:39 -07:00
// Func accepts a FieldLevel interface for all validation needs. The return
// value should be true when validation succeeds.
2016-08-03 14:46:35 -04:00
type Func func ( fl FieldLevel ) bool
2017-08-29 18:44:39 -07:00
// FuncCtx accepts a context.Context and FieldLevel interface for all
// validation needs. The return value should be true when validation succeeds.
2017-07-29 20:49:32 -07:00
type FuncCtx func ( ctx context . Context , fl FieldLevel ) bool
// wrapFunc wraps noramal Func makes it compatible with FuncCtx
func wrapFunc ( fn Func ) FuncCtx {
if fn == nil {
return nil // be sure not to wrap a bad function.
}
return func ( ctx context . Context , fl FieldLevel ) bool {
return fn ( fl )
}
}
2016-08-03 14:46:35 -04:00
var (
restrictedTags = map [ string ] struct { } {
diveTag : { } ,
2017-11-12 20:58:10 -08:00
keysTag : { } ,
endKeysTag : { } ,
2016-08-03 14:46:35 -04:00
structOnlyTag : { } ,
omitempty : { } ,
skipValidationTag : { } ,
utf8HexComma : { } ,
utf8Pipe : { } ,
noStructLevelTag : { } ,
2016-09-28 10:56:49 -04:00
requiredTag : { } ,
2017-08-20 09:53:47 -07:00
isdefault : { } ,
2016-08-03 14:46:35 -04:00
}
// BakedInAliasValidators is a default mapping of a single validation tag that
// defines a common or complex set of validation(s) to simplify
// adding validation to structs.
bakedInAliases = map [ string ] string {
"iscolor" : "hexcolor|rgb|rgba|hsl|hsla" ,
}
// BakedInValidators is the default map of ValidationFunc
// you can add, remove or even replace items to suite your needs,
// or even disregard and use your own map if so desired.
bakedInValidators = map [ string ] Func {
2019-04-29 16:05:30 +04:30
"required" : hasValue ,
"required_with" : requiredWith ,
"required_with_all" : requiredWithAll ,
"required_without" : requiredWithout ,
"required_without_all" : requiredWithoutAll ,
"isdefault" : isDefault ,
"len" : hasLengthOf ,
"min" : hasMinOf ,
"max" : hasMaxOf ,
"eq" : isEq ,
"ne" : isNe ,
"lt" : isLt ,
"lte" : isLte ,
"gt" : isGt ,
"gte" : isGte ,
"eqfield" : isEqField ,
"eqcsfield" : isEqCrossStructField ,
"necsfield" : isNeCrossStructField ,
"gtcsfield" : isGtCrossStructField ,
"gtecsfield" : isGteCrossStructField ,
"ltcsfield" : isLtCrossStructField ,
"ltecsfield" : isLteCrossStructField ,
"nefield" : isNeField ,
"gtefield" : isGteField ,
"gtfield" : isGtField ,
"ltefield" : isLteField ,
"ltfield" : isLtField ,
"fieldcontains" : fieldContains ,
"fieldexcludes" : fieldExcludes ,
"alpha" : isAlpha ,
"alphanum" : isAlphanum ,
"alphaunicode" : isAlphaUnicode ,
"alphanumunicode" : isAlphanumUnicode ,
"numeric" : isNumeric ,
"number" : isNumber ,
"hexadecimal" : isHexadecimal ,
"hexcolor" : isHEXColor ,
"rgb" : isRGB ,
"rgba" : isRGBA ,
"hsl" : isHSL ,
"hsla" : isHSLA ,
2019-10-16 16:16:27 -06:00
"e164" : isE164 ,
2019-04-29 16:05:30 +04:30
"email" : isEmail ,
"url" : isURL ,
"uri" : isURI ,
"urn_rfc2141" : isUrnRFC2141 , // RFC 2141
"file" : isFile ,
"base64" : isBase64 ,
"base64url" : isBase64URL ,
"contains" : contains ,
"containsany" : containsAny ,
"containsrune" : containsRune ,
"excludes" : excludes ,
"excludesall" : excludesAll ,
"excludesrune" : excludesRune ,
"startswith" : startsWith ,
"endswith" : endsWith ,
"isbn" : isISBN ,
"isbn10" : isISBN10 ,
"isbn13" : isISBN13 ,
"eth_addr" : isEthereumAddress ,
"btc_addr" : isBitcoinAddress ,
"btc_addr_bech32" : isBitcoinBech32Address ,
"uuid" : isUUID ,
"uuid3" : isUUID3 ,
"uuid4" : isUUID4 ,
"uuid5" : isUUID5 ,
"uuid_rfc4122" : isUUIDRFC4122 ,
"uuid3_rfc4122" : isUUID3RFC4122 ,
"uuid4_rfc4122" : isUUID4RFC4122 ,
"uuid5_rfc4122" : isUUID5RFC4122 ,
"ascii" : isASCII ,
"printascii" : isPrintableASCII ,
"multibyte" : hasMultiByteCharacter ,
"datauri" : isDataURI ,
"latitude" : isLatitude ,
"longitude" : isLongitude ,
"ssn" : isSSN ,
"ipv4" : isIPv4 ,
"ipv6" : isIPv6 ,
"ip" : isIP ,
"cidrv4" : isCIDRv4 ,
"cidrv6" : isCIDRv6 ,
"cidr" : isCIDR ,
"tcp4_addr" : isTCP4AddrResolvable ,
"tcp6_addr" : isTCP6AddrResolvable ,
"tcp_addr" : isTCPAddrResolvable ,
"udp4_addr" : isUDP4AddrResolvable ,
"udp6_addr" : isUDP6AddrResolvable ,
"udp_addr" : isUDPAddrResolvable ,
"ip4_addr" : isIP4AddrResolvable ,
"ip6_addr" : isIP6AddrResolvable ,
"ip_addr" : isIPAddrResolvable ,
"unix_addr" : isUnixAddrResolvable ,
"mac" : isMAC ,
"hostname" : isHostnameRFC952 , // RFC 952
"hostname_rfc1123" : isHostnameRFC1123 , // RFC 1123
"fqdn" : isFQDN ,
"unique" : isUnique ,
"oneof" : isOneOf ,
"html" : isHTML ,
"html_encoded" : isHTMLEncoded ,
"url_encoded" : isURLEncoded ,
"dir" : isDir ,
2016-08-03 14:46:35 -04:00
}
)
2015-10-15 21:14:54 -04:00
2018-02-19 11:03:16 -06:00
var oneofValsCache = map [ string ] [ ] string { }
var oneofValsCacheRWLock = sync . RWMutex { }
2018-02-16 11:05:31 -06:00
2018-02-19 11:03:16 -06:00
func parseOneOfParam2 ( s string ) [ ] string {
oneofValsCacheRWLock . RLock ( )
vals , ok := oneofValsCache [ s ]
oneofValsCacheRWLock . RUnlock ( )
2018-02-16 11:05:31 -06:00
if ! ok {
2018-02-19 11:03:16 -06:00
oneofValsCacheRWLock . Lock ( )
vals = strings . Fields ( s )
oneofValsCache [ s ] = vals
oneofValsCacheRWLock . Unlock ( )
2018-02-16 11:05:31 -06:00
}
2018-02-19 11:03:16 -06:00
return vals
}
2018-06-28 18:11:36 -05:00
func isURLEncoded ( fl FieldLevel ) bool {
return uRLEncodedRegex . MatchString ( fl . Field ( ) . String ( ) )
}
func isHTMLEncoded ( fl FieldLevel ) bool {
return hTMLEncodedRegex . MatchString ( fl . Field ( ) . String ( ) )
}
func isHTML ( fl FieldLevel ) bool {
return hTMLRegex . MatchString ( fl . Field ( ) . String ( ) )
}
2018-02-19 11:03:16 -06:00
func isOneOf ( fl FieldLevel ) bool {
vals := parseOneOfParam2 ( fl . Param ( ) )
2018-02-16 11:05:31 -06:00
field := fl . Field ( )
var v string
switch field . Kind ( ) {
case reflect . String :
v = field . String ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
v = strconv . FormatInt ( field . Int ( ) , 10 )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
v = strconv . FormatUint ( field . Uint ( ) , 10 )
default :
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
for i := 0 ; i < len ( vals ) ; i ++ {
if vals [ i ] == v {
return true
}
}
return false
}
2018-05-04 13:20:05 +01:00
// isUnique is the validation function for validating if each array|slice|map value is unique
2017-10-22 17:20:41 -07:00
func isUnique ( fl FieldLevel ) bool {
field := fl . Field ( )
2019-08-02 17:11:23 +09:00
param := fl . Param ( )
2017-10-22 17:20:41 -07:00
v := reflect . ValueOf ( struct { } { } )
switch field . Kind ( ) {
case reflect . Slice , reflect . Array :
2019-08-02 17:11:23 +09:00
if param == "" {
m := reflect . MakeMap ( reflect . MapOf ( field . Type ( ) . Elem ( ) , v . Type ( ) ) )
for i := 0 ; i < field . Len ( ) ; i ++ {
m . SetMapIndex ( field . Index ( i ) , v )
}
return field . Len ( ) == m . Len ( )
}
sf , ok := field . Type ( ) . Elem ( ) . FieldByName ( param )
if ! ok {
panic ( fmt . Sprintf ( "Bad field name %s" , param ) )
}
2017-10-22 17:20:41 -07:00
2019-08-02 17:11:23 +09:00
m := reflect . MakeMap ( reflect . MapOf ( sf . Type , v . Type ( ) ) )
2017-10-22 17:20:41 -07:00
for i := 0 ; i < field . Len ( ) ; i ++ {
2019-08-02 17:11:23 +09:00
m . SetMapIndex ( field . Index ( i ) . FieldByName ( param ) , v )
2017-10-22 17:20:41 -07:00
}
return field . Len ( ) == m . Len ( )
2018-05-04 13:20:05 +01:00
case reflect . Map :
m := reflect . MakeMap ( reflect . MapOf ( field . Type ( ) . Elem ( ) , v . Type ( ) ) )
for _ , k := range field . MapKeys ( ) {
m . SetMapIndex ( field . MapIndex ( k ) , v )
}
return field . Len ( ) == m . Len ( )
2017-10-22 17:20:41 -07:00
default :
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
}
2015-10-15 21:14:54 -04:00
// IsMAC is the validation function for validating if the field's value is a valid MAC address.
2016-08-03 14:46:35 -04:00
func isMAC ( fl FieldLevel ) bool {
_ , err := net . ParseMAC ( fl . Field ( ) . String ( ) )
2015-07-27 22:45:59 -04:00
return err == nil
2015-07-27 22:31:33 -04:00
}
2015-10-15 21:14:54 -04:00
// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
2016-08-03 14:46:35 -04:00
func isCIDRv4 ( fl FieldLevel ) bool {
2015-10-06 15:23:39 +02:00
2016-08-03 14:46:35 -04:00
ip , _ , err := net . ParseCIDR ( fl . Field ( ) . String ( ) )
2015-10-06 15:23:39 +02:00
return err == nil && ip . To4 ( ) != nil
}
2015-10-15 21:14:54 -04:00
// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
2016-08-03 14:46:35 -04:00
func isCIDRv6 ( fl FieldLevel ) bool {
2015-10-06 15:23:39 +02:00
2016-08-03 14:46:35 -04:00
ip , _ , err := net . ParseCIDR ( fl . Field ( ) . String ( ) )
2015-10-06 15:23:39 +02:00
return err == nil && ip . To4 ( ) == nil
}
2015-10-15 21:14:54 -04:00
// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
2016-08-03 14:46:35 -04:00
func isCIDR ( fl FieldLevel ) bool {
2015-10-06 15:23:39 +02:00
2016-08-03 14:46:35 -04:00
_ , _ , err := net . ParseCIDR ( fl . Field ( ) . String ( ) )
2015-10-06 15:23:39 +02:00
return err == nil
}
2015-10-15 21:14:54 -04:00
// IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
2016-08-03 14:46:35 -04:00
func isIPv4 ( fl FieldLevel ) bool {
2015-07-27 22:31:33 -04:00
2016-08-03 14:46:35 -04:00
ip := net . ParseIP ( fl . Field ( ) . String ( ) )
2015-07-27 22:31:33 -04:00
return ip != nil && ip . To4 ( ) != nil
}
2015-10-15 21:14:54 -04:00
// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
2016-08-03 14:46:35 -04:00
func isIPv6 ( fl FieldLevel ) bool {
ip := net . ParseIP ( fl . Field ( ) . String ( ) )
2015-07-27 22:31:33 -04:00
return ip != nil && ip . To4 ( ) == nil
}
2015-10-15 21:14:54 -04:00
// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
2016-08-03 14:46:35 -04:00
func isIP ( fl FieldLevel ) bool {
2015-07-27 22:31:33 -04:00
2016-08-03 14:46:35 -04:00
ip := net . ParseIP ( fl . Field ( ) . String ( ) )
2015-07-27 22:31:33 -04:00
return ip != nil
2015-07-14 22:45:37 -04:00
}
2015-06-17 09:02:26 -04:00
2015-10-15 21:14:54 -04:00
// IsSSN is the validation function for validating if the field's value is a valid SSN.
2016-08-03 14:46:35 -04:00
func isSSN ( fl FieldLevel ) bool {
field := fl . Field ( )
2015-06-17 09:02:26 -04:00
2015-07-14 22:45:37 -04:00
if field . Len ( ) != 11 {
return false
}
2015-06-17 09:02:26 -04:00
2015-09-02 20:57:31 -04:00
return sSNRegex . MatchString ( field . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-17 09:02:26 -04:00
2015-10-15 21:14:54 -04:00
// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
2016-08-03 14:46:35 -04:00
func isLongitude ( fl FieldLevel ) bool {
2019-01-28 11:14:55 +01:00
field := fl . Field ( )
var v string
switch field . Kind ( ) {
case reflect . String :
v = field . String ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
v = strconv . FormatInt ( field . Int ( ) , 10 )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
v = strconv . FormatUint ( field . Uint ( ) , 10 )
case reflect . Float32 :
v = strconv . FormatFloat ( field . Float ( ) , 'f' , - 1 , 32 )
case reflect . Float64 :
v = strconv . FormatFloat ( field . Float ( ) , 'f' , - 1 , 64 )
default :
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
return longitudeRegex . MatchString ( v )
2015-07-14 22:45:37 -04:00
}
2015-06-17 09:02:26 -04:00
2015-10-15 21:14:54 -04:00
// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
2016-08-03 14:46:35 -04:00
func isLatitude ( fl FieldLevel ) bool {
2019-01-28 11:14:55 +01:00
field := fl . Field ( )
var v string
switch field . Kind ( ) {
case reflect . String :
v = field . String ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
v = strconv . FormatInt ( field . Int ( ) , 10 )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
v = strconv . FormatUint ( field . Uint ( ) , 10 )
case reflect . Float32 :
v = strconv . FormatFloat ( field . Float ( ) , 'f' , - 1 , 32 )
case reflect . Float64 :
v = strconv . FormatFloat ( field . Float ( ) , 'f' , - 1 , 64 )
default :
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
return latitudeRegex . MatchString ( v )
2015-07-14 22:45:37 -04:00
}
2015-06-17 09:02:26 -04:00
2015-10-15 21:14:54 -04:00
// IsDataURI is the validation function for validating if the field's value is a valid data URI.
2016-08-03 14:46:35 -04:00
func isDataURI ( fl FieldLevel ) bool {
2015-06-17 09:02:26 -04:00
2016-08-03 14:46:35 -04:00
uri := strings . SplitN ( fl . Field ( ) . String ( ) , "," , 2 )
2015-06-17 09:02:26 -04:00
2015-07-14 22:45:37 -04:00
if len ( uri ) != 2 {
return false
}
2015-06-17 08:03:31 -04:00
2015-09-02 20:57:31 -04:00
if ! dataURIRegex . MatchString ( uri [ 0 ] ) {
2015-07-14 22:45:37 -04:00
return false
}
2015-06-17 08:03:31 -04:00
2016-08-03 14:46:35 -04:00
return base64Regex . MatchString ( uri [ 1 ] )
2015-07-14 22:45:37 -04:00
}
2015-06-17 08:03:31 -04:00
2015-10-15 21:14:54 -04:00
// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
2016-08-03 14:46:35 -04:00
func hasMultiByteCharacter ( fl FieldLevel ) bool {
field := fl . Field ( )
2015-06-16 23:22:36 -04:00
2015-07-14 22:45:37 -04:00
if field . Len ( ) == 0 {
return true
}
2015-06-16 23:22:36 -04:00
2015-09-02 20:57:31 -04:00
return multibyteRegex . MatchString ( field . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
2016-08-03 14:46:35 -04:00
func isPrintableASCII ( fl FieldLevel ) bool {
return printableASCIIRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsASCII is the validation function for validating if the field's value is a valid ASCII character.
2016-08-03 14:46:35 -04:00
func isASCII ( fl FieldLevel ) bool {
return aSCIIRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
2016-08-03 14:46:35 -04:00
func isUUID5 ( fl FieldLevel ) bool {
return uUID5Regex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
2016-08-03 14:46:35 -04:00
func isUUID4 ( fl FieldLevel ) bool {
return uUID4Regex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
2016-08-03 14:46:35 -04:00
func isUUID3 ( fl FieldLevel ) bool {
return uUID3Regex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsUUID is the validation function for validating if the field's value is a valid UUID of any version.
2016-08-03 14:46:35 -04:00
func isUUID ( fl FieldLevel ) bool {
return uUIDRegex . MatchString ( fl . Field ( ) . String ( ) )
2019-01-27 21:00:13 -08:00
}
// IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
func isUUID5RFC4122 ( fl FieldLevel ) bool {
return uUID5RFC4122Regex . MatchString ( fl . Field ( ) . String ( ) )
}
// IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
func isUUID4RFC4122 ( fl FieldLevel ) bool {
return uUID4RFC4122Regex . MatchString ( fl . Field ( ) . String ( ) )
}
// IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
func isUUID3RFC4122 ( fl FieldLevel ) bool {
return uUID3RFC4122Regex . MatchString ( fl . Field ( ) . String ( ) )
}
// IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
func isUUIDRFC4122 ( fl FieldLevel ) bool {
return uUIDRFC4122Regex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
2016-08-03 14:46:35 -04:00
func isISBN ( fl FieldLevel ) bool {
return isISBN10 ( fl ) || isISBN13 ( fl )
2015-07-14 22:45:37 -04:00
}
2015-06-16 23:22:36 -04:00
2015-10-15 21:14:54 -04:00
// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
2016-08-03 14:46:35 -04:00
func isISBN13 ( fl FieldLevel ) bool {
2015-06-16 23:22:36 -04:00
2016-08-03 14:46:35 -04:00
s := strings . Replace ( strings . Replace ( fl . Field ( ) . String ( ) , "-" , "" , 4 ) , " " , "" , 4 )
2015-06-16 23:22:36 -04:00
2015-09-02 20:57:31 -04:00
if ! iSBN13Regex . MatchString ( s ) {
2015-07-14 22:45:37 -04:00
return false
}
2015-06-16 23:22:36 -04:00
2015-07-14 22:45:37 -04:00
var checksum int32
var i int32
2015-06-16 23:22:36 -04:00
2015-07-14 22:45:37 -04:00
factor := [ ] int32 { 1 , 3 }
2015-06-16 23:22:36 -04:00
2015-07-14 22:45:37 -04:00
for i = 0 ; i < 12 ; i ++ {
checksum += factor [ i % 2 ] * int32 ( s [ i ] - '0' )
}
2015-06-16 23:22:36 -04:00
2016-07-09 11:28:37 -04:00
return ( int32 ( s [ 12 ] - '0' ) ) - ( ( 10 - ( checksum % 10 ) ) % 10 ) == 0
2015-07-14 22:45:37 -04:00
}
2015-05-22 22:28:40 -04:00
2015-10-15 21:14:54 -04:00
// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
2016-08-03 14:46:35 -04:00
func isISBN10 ( fl FieldLevel ) bool {
2015-05-22 22:28:40 -04:00
2016-08-03 14:46:35 -04:00
s := strings . Replace ( strings . Replace ( fl . Field ( ) . String ( ) , "-" , "" , 3 ) , " " , "" , 3 )
2015-05-22 22:28:40 -04:00
2015-09-02 20:57:31 -04:00
if ! iSBN10Regex . MatchString ( s ) {
2015-07-14 22:45:37 -04:00
return false
}
2015-05-22 22:28:40 -04:00
2015-07-14 22:45:37 -04:00
var checksum int32
var i int32
2015-05-22 22:28:40 -04:00
2015-07-14 22:45:37 -04:00
for i = 0 ; i < 9 ; i ++ {
checksum += ( i + 1 ) * int32 ( s [ i ] - '0' )
}
2015-05-22 22:28:40 -04:00
2015-07-14 22:45:37 -04:00
if s [ 9 ] == 'X' {
checksum += 10 * 10
} else {
checksum += 10 * int32 ( s [ 9 ] - '0' )
}
2015-05-22 22:28:40 -04:00
2016-07-09 11:28:37 -04:00
return checksum % 11 == 0
2015-07-14 22:45:37 -04:00
}
2015-05-19 15:20:34 -04:00
2018-04-08 19:38:12 -07:00
// IsEthereumAddress is the validation function for validating if the field's value is a valid ethereum address based currently only on the format
func isEthereumAddress ( fl FieldLevel ) bool {
2018-04-08 19:38:12 -07:00
address := fl . Field ( ) . String ( )
if ! ethAddressRegex . MatchString ( address ) {
return false
}
if ethaddressRegexUpper . MatchString ( address ) || ethAddressRegexLower . MatchString ( address ) {
return true
}
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
// checksum validation is blocked by https://github.com/golang/crypto/pull/28
return true
2018-04-08 19:38:12 -07:00
}
2018-04-08 19:38:12 -07:00
// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address
2018-04-08 19:38:12 -07:00
func isBitcoinAddress ( fl FieldLevel ) bool {
2018-04-08 19:38:12 -07:00
address := fl . Field ( ) . String ( )
2018-04-08 19:38:12 -07:00
if ! btcAddressRegex . MatchString ( address ) {
return false
}
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
alphabet := [ ] byte ( "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" )
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
decode := [ 25 ] byte { }
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
for _ , n := range [ ] byte ( address ) {
d := bytes . IndexByte ( alphabet , n )
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
for i := 24 ; i >= 0 ; i -- {
d += 58 * int ( decode [ i ] )
decode [ i ] = byte ( d % 256 )
d /= 256
2018-04-08 19:38:12 -07:00
}
2018-04-08 19:38:12 -07:00
}
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
h := sha256 . New ( )
2018-05-05 09:23:38 -07:00
_ , _ = h . Write ( decode [ : 21 ] )
2018-04-08 19:38:12 -07:00
d := h . Sum ( [ ] byte { } )
h = sha256 . New ( )
2018-05-05 09:23:38 -07:00
_ , _ = h . Write ( d )
2018-04-08 19:38:12 -07:00
validchecksum := [ 4 ] byte { }
computedchecksum := [ 4 ] byte { }
copy ( computedchecksum [ : ] , h . Sum ( d [ : 0 ] ) )
copy ( validchecksum [ : ] , decode [ 21 : ] )
return validchecksum == computedchecksum
}
2018-04-09 01:49:06 -07:00
// IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
2018-04-08 19:38:12 -07:00
func isBitcoinBech32Address ( fl FieldLevel ) bool {
address := fl . Field ( ) . String ( )
2018-05-05 09:23:38 -07:00
if ! btcLowerAddressRegexBech32 . MatchString ( address ) && ! btcUpperAddressRegexBech32 . MatchString ( address ) {
2018-04-08 19:38:12 -07:00
return false
}
am := len ( address ) % 8
2018-05-05 09:23:38 -07:00
if am == 0 || am == 3 || am == 5 {
2018-04-08 19:38:12 -07:00
return false
}
address = strings . ToLower ( address )
alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
hr := [ ] int { 3 , 3 , 0 , 2 , 3 } // the human readable part will always be bc
2018-05-05 09:23:38 -07:00
addr := address [ 3 : ]
dp := make ( [ ] int , 0 , len ( addr ) )
2018-04-08 19:38:12 -07:00
2018-05-05 09:23:38 -07:00
for _ , c := range addr {
2018-04-08 19:38:12 -07:00
dp = append ( dp , strings . IndexRune ( alphabet , c ) )
}
ver := dp [ 0 ]
2018-05-05 09:23:38 -07:00
if ver < 0 || ver > 16 {
2018-04-08 19:38:12 -07:00
return false
}
if ver == 0 {
if len ( address ) != 42 && len ( address ) != 62 {
2018-04-08 19:38:12 -07:00
return false
}
2018-04-08 19:38:12 -07:00
}
values := append ( hr , dp ... )
2018-05-05 09:23:38 -07:00
GEN := [ ] int { 0x3b6a57b2 , 0x26508e6d , 0x1ea119fa , 0x3d4233dd , 0x2a1462b3 }
2018-04-08 19:38:12 -07:00
p := 1
for _ , v := range values {
b := p >> 25
2018-05-05 09:23:38 -07:00
p = ( p & 0x1ffffff ) << 5 ^ v
2018-04-08 19:38:12 -07:00
for i := 0 ; i < 5 ; i ++ {
2018-05-05 09:23:38 -07:00
if ( b >> uint ( i ) ) & 1 == 1 {
2018-04-08 19:38:12 -07:00
p ^ = GEN [ i ]
}
}
}
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
if p != 1 {
return false
}
2018-04-08 19:38:12 -07:00
2018-04-08 19:38:12 -07:00
b := uint ( 0 )
acc := 0
mv := ( 1 << 5 ) - 1
2018-05-05 09:23:38 -07:00
var sw [ ] int
2018-04-08 19:38:12 -07:00
2018-05-05 09:23:38 -07:00
for _ , v := range dp [ 1 : len ( dp ) - 6 ] {
2018-04-08 19:38:12 -07:00
acc = ( acc << 5 ) | v
b += 5
2018-05-05 09:23:38 -07:00
for b >= 8 {
2018-04-08 19:38:12 -07:00
b -= 8
sw = append ( sw , ( acc >> b ) & mv )
}
}
2018-05-05 09:23:38 -07:00
if len ( sw ) < 2 || len ( sw ) > 40 {
2018-04-08 19:38:12 -07:00
return false
}
return true
2018-04-08 19:38:12 -07:00
}
2016-07-18 09:40:22 -04:00
// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
2016-08-03 14:46:35 -04:00
func excludesRune ( fl FieldLevel ) bool {
return ! containsRune ( fl )
2015-07-14 22:45:37 -04:00
}
2015-05-19 15:20:34 -04:00
2016-07-18 09:40:22 -04:00
// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
2016-08-03 14:46:35 -04:00
func excludesAll ( fl FieldLevel ) bool {
return ! containsAny ( fl )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-07-18 09:40:22 -04:00
// Excludes is the validation function for validating that the field's value does not contain the text specified within the param.
2016-08-03 14:46:35 -04:00
func excludes ( fl FieldLevel ) bool {
return ! contains ( fl )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-07-18 09:40:22 -04:00
// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param.
2016-08-03 14:46:35 -04:00
func containsRune ( fl FieldLevel ) bool {
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
r , _ := utf8 . DecodeRuneInString ( fl . Param ( ) )
return strings . ContainsRune ( fl . Field ( ) . String ( ) , r )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-07-18 09:40:22 -04:00
// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
2016-08-03 14:46:35 -04:00
func containsAny ( fl FieldLevel ) bool {
return strings . ContainsAny ( fl . Field ( ) . String ( ) , fl . Param ( ) )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-07-18 09:40:22 -04:00
// Contains is the validation function for validating that the field's value contains the text specified within the param.
2016-08-03 14:46:35 -04:00
func contains ( fl FieldLevel ) bool {
return strings . Contains ( fl . Field ( ) . String ( ) , fl . Param ( ) )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2019-03-15 15:21:21 -06:00
// StartsWith is the validation function for validating that the field's value starts with the text specified within the param.
func startsWith ( fl FieldLevel ) bool {
return strings . HasPrefix ( fl . Field ( ) . String ( ) , fl . Param ( ) )
}
// EndsWith is the validation function for validating that the field's value ends with the text specified within the param.
func endsWith ( fl FieldLevel ) bool {
return strings . HasSuffix ( fl . Field ( ) . String ( ) , fl . Param ( ) )
}
2019-01-08 20:31:28 -08:00
// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
func fieldContains ( fl FieldLevel ) bool {
field := fl . Field ( )
currentField , _ , ok := fl . GetStructFieldOK ( )
if ! ok {
return false
}
return strings . Contains ( field . String ( ) , currentField . String ( ) )
}
// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
func fieldExcludes ( fl FieldLevel ) bool {
field := fl . Field ( )
currentField , _ , ok := fl . GetStructFieldOK ( )
if ! ok {
return true
}
return ! strings . Contains ( field . String ( ) , currentField . String ( ) )
}
2015-10-15 21:14:54 -04:00
// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isNeField ( fl FieldLevel ) bool {
2015-08-17 09:05:20 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
2015-08-17 09:05:20 -04:00
2016-08-03 14:46:35 -04:00
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-17 09:05:20 -04:00
return true
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-19 20:17:28 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return field . Int ( ) != currentField . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return field . Uint ( ) != currentField . Uint ( )
case reflect . Float32 , reflect . Float64 :
return field . Float ( ) != currentField . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( field . Len ( ) ) != int64 ( currentField . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-19 20:17:28 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return true
}
if fieldType == timeType {
t := currentField . Interface ( ) . ( time . Time )
fieldTime := field . Interface ( ) . ( time . Time )
return ! fieldTime . Equal ( t )
}
}
// default reflect.String:
return field . String ( ) != currentField . String ( )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2015-10-15 21:14:54 -04:00
// IsNe is the validation function for validating that the field's value does not equal the provided param value.
2016-08-03 14:46:35 -04:00
func isNe ( fl FieldLevel ) bool {
return ! isEq ( fl )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2015-10-15 21:14:54 -04:00
// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
2016-08-03 14:46:35 -04:00
func isLteCrossStructField ( fl FieldLevel ) bool {
2015-08-16 15:59:05 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
topField , topKind , ok := fl . GetStructFieldOK ( )
if ! ok || topKind != kind {
2015-08-16 15:59:05 -04:00
return false
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-16 15:59:05 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return field . Int ( ) <= topField . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return field . Uint ( ) <= topField . Uint ( )
case reflect . Float32 , reflect . Float64 :
return field . Float ( ) <= topField . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( field . Len ( ) ) <= int64 ( topField . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-16 15:59:05 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return false
}
if fieldType == timeType {
fieldTime := field . Interface ( ) . ( time . Time )
topTime := topField . Interface ( ) . ( time . Time )
return fieldTime . Before ( topTime ) || fieldTime . Equal ( topTime )
}
}
// default reflect.String:
2015-08-16 21:12:26 -04:00
return field . String ( ) <= topField . String ( )
2015-08-16 15:59:05 -04:00
}
2015-10-15 21:14:54 -04:00
// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
2016-08-03 14:46:35 -04:00
func isLtCrossStructField ( fl FieldLevel ) bool {
2015-08-16 15:59:05 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
topField , topKind , ok := fl . GetStructFieldOK ( )
if ! ok || topKind != kind {
2015-08-16 15:59:05 -04:00
return false
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-16 15:59:05 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return field . Int ( ) < topField . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return field . Uint ( ) < topField . Uint ( )
case reflect . Float32 , reflect . Float64 :
return field . Float ( ) < topField . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( field . Len ( ) ) < int64 ( topField . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-16 15:59:05 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return false
}
if fieldType == timeType {
fieldTime := field . Interface ( ) . ( time . Time )
topTime := topField . Interface ( ) . ( time . Time )
return fieldTime . Before ( topTime )
}
}
// default reflect.String:
2015-08-16 21:12:26 -04:00
return field . String ( ) < topField . String ( )
2015-08-16 15:59:05 -04:00
}
2015-10-15 21:14:54 -04:00
// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
2016-08-03 14:46:35 -04:00
func isGteCrossStructField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-08-16 15:59:05 -04:00
2016-08-03 14:46:35 -04:00
topField , topKind , ok := fl . GetStructFieldOK ( )
if ! ok || topKind != kind {
2015-08-16 15:59:05 -04:00
return false
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-16 15:59:05 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return field . Int ( ) >= topField . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return field . Uint ( ) >= topField . Uint ( )
case reflect . Float32 , reflect . Float64 :
return field . Float ( ) >= topField . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( field . Len ( ) ) >= int64 ( topField . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-16 15:59:05 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return false
}
if fieldType == timeType {
fieldTime := field . Interface ( ) . ( time . Time )
topTime := topField . Interface ( ) . ( time . Time )
return fieldTime . After ( topTime ) || fieldTime . Equal ( topTime )
}
}
// default reflect.String:
2015-08-16 21:12:26 -04:00
return field . String ( ) >= topField . String ( )
2015-08-16 15:59:05 -04:00
}
2015-10-15 21:14:54 -04:00
// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
2016-08-03 14:46:35 -04:00
func isGtCrossStructField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-08-16 15:59:05 -04:00
2016-08-03 14:46:35 -04:00
topField , topKind , ok := fl . GetStructFieldOK ( )
if ! ok || topKind != kind {
2015-08-16 15:59:05 -04:00
return false
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-16 15:59:05 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return field . Int ( ) > topField . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return field . Uint ( ) > topField . Uint ( )
case reflect . Float32 , reflect . Float64 :
return field . Float ( ) > topField . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( field . Len ( ) ) > int64 ( topField . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-16 15:59:05 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return false
}
if fieldType == timeType {
fieldTime := field . Interface ( ) . ( time . Time )
topTime := topField . Interface ( ) . ( time . Time )
return fieldTime . After ( topTime )
}
}
// default reflect.String:
2015-08-16 21:12:26 -04:00
return field . String ( ) > topField . String ( )
2015-08-16 15:59:05 -04:00
}
2015-10-15 21:14:54 -04:00
// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
2016-08-03 14:46:35 -04:00
func isNeCrossStructField ( fl FieldLevel ) bool {
2015-08-16 15:37:47 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
topField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-17 09:05:20 -04:00
return true
}
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-19 20:17:28 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return topField . Int ( ) != field . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return topField . Uint ( ) != field . Uint ( )
case reflect . Float32 , reflect . Float64 :
return topField . Float ( ) != field . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( topField . Len ( ) ) != int64 ( field . Len ( ) )
case reflect . Struct :
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-19 20:17:28 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return true
}
if fieldType == timeType {
t := field . Interface ( ) . ( time . Time )
fieldTime := topField . Interface ( ) . ( time . Time )
return ! fieldTime . Equal ( t )
}
}
// default reflect.String:
return topField . String ( ) != field . String ( )
2015-08-16 15:37:47 -04:00
}
2015-10-15 21:14:54 -04:00
// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
2016-08-03 14:46:35 -04:00
func isEqCrossStructField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
topField , topKind , ok := fl . GetStructFieldOK ( )
if ! ok || topKind != kind {
2015-08-14 21:02:01 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-08-14 21:02:01 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return topField . Int ( ) == field . Int ( )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return topField . Uint ( ) == field . Uint ( )
case reflect . Float32 , reflect . Float64 :
return topField . Float ( ) == field . Float ( )
case reflect . Slice , reflect . Map , reflect . Array :
return int64 ( topField . Len ( ) ) == int64 ( field . Len ( ) )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:02:01 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != topField . Type ( ) {
return false
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2015-08-14 21:02:01 -04:00
if fieldType == timeType {
t := field . Interface ( ) . ( time . Time )
fieldTime := topField . Interface ( ) . ( time . Time )
2015-05-08 11:59:48 -04:00
2015-08-14 21:02:01 -04:00
return fieldTime . Equal ( t )
2015-07-14 22:45:37 -04:00
}
}
2015-05-08 11:59:48 -04:00
2015-08-14 21:02:01 -04:00
// default reflect.String:
2015-08-16 15:59:05 -04:00
return topField . String ( ) == field . String ( )
2015-08-14 21:02:01 -04:00
}
2015-10-15 21:14:54 -04:00
// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isEqField ( fl FieldLevel ) bool {
2015-08-14 21:02:01 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-14 21:02:01 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
2015-08-14 21:02:01 -04:00
return field . Int ( ) == currentField . Int ( )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
2015-08-14 21:02:01 -04:00
return field . Uint ( ) == currentField . Uint ( )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
2015-08-14 21:02:01 -04:00
return field . Float ( ) == currentField . Float ( )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Slice , reflect . Map , reflect . Array :
2015-08-14 21:02:01 -04:00
return int64 ( field . Len ( ) ) == int64 ( currentField . Len ( ) )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:02:01 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return false
}
if fieldType == timeType {
2015-05-08 11:59:48 -04:00
2015-08-14 21:02:01 -04:00
t := currentField . Interface ( ) . ( time . Time )
2015-07-14 22:45:37 -04:00
fieldTime := field . Interface ( ) . ( time . Time )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
return fieldTime . Equal ( t )
}
2015-08-14 21:02:01 -04:00
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2015-08-14 21:02:01 -04:00
// default reflect.String:
return field . String ( ) == currentField . String ( )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2015-10-15 21:14:54 -04:00
// IsEq is the validation function for validating if the current field's value is equal to the param's value.
2016-08-03 14:46:35 -04:00
func isEq ( fl FieldLevel ) bool {
field := fl . Field ( )
param := fl . Param ( )
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
switch field . Kind ( ) {
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . String :
return field . String ( ) == param
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
return int64 ( field . Len ( ) ) == p
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
return field . Int ( ) == p
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
return field . Uint ( ) == p
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
return field . Float ( ) == p
}
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-05-08 11:59:48 -04:00
2015-10-15 21:14:54 -04:00
// IsBase64 is the validation function for validating if the current field's value is a valid base 64.
2016-08-03 14:46:35 -04:00
func isBase64 ( fl FieldLevel ) bool {
return base64Regex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-05-08 11:59:48 -04:00
2018-03-26 22:22:56 -04:00
// 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 ( ) )
}
2015-10-15 21:14:54 -04:00
// IsURI is the validation function for validating if the current field's value is a valid URI.
2016-08-03 14:46:35 -04:00
func isURI ( fl FieldLevel ) bool {
2015-05-08 11:59:48 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
switch field . Kind ( ) {
2015-05-08 11:59:48 -04:00
2015-07-14 22:45:37 -04:00
case reflect . String :
2016-02-23 15:25:49 -05:00
s := field . String ( )
2016-02-23 15:26:02 -05:00
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
2016-02-23 15:25:49 -05:00
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i := strings . Index ( s , "#" ) ; i > - 1 {
s = s [ : i ]
}
2016-08-03 14:46:35 -04:00
if len ( s ) == 0 {
2016-02-23 15:25:49 -05:00
return false
}
_ , err := url . ParseRequestURI ( s )
2015-02-14 22:16:03 -05:00
2015-07-14 22:45:37 -04:00
return err == nil
}
2015-02-25 15:08:22 -05:00
2015-07-14 22:45:37 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-02-25 15:08:22 -05:00
2015-10-15 21:14:54 -04:00
// IsURL is the validation function for validating if the current field's value is a valid URL.
2016-08-03 14:46:35 -04:00
func isURL ( fl FieldLevel ) bool {
field := fl . Field ( )
2015-02-25 15:08:22 -05:00
2016-08-03 14:46:35 -04:00
switch field . Kind ( ) {
2015-02-25 15:08:22 -05:00
2015-07-14 22:45:37 -04:00
case reflect . String :
2015-03-10 15:07:00 -04:00
2016-02-23 15:25:49 -05:00
var i int
s := field . String ( )
2016-02-23 15:26:02 -05:00
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
2016-02-23 15:25:49 -05:00
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i = strings . Index ( s , "#" ) ; i > - 1 {
s = s [ : i ]
}
2016-08-03 14:46:35 -04:00
if len ( s ) == 0 {
2015-07-14 22:45:37 -04:00
return false
}
2015-02-25 15:08:22 -05:00
2016-02-23 15:25:49 -05:00
url , err := url . ParseRequestURI ( s )
2016-08-03 14:46:35 -04:00
if err != nil || url . Scheme == "" {
2015-07-14 22:45:37 -04:00
return false
}
2015-02-25 15:08:22 -05:00
2015-07-14 22:45:37 -04:00
return err == nil
}
2015-02-13 14:23:21 -05:00
2018-06-27 12:03:42 +03:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2018-12-04 10:35:01 +01:00
// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
func isUrnRFC2141 ( fl FieldLevel ) bool {
2018-12-04 03:33:00 +01:00
field := fl . Field ( )
switch field . Kind ( ) {
case reflect . String :
str := field . String ( )
_ , match := urn . Parse ( [ ] byte ( str ) )
return match
}
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2018-06-27 12:03:42 +03:00
// IsFile is the validation function for validating if the current field's value is a valid file path.
func isFile ( fl FieldLevel ) bool {
field := fl . Field ( )
switch field . Kind ( ) {
case reflect . String :
fileInfo , err := os . Stat ( field . String ( ) )
if err != nil {
return false
}
return ! fileInfo . IsDir ( )
}
2015-07-14 22:45:37 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-02-13 14:23:21 -05:00
2019-10-16 16:16:27 -06:00
// IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
func isE164 ( fl FieldLevel ) bool {
return e164Regex . MatchString ( fl . Field ( ) . String ( ) )
}
2015-10-15 21:14:54 -04:00
// IsEmail is the validation function for validating if the current field's value is a valid email address.
2016-08-03 14:46:35 -04:00
func isEmail ( fl FieldLevel ) bool {
return emailRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-02-12 20:49:57 -05:00
}
2015-02-12 22:42:16 -05:00
2015-10-15 21:14:54 -04:00
// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color.
2016-08-03 14:46:35 -04:00
func isHSLA ( fl FieldLevel ) bool {
return hslaRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsHSL is the validation function for validating if the current field's value is a valid HSL color.
2016-08-03 14:46:35 -04:00
func isHSL ( fl FieldLevel ) bool {
return hslRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color.
2016-08-03 14:46:35 -04:00
func isRGBA ( fl FieldLevel ) bool {
return rgbaRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsRGB is the validation function for validating if the current field's value is a valid RGB color.
2016-08-03 14:46:35 -04:00
func isRGB ( fl FieldLevel ) bool {
return rgbRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color.
2016-08-03 14:46:35 -04:00
func isHEXColor ( fl FieldLevel ) bool {
return hexcolorRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
2016-08-03 14:46:35 -04:00
func isHexadecimal ( fl FieldLevel ) bool {
return hexadecimalRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsNumber is the validation function for validating if the current field's value is a valid number.
2016-08-03 14:46:35 -04:00
func isNumber ( fl FieldLevel ) bool {
2018-05-09 09:00:03 -07:00
switch fl . Field ( ) . Kind ( ) {
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 , reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr , reflect . Float32 , reflect . Float64 :
return true
default :
return numberRegex . MatchString ( fl . Field ( ) . String ( ) )
}
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsNumeric is the validation function for validating if the current field's value is a valid numeric value.
2016-08-03 14:46:35 -04:00
func isNumeric ( fl FieldLevel ) bool {
2018-05-09 09:00:03 -07:00
switch fl . Field ( ) . Kind ( ) {
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 , reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr , reflect . Float32 , reflect . Float64 :
return true
default :
return numericRegex . MatchString ( fl . Field ( ) . String ( ) )
}
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
2016-08-03 14:46:35 -04:00
func isAlphanum ( fl FieldLevel ) bool {
return alphaNumericRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsAlpha is the validation function for validating if the current field's value is a valid alpha value.
2016-08-03 14:46:35 -04:00
func isAlpha ( fl FieldLevel ) bool {
return alphaRegex . MatchString ( fl . Field ( ) . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2016-11-30 08:37:03 -05:00
// IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
func isAlphanumUnicode ( fl FieldLevel ) bool {
return alphaUnicodeNumericRegex . MatchString ( fl . Field ( ) . String ( ) )
}
// IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
func isAlphaUnicode ( fl FieldLevel ) bool {
return alphaUnicodeRegex . MatchString ( fl . Field ( ) . String ( ) )
}
2017-08-20 09:53:47 -07:00
// isDefault is the opposite of required aka hasValue
func isDefault ( fl FieldLevel ) bool {
return ! hasValue ( fl )
}
2015-10-15 21:14:54 -04:00
// HasValue is the validation function for validating if the current field's value is not the default static value.
2016-08-03 14:46:35 -04:00
func hasValue ( fl FieldLevel ) bool {
2019-09-29 13:39:27 -07:00
field := fl . Field ( )
switch field . Kind ( ) {
case reflect . Slice , reflect . Map , reflect . Ptr , reflect . Interface , reflect . Chan , reflect . Func :
return ! field . IsNil ( )
default :
if fl . ( * validate ) . fldIsPointer && field . Interface ( ) != nil {
return true
}
return field . IsValid ( ) && field . Interface ( ) != reflect . Zero ( field . Type ( ) ) . Interface ( )
}
2019-05-01 16:39:21 +04:30
}
2016-08-03 14:46:35 -04:00
2019-05-01 16:39:21 +04:30
// requireCheckField is a func for check field kind
2019-09-29 14:12:27 -07:00
func requireCheckFieldKind ( fl FieldLevel , param string , defaultNotFoundValue bool ) bool {
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
2019-09-29 13:39:27 -07:00
kind := field . Kind ( )
2019-11-17 13:02:10 -08:00
var nullable , found bool
2019-05-01 16:39:21 +04:30
if len ( param ) > 0 {
2019-11-17 13:02:10 -08:00
field , kind , nullable , found = fl . GetStructFieldOKAdvanced2 ( fl . Parent ( ) , param )
if ! found {
2019-09-29 14:12:27 -07:00
return defaultNotFoundValue
2019-06-14 03:06:35 +08:00
}
2019-05-01 16:39:21 +04:30
}
2019-09-29 13:39:27 -07:00
switch kind {
case reflect . Invalid :
2019-09-29 14:12:27 -07:00
return defaultNotFoundValue
2015-07-27 17:20:42 -04:00
case reflect . Slice , reflect . Map , reflect . Ptr , reflect . Interface , reflect . Chan , reflect . Func :
2019-11-17 13:02:10 -08:00
return field . IsNil ( )
2015-07-14 22:45:37 -04:00
default :
2019-11-17 13:02:10 -08:00
if nullable && field . Interface ( ) != nil {
return false
}
return field . IsValid ( ) && field . Interface ( ) == reflect . Zero ( field . Type ( ) ) . Interface ( )
2015-07-14 22:45:37 -04:00
}
}
2015-03-10 23:34:19 -04:00
2019-04-29 15:35:35 +04:30
// RequiredWith is the validation function
2019-04-29 15:46:48 +04:30
// The field under validation must be present and not empty only if any of the other specified fields are present.
2019-04-29 15:32:37 +04:30
func requiredWith ( fl FieldLevel ) bool {
params := parseOneOfParam2 ( fl . Param ( ) )
for _ , param := range params {
2019-11-17 13:02:10 -08:00
if ! requireCheckFieldKind ( fl , param , true ) {
2019-09-29 14:12:27 -07:00
return hasValue ( fl )
2019-04-29 15:32:37 +04:30
}
}
return true
}
2019-04-29 15:46:48 +04:30
// RequiredWithAll is the validation function
// The field under validation must be present and not empty only if all of the other specified fields are present.
func requiredWithAll ( fl FieldLevel ) bool {
params := parseOneOfParam2 ( fl . Param ( ) )
for _ , param := range params {
2019-11-17 13:02:10 -08:00
if requireCheckFieldKind ( fl , param , true ) {
2019-09-29 14:12:27 -07:00
return true
2019-04-29 15:46:48 +04:30
}
}
2019-09-29 14:12:27 -07:00
return hasValue ( fl )
2019-04-29 15:46:48 +04:30
}
2019-04-29 16:01:11 +04:30
// RequiredWithout is the validation function
// The field under validation must be present and not empty only when any of the other specified fields are not present.
func requiredWithout ( fl FieldLevel ) bool {
2019-11-17 13:02:10 -08:00
if requireCheckFieldKind ( fl , strings . TrimSpace ( fl . Param ( ) ) , true ) {
return hasValue ( fl )
2019-04-29 16:01:11 +04:30
}
return true
}
2019-04-29 16:05:30 +04:30
// RequiredWithoutAll is the validation function
// The field under validation must be present and not empty only when all of the other specified fields are not present.
func requiredWithoutAll ( fl FieldLevel ) bool {
params := parseOneOfParam2 ( fl . Param ( ) )
for _ , param := range params {
2019-11-17 13:02:10 -08:00
if ! requireCheckFieldKind ( fl , param , true ) {
2019-09-29 13:39:27 -07:00
return true
2019-04-29 16:05:30 +04:30
}
}
2019-09-29 13:39:27 -07:00
return hasValue ( fl )
2019-04-29 16:05:30 +04:30
}
2015-10-15 21:14:54 -04:00
// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isGteField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-14 21:31:16 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
return field . Int ( ) >= currentField . Int ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
return field . Uint ( ) >= currentField . Uint ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
return field . Float ( ) >= currentField . Float ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:31:16 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return false
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
if fieldType == timeType {
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
t := currentField . Interface ( ) . ( time . Time )
2015-07-14 22:45:37 -04:00
fieldTime := field . Interface ( ) . ( time . Time )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
return fieldTime . After ( t ) || fieldTime . Equal ( t )
}
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:31:16 -04:00
// default reflect.String
return len ( field . String ( ) ) >= len ( currentField . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isGtField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-08-14 21:19:41 -04:00
2016-08-03 14:46:35 -04:00
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-14 21:19:41 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
return field . Int ( ) > currentField . Int ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
return field . Uint ( ) > currentField . Uint ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
return field . Float ( ) > currentField . Float ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:19:41 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return false
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
if fieldType == timeType {
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
t := currentField . Interface ( ) . ( time . Time )
2015-07-14 22:45:37 -04:00
fieldTime := field . Interface ( ) . ( time . Time )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
return fieldTime . After ( t )
}
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:19:41 -04:00
// default reflect.String
return len ( field . String ( ) ) > len ( currentField . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-02-15 23:20:33 -05:00
2015-10-15 21:14:54 -04:00
// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
2016-08-03 14:46:35 -04:00
func isGte ( fl FieldLevel ) bool {
2015-02-15 23:20:33 -05:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
param := fl . Param ( )
switch field . Kind ( ) {
2015-02-15 23:20:33 -05:00
case reflect . String :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return int64 ( utf8 . RuneCountInString ( field . String ( ) ) ) >= p
2015-02-15 23:20:33 -05:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return int64 ( field . Len ( ) ) >= p
2015-02-15 23:20:33 -05:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return field . Int ( ) >= p
2015-02-15 23:20:33 -05:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-07-14 13:36:55 -04:00
return field . Uint ( ) >= p
2015-02-15 23:20:33 -05:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-07-14 13:36:55 -04:00
return field . Float ( ) >= p
2015-02-15 23:20:33 -05:00
2015-03-10 15:07:00 -04:00
case reflect . Struct :
2016-08-03 14:46:35 -04:00
if field . Type ( ) == timeType {
2015-03-10 15:07:00 -04:00
now := time . Now ( ) . UTC ( )
2015-07-14 13:36:55 -04:00
t := field . Interface ( ) . ( time . Time )
2015-03-10 15:07:00 -04:00
return t . After ( now ) || t . Equal ( now )
}
2015-02-15 23:20:33 -05:00
}
2015-03-10 15:07:00 -04:00
2015-07-14 21:10:25 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
2015-02-15 23:20:33 -05:00
}
2015-10-15 21:14:54 -04:00
// IsGt is the validation function for validating if the current field's value is greater than the param's value.
2016-08-03 14:46:35 -04:00
func isGt ( fl FieldLevel ) bool {
2015-02-15 23:20:33 -05:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
param := fl . Param ( )
switch field . Kind ( ) {
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
case reflect . String :
p := asInt ( param )
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
return int64 ( utf8 . RuneCountInString ( field . String ( ) ) ) > p
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
return int64 ( field . Len ( ) ) > p
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
return field . Int ( ) > p
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
return field . Uint ( ) > p
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-02-15 23:20:33 -05:00
2015-07-14 22:45:37 -04:00
return field . Float ( ) > p
case reflect . Struct :
2015-02-15 23:20:33 -05:00
2016-08-03 14:46:35 -04:00
if field . Type ( ) == timeType {
2015-03-10 15:07:00 -04:00
2015-07-14 22:45:37 -04:00
return field . Interface ( ) . ( time . Time ) . After ( time . Now ( ) . UTC ( ) )
}
}
2015-03-10 15:07:00 -04:00
2015-07-14 22:45:37 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-02-15 23:20:33 -05:00
2015-10-15 21:14:54 -04:00
// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
2016-08-03 14:46:35 -04:00
func hasLengthOf ( fl FieldLevel ) bool {
2015-02-12 22:42:16 -05:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
param := fl . Param ( )
switch field . Kind ( ) {
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
case reflect . String :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
return int64 ( utf8 . RuneCountInString ( field . String ( ) ) ) == p
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
return int64 ( field . Len ( ) ) == p
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
return field . Int ( ) == p
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
return field . Uint ( ) == p
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 21:10:25 -04:00
return field . Float ( ) == p
}
2015-03-10 15:07:00 -04:00
2015-07-14 21:10:25 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-02-12 22:42:16 -05:00
2015-10-15 21:14:54 -04:00
// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
2016-08-03 14:46:35 -04:00
func hasMinOf ( fl FieldLevel ) bool {
return isGte ( fl )
2015-02-15 23:20:33 -05:00
}
2015-10-15 21:14:54 -04:00
// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isLteField ( fl FieldLevel ) bool {
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
field := fl . Field ( )
kind := field . Kind ( )
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-14 21:41:25 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Int ( ) <= currentField . Int ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Uint ( ) <= currentField . Uint ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Float ( ) <= currentField . Float ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:41:25 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return false
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
if fieldType == timeType {
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
t := currentField . Interface ( ) . ( time . Time )
2015-07-14 22:45:37 -04:00
fieldTime := field . Interface ( ) . ( time . Time )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
return fieldTime . Before ( t ) || fieldTime . Equal ( t )
}
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
// default reflect.String
return len ( field . String ( ) ) <= len ( currentField . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2015-10-15 21:14:54 -04:00
// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
2016-08-03 14:46:35 -04:00
func isLtField ( fl FieldLevel ) bool {
field := fl . Field ( )
kind := field . Kind ( )
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
currentField , currentKind , ok := fl . GetStructFieldOK ( )
if ! ok || currentKind != kind {
2015-08-14 21:41:25 -04:00
return false
2015-07-14 22:45:37 -04:00
}
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
switch kind {
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Int ( ) < currentField . Int ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Uint ( ) < currentField . Uint ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
return field . Float ( ) < currentField . Float ( )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-03-10 23:34:19 -04:00
2016-08-03 14:46:35 -04:00
fieldType := field . Type ( )
2015-08-14 21:41:25 -04:00
// Not Same underlying type i.e. struct and time
if fieldType != currentField . Type ( ) {
return false
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
if fieldType == timeType {
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
t := currentField . Interface ( ) . ( time . Time )
2015-07-14 22:45:37 -04:00
fieldTime := field . Interface ( ) . ( time . Time )
2015-03-10 23:34:19 -04:00
2015-07-14 22:45:37 -04:00
return fieldTime . Before ( t )
}
}
2015-03-10 23:34:19 -04:00
2015-08-14 21:41:25 -04:00
// default reflect.String
return len ( field . String ( ) ) < len ( currentField . String ( ) )
2015-07-14 22:45:37 -04:00
}
2015-02-15 23:20:33 -05:00
2015-10-15 21:14:54 -04:00
// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value.
2016-08-03 14:46:35 -04:00
func isLte ( fl FieldLevel ) bool {
field := fl . Field ( )
param := fl . Param ( )
2015-02-12 22:42:16 -05:00
2016-08-03 14:46:35 -04:00
switch field . Kind ( ) {
2015-02-12 22:42:16 -05:00
case reflect . String :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return int64 ( utf8 . RuneCountInString ( field . String ( ) ) ) <= p
2015-02-12 22:42:16 -05:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return int64 ( field . Len ( ) ) <= p
2015-02-12 22:42:16 -05:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-07-14 13:36:55 -04:00
return field . Int ( ) <= p
2015-02-12 22:42:16 -05:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-07-14 13:36:55 -04:00
return field . Uint ( ) <= p
2015-02-12 22:42:16 -05:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-07-14 13:36:55 -04:00
return field . Float ( ) <= p
2015-02-12 22:42:16 -05:00
2015-03-10 15:07:00 -04:00
case reflect . Struct :
2016-08-03 14:46:35 -04:00
if field . Type ( ) == timeType {
2015-03-10 15:07:00 -04:00
now := time . Now ( ) . UTC ( )
2015-07-14 13:36:55 -04:00
t := field . Interface ( ) . ( time . Time )
2015-03-10 15:07:00 -04:00
return t . Before ( now ) || t . Equal ( now )
}
2015-02-12 22:42:16 -05:00
}
2015-03-10 15:07:00 -04:00
2015-07-14 21:10:25 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
2015-02-12 22:42:16 -05:00
}
2015-10-15 21:14:54 -04:00
// IsLt is the validation function for validating if the current field's value is less than the param's value.
2016-08-03 14:46:35 -04:00
func isLt ( fl FieldLevel ) bool {
field := fl . Field ( )
param := fl . Param ( )
2015-02-12 22:42:16 -05:00
2016-08-03 14:46:35 -04:00
switch field . Kind ( ) {
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . String :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
return int64 ( utf8 . RuneCountInString ( field . String ( ) ) ) < p
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Slice , reflect . Map , reflect . Array :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
return int64 ( field . Len ( ) ) < p
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
p := asInt ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
return field . Int ( ) < p
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
p := asUint ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
return field . Uint ( ) < p
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Float32 , reflect . Float64 :
p := asFloat ( param )
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
return field . Float ( ) < p
2015-02-12 22:42:16 -05:00
2015-07-14 22:45:37 -04:00
case reflect . Struct :
2015-03-10 15:07:00 -04:00
2016-08-03 14:46:35 -04:00
if field . Type ( ) == timeType {
2015-03-10 15:07:00 -04:00
2015-07-14 22:45:37 -04:00
return field . Interface ( ) . ( time . Time ) . Before ( time . Now ( ) . UTC ( ) )
}
}
2015-03-10 15:07:00 -04:00
2015-07-14 22:45:37 -04:00
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}
2015-02-12 22:42:16 -05:00
2015-10-15 21:14:54 -04:00
// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
2016-08-03 14:46:35 -04:00
func hasMaxOf ( fl FieldLevel ) bool {
return isLte ( fl )
2015-02-15 23:20:33 -05:00
}
2016-01-19 13:01:05 +01:00
2016-01-19 15:09:50 +01:00
// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
2016-08-03 14:46:35 -04:00
func isTCP4AddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP4Addr ( fl ) {
2016-01-20 10:06:30 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveTCPAddr ( "tcp4" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
2016-08-03 14:46:35 -04:00
func isTCP6AddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP6Addr ( fl ) {
2016-01-20 10:06:30 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveTCPAddr ( "tcp6" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
2016-08-03 14:46:35 -04:00
func isTCPAddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP4Addr ( fl ) && ! isIP6Addr ( fl ) {
2016-02-02 08:12:47 -05:00
return false
}
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveTCPAddr ( "tcp" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
2016-08-03 14:46:35 -04:00
func isUDP4AddrResolvable ( fl FieldLevel ) bool {
2016-02-02 08:23:37 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP4Addr ( fl ) {
2016-02-02 08:23:37 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveUDPAddr ( "udp4" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
2016-08-03 14:46:35 -04:00
func isUDP6AddrResolvable ( fl FieldLevel ) bool {
2016-02-02 08:23:37 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP6Addr ( fl ) {
2016-02-02 08:23:37 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveUDPAddr ( "udp6" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
2016-08-03 14:46:35 -04:00
func isUDPAddrResolvable ( fl FieldLevel ) bool {
2016-02-02 08:23:37 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP4Addr ( fl ) && ! isIP6Addr ( fl ) {
2016-02-02 08:23:37 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveUDPAddr ( "udp" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
2016-08-03 14:46:35 -04:00
func isIP4AddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIPv4 ( fl ) {
2016-01-20 10:06:30 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveIPAddr ( "ip4" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
2016-08-03 14:46:35 -04:00
func isIP6AddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIPv6 ( fl ) {
2016-01-20 10:06:30 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveIPAddr ( "ip6" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
2016-08-03 14:46:35 -04:00
func isIPAddrResolvable ( fl FieldLevel ) bool {
2016-01-20 10:06:30 -05:00
2016-08-03 14:46:35 -04:00
if ! isIP ( fl ) {
2016-01-20 10:06:30 -05:00
return false
}
2016-08-03 14:46:35 -04:00
_ , err := net . ResolveIPAddr ( "ip" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-01-19 15:09:50 +01:00
// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
2016-08-03 14:46:35 -04:00
func isUnixAddrResolvable ( fl FieldLevel ) bool {
_ , err := net . ResolveUnixAddr ( "unix" , fl . Field ( ) . String ( ) )
2016-01-19 13:01:05 +01:00
return err == nil
}
2016-02-02 08:33:55 -05:00
2016-08-03 14:46:35 -04:00
func isIP4Addr ( fl FieldLevel ) bool {
val := fl . Field ( ) . String ( )
2016-02-02 08:33:55 -05:00
if idx := strings . LastIndex ( val , ":" ) ; idx != - 1 {
val = val [ 0 : idx ]
}
2016-08-03 14:46:35 -04:00
ip := net . ParseIP ( val )
2016-02-02 08:33:55 -05:00
2016-08-03 14:46:35 -04:00
return ip != nil && ip . To4 ( ) != nil
2016-02-02 08:33:55 -05:00
}
2016-08-03 14:46:35 -04:00
func isIP6Addr ( fl FieldLevel ) bool {
val := fl . Field ( ) . String ( )
2016-02-02 08:33:55 -05:00
if idx := strings . LastIndex ( val , ":" ) ; idx != - 1 {
if idx != 0 && val [ idx - 1 : idx ] == "]" {
val = val [ 1 : idx - 1 ]
}
}
2016-08-03 14:46:35 -04:00
ip := net . ParseIP ( val )
2016-02-02 08:33:55 -05:00
2016-08-03 14:46:35 -04:00
return ip != nil && ip . To4 ( ) == nil
2016-02-02 08:33:55 -05:00
}
2017-08-05 09:01:57 +02:00
2018-02-15 08:50:04 -08:00
func isHostnameRFC952 ( fl FieldLevel ) bool {
return hostnameRegexRFC952 . MatchString ( fl . Field ( ) . String ( ) )
}
func isHostnameRFC1123 ( fl FieldLevel ) bool {
return hostnameRegexRFC1123 . MatchString ( fl . Field ( ) . String ( ) )
2017-08-05 09:01:57 +02:00
}
func isFQDN ( fl FieldLevel ) bool {
val := fl . Field ( ) . String ( )
2017-09-06 20:37:05 -07:00
if val == "" {
return false
}
2017-08-05 09:12:57 +02:00
if val [ len ( val ) - 1 ] == '.' {
val = val [ 0 : len ( val ) - 1 ]
2017-08-05 09:01:57 +02:00
}
2018-02-15 08:50:04 -08:00
return strings . ContainsAny ( val , "." ) &&
hostnameRegexRFC952 . MatchString ( val )
2017-08-05 09:01:57 +02:00
}
2019-02-08 16:03:16 +01:00
// IsDir is the validation function for validating if the current field's value is a valid directory.
func isDir ( fl FieldLevel ) bool {
field := fl . Field ( )
if field . Kind ( ) == reflect . String {
fileInfo , err := os . Stat ( field . String ( ) )
if err != nil {
return false
}
return fileInfo . IsDir ( )
}
panic ( fmt . Sprintf ( "Bad field type %T" , field . Interface ( ) ) )
}