Skip to content

Commit

Permalink
Added more useful validations for IP and DNS
Browse files Browse the repository at this point in the history
  • Loading branch information
mrz1836 committed Apr 8, 2020
1 parent 5f57186 commit dbbe37b
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 4 deletions.
48 changes: 44 additions & 4 deletions extra_validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
200 changes: 200 additions & 0 deletions extra_validations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

0 comments on commit dbbe37b

Please sign in to comment.