diff --git a/baked_in.go b/baked_in.go index e9fc9a4..2d60162 100644 --- a/baked_in.go +++ b/baked_in.go @@ -84,6 +84,16 @@ var bakedInValidators = map[string]Func{ "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, } @@ -1236,3 +1246,150 @@ func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Val func HasMaxOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { return IsLte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) } + +// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsTCP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveTCPAddr("tcp4", field.String()) + return err == nil +} + +// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsTCP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveTCPAddr("tcp6", field.String()) + return err == nil +} + +// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsTCPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && + !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveTCPAddr("tcp", field.String()) + return err == nil +} + +// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsUDP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveUDPAddr("udp4", field.String()) + return err == nil +} + +// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsUDP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveUDPAddr("udp6", field.String()) + return err == nil +} + +// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsUDPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) && + !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveUDPAddr("udp", field.String()) + return err == nil +} + +// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsIP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !IsIPv4(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveIPAddr("ip4", field.String()) + return err == nil +} + +// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsIP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !IsIPv6(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveIPAddr("ip6", field.String()) + return err == nil +} + +// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsIPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + + if !IsIP(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) { + return false + } + + _, err := net.ResolveIPAddr("ip", field.String()) + return err == nil +} + +// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address. +// NOTE: This is exposed for use within your own custom functions and not intended to be called directly. +func IsUnixAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + _, err := net.ResolveUnixAddr("unix", field.String()) + return err == nil +} + +func isIP4Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + val := field.String() + + if idx := strings.LastIndex(val, ":"); idx != -1 { + val = val[0:idx] + } + + if !IsIPv4(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { + return false + } + + return true +} + +func isIP6Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool { + val := field.String() + + if idx := strings.LastIndex(val, ":"); idx != -1 { + if idx != 0 && val[idx-1:idx] == "]" { + val = val[1 : idx-1] + } + } + + if !IsIPv6(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) { + return false + } + + return true +} diff --git a/doc.go b/doc.go index d9a5270..c351a61 100644 --- a/doc.go +++ b/doc.go @@ -735,6 +735,66 @@ This validates that a string value contains a valid v6 CIDR Adress. Usage: cidrv6 +Transmission Control Protocol Address TCP + +This validates that a string value contains a valid resolvable TCP Adress. + + Usage: tcp_addr + +Transmission Control Protocol Address TCPv4 + +This validates that a string value contains a valid resolvable v4 TCP Adress. + + Usage: tcp4_addr + +Transmission Control Protocol Address TCPv6 + +This validates that a string value contains a valid resolvable v6 TCP Adress. + + Usage: tcp6_addr + +User Datagram Protocol Address UDP + +This validates that a string value contains a valid resolvable UDP Adress. + + Usage: udp_addr + +User Datagram Protocol Address UDPv4 + +This validates that a string value contains a valid resolvable v4 UDP Adress. + + Usage: udp4_addr + +User Datagram Protocol Address UDPv6 + +This validates that a string value contains a valid resolvable v6 UDP Adress. + + Usage: udp6_addr + +Internet Protocol Address IP + +This validates that a string value contains a valid resolvable IP Adress. + + Usage: ip_addr + +Internet Protocol Address IPv4 + +This validates that a string value contains a valid resolvable v4 IP Adress. + + Usage: ip4_addr + +Internet Protocol Address IPv6 + +This validates that a string value contains a valid resolvable v6 IP Adress. + + Usage: ip6_addr + +Unix domain socket end point Address + +This validates that a string value contains a valid Unix Adress. + + Usage: unix_addr + Media Access Control Address MAC This validates that a string value contains a valid MAC Adress. @@ -745,8 +805,6 @@ Note: See Go's ParseMAC for accepted formats and types: http://golang.org/src/net/mac.go?s=866:918#L29 - Usage: mac - Alias Validators and Tags NOTE: When returning an error, the tag returned in "FieldError" will be diff --git a/validator_test.go b/validator_test.go index 189e522..63f3d9b 100644 --- a/validator_test.go +++ b/validator_test.go @@ -1755,6 +1755,7 @@ func TestIPValidation(t *testing.T) { param string expected bool }{ + {"", false}, {"10.0.0.1", true}, {"172.16.0.1", true}, {"192.168.0.1", true}, @@ -1987,6 +1988,326 @@ func TestCIDRv4Validation(t *testing.T) { } } +func TestTCPAddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", true}, + {"[::1]:80", true}, + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "tcp_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "tcp_addr" { + t.Fatalf("Index: %d tcp_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestTCP6AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", false}, + {"[::1]:80", true}, + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "tcp6_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "tcp6_addr" { + t.Fatalf("Index: %d tcp6_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestTCP4AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", true}, + {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "tcp4_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Log(test.param, IsEqual(errs, nil)) + t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "tcp4_addr" { + t.Fatalf("Index: %d tcp4_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestUDPAddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", true}, + {"[::1]:80", true}, + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "udp_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "udp_addr" { + t.Fatalf("Index: %d udp_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestUDP6AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", false}, + {"[::1]:80", true}, + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "udp6_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "udp6_addr" { + t.Fatalf("Index: %d udp6_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestUDP4AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {":80", false}, + {"127.0.0.1:80", true}, + {"[::1]:80", false}, // https://github.com/golang/go/issues/14037 + {"256.0.0.0:1", false}, + {"[::1]", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "udp4_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Log(test.param, IsEqual(errs, nil)) + t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "udp4_addr" { + t.Fatalf("Index: %d udp4_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestIPAddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"127.0.0.1:80", false}, + {"::1", true}, + {"256.0.0.0", false}, + {"localhost", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "ip_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "ip_addr" { + t.Fatalf("Index: %d ip_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestIP6AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", false}, // https://github.com/golang/go/issues/14037 + {"127.0.0.1:80", false}, + {"::1", true}, + {"0:0:0:0:0:0:0:1", true}, + {"256.0.0.0", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "ip6_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "ip6_addr" { + t.Fatalf("Index: %d ip6_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestIP4AddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"127.0.0.1:80", false}, + {"::1", false}, // https://github.com/golang/go/issues/14037 + {"256.0.0.0", false}, + {"localhost", false}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "ip4_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Log(test.param, IsEqual(errs, nil)) + t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "ip4_addr" { + t.Fatalf("Index: %d ip4_addr failed Error: %s", i, errs) + } + } + } + } +} + +func TestUnixAddrValidation(t *testing.T) { + tests := []struct { + param string + expected bool + }{ + {"", true}, + {"v.sock", true}, + } + + for i, test := range tests { + errs := validate.Field(test.param, "unix_addr") + if test.expected == true { + if !IsEqual(errs, nil) { + t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) + } + } else { + if IsEqual(errs, nil) { + t.Log(test.param, IsEqual(errs, nil)) + t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) + } else { + val := errs.(ValidationErrors)[""] + if val.Tag != "unix_addr" { + t.Fatalf("Index: %d unix_addr failed Error: %s", i, errs) + } + } + } + } +} + func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing.T) { var m map[string]string