From dbbe37bb7b235021819119db5445b78dc663d251 Mon Sep 17 00:00:00 2001 From: mrz1836 Date: Wed, 8 Apr 2020 17:29:56 -0400 Subject: [PATCH] Added more useful validations for IP and DNS --- extra_validations.go | 48 ++++++++- extra_validations_test.go | 200 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 4 deletions(-) diff --git a/extra_validations.go b/extra_validations.go index c1f210f..ae911ef 100644 --- a/extra_validations.go +++ b/extra_validations.go @@ -7,6 +7,11 @@ import ( "strings" ) +const ( + // socialBasicRawRegex social Security number regex for validation + socialBasicRawRegex = `^\d{3}-\d{2}-\d{4}$` +) + var ( // blacklistedSocials known blacklisted socials (exclude automatically) @@ -43,6 +48,7 @@ var ( "aol.con", // Does not exist, but valid TLD in regex "example.com", // Invalid domain - used for testing but should not work in production "gmail.con", // Does not exist, but valid TLD in regex + "gnail.com", // Does not exist, but valid TLD in regex "hotmail.con", // Does not exist, but valid TLD in regex "yahoo.con", // Does not exist, but valid TLD in regex } @@ -53,11 +59,9 @@ var ( "52", // Mexico // todo: support more countries in phone number validation (@mrz) } -) -const ( - // socialBasicRawRegex social Security number regex for validation - socialBasicRawRegex = `^\d{3}-\d{2}-\d{4}$` + // dnsRegEx is the regex for a DNS name + dnsRegEx = regexp.MustCompile(`^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[._]?$`) ) // IsValidEnum validates an enum given the required parameters and tests if the supplied value is valid from accepted values @@ -129,6 +133,12 @@ func IsValidEmail(email string, mxCheck bool) (success bool, err error) { return } + // Validate the host + if ok := IsValidHost(host); !ok { + err = fmt.Errorf("email domain is not a valid host") + return + } + // Check for mx record or A record if mxCheck { if _, err = net.LookupMX(host); err != nil { @@ -308,3 +318,33 @@ func IsValidPhoneNumber(phone string, countryCode string) (success bool, err err success = true return } + +// IsValidHost checks if the string is a valid IP (both v4 and v6) or a valid DNS name +func IsValidHost(host string) bool { + return IsValidIP(host) || IsValidDNSName(host) +} + +// IsValidIP checks if a string is either IP version 4 or 6. Alias for `net.ParseIP` +func IsValidIP(ipAddress string) bool { + return net.ParseIP(ipAddress) != nil +} + +// IsValidIPv4 check if the string is an IP version 4. +func IsValidIPv4(ipAddress string) bool { + ip := net.ParseIP(ipAddress) + return ip != nil && strings.Contains(ipAddress, ".") +} + +// IsValidIPv6 check if the string is an IP version 6. +func IsValidIPv6(ipAddress string) bool { + ip := net.ParseIP(ipAddress) + return ip != nil && strings.Contains(ipAddress, ":") +} + +// IsValidDNSName will validate the given string as a DNS name +func IsValidDNSName(dnsName string) bool { + if dnsName == "" || len(strings.Replace(dnsName, ".", "", -1)) > 255 { + return false + } + return !IsValidIP(dnsName) && dnsRegEx.MatchString(dnsName) +} diff --git a/extra_validations_test.go b/extra_validations_test.go index 6f45e9a..1ce8347 100644 --- a/extra_validations_test.go +++ b/extra_validations_test.go @@ -634,3 +634,203 @@ func BenchmarkIsValidPhoneNumber(b *testing.B) { _, _ = IsValidPhoneNumber(phone, countryCode) } } + +// TestIsValidDNSName testing the dns name +func TestIsValidDNSName(t *testing.T) { + t.Parallel() + + var tests = []struct { + param string + expected bool + }{ + {"localhost", true}, + {"a.bc", true}, + {"a.b.", true}, + {"a.b..", false}, + {"localhost.local", true}, + {"localhost.localdomain.intern", true}, + {"l.local.intern", true}, + {"ru.link.n.svpncloud.com", true}, + {"-localhost", false}, + {"localhost.-localdomain", false}, + {"localhost.localdomain.-int", false}, + {"_localhost", true}, + {"localhost._localdomain", true}, + {"localhost.localdomain._int", true}, + {"lÖcalhost", false}, + {"localhost.lÖcaldomain", false}, + {"localhost.localdomain.üntern", false}, + {"__", true}, + {"localhost/", false}, + {"127.0.0.1", false}, + {"[::1]", false}, + {"50.50.50.50", false}, + {"localhost.localdomain.intern:65535", false}, + {"漢字汉字", false}, + {"www.jubfvq1v3p38i51622y0dvmdk1mymowjyeu26gbtw9andgynj1gg8z3msb1kl5z6906k846pj3sulm4kiyk82ln5teqj9nsht59opr0cs5ssltx78lfyvml19lfq1wp4usbl0o36cmiykch1vywbttcus1p9yu0669h8fj4ll7a6bmop505908s1m83q2ec2qr9nbvql2589adma3xsq2o38os2z3dmfh2tth4is4ixyfasasasefqwe4t2ub2fz1rme.de", false}, + } + + for _, test := range tests { + actual := IsValidDNSName(test.param) + if actual != test.expected { + t.Errorf("Expected IsValidDNSName(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +// ExampleIsValidDNSName_invalid example of an invalid dns name +func ExampleIsValidDNSName_invalid() { + ok := IsValidDNSName("localhost.-localdomain") + fmt.Println(ok) + // Output: false +} + +// ExampleIsValidDNSName_valid example of a valid dns name +func ExampleIsValidDNSName_valid() { + ok := IsValidDNSName("localhost") + fmt.Println(ok) + // Output: true +} + +// BenchmarkIsValidDNSName benchmarks the IsValidDNSName (valid value) +func BenchmarkIsValidDNSName(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = IsValidDNSName("localhost") + } +} + +// TestIsValidIP will test IPv4 and IPv6 +func TestIsValidIP(t *testing.T) { + t.Parallel() + + // Without version + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"0.0.0.0", true}, + {"255.255.255.255", true}, + {"1.2.3.4", true}, + {"::1", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsValidIP(test.param) + if actual != test.expected { + t.Errorf("Expected IsValidIP(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // IPv4 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"0.0.0.0", true}, + {"255.255.255.255", true}, + {"1.2.3.4", true}, + {"::1", false}, + {"2001:db8:0000:1:1:1:1:1", false}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsValidIPv4(test.param) + if actual != test.expected { + t.Errorf("Expected IsValidIPv4(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + + // IPv6 + tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", false}, + {"0.0.0.0", false}, + {"255.255.255.255", false}, + {"1.2.3.4", false}, + {"::1", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsValidIPv6(test.param) + if actual != test.expected { + t.Errorf("Expected IsValidIPv6(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +} + +// ExampleIsValidIP_invalid example of an invalid ip address +func ExampleIsValidIP_invalid() { + ok := IsValidIP("300.0.0.0") + fmt.Println(ok) + // Output: false +} + +// ExampleIsValidIP_valid example of a valid ip address +func ExampleIsValidIP_valid() { + ok := IsValidIP("127.0.0.1") + fmt.Println(ok) + // Output: true +} + +// BenchmarkIsValidIP benchmarks the IsValidIP (valid value) +func BenchmarkIsValidIP(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = IsValidIP("127.0.0.1") + } +} + +// TestIsValidHost will test a hostname +func TestIsValidHost(t *testing.T) { + t.Parallel() + var tests = []struct { + param string + expected bool + }{ + {"localhost", true}, + {"localhost.localdomain", true}, + {"2001:db8:0000:1:1:1:1:1", true}, + {"::1", true}, + {"play.golang.org", true}, + {"localhost.localdomain.intern:65535", false}, + {"-[::1]", false}, + {"-localhost", false}, + {".localhost", false}, + } + for _, test := range tests { + actual := IsValidHost(test.param) + if actual != test.expected { + t.Errorf("Expected IsValidHost(%q) to be %v, got %v", test.param, test.expected, actual) + } + } + +} + +// ExampleIsValidHost_invalid example of an invalid host +func ExampleIsValidHost_invalid() { + ok := IsValidHost("-localhost") + fmt.Println(ok) + // Output: false +} + +// ExampleIsValidHost_valid example of a valid host +func ExampleIsValidHost_valid() { + ok := IsValidHost("localhost") + fmt.Println(ok) + // Output: true +} + +// BenchmarkIsValidHost benchmarks the IsValidHost (valid value) +func BenchmarkIsValidHost(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = IsValidHost("localhost") + } +}