Repository: go-playground/validator
Pull request #612 (2020-05-21 00:23:50)

Allow numbers in FQDN validation
Fixes FQDN validation to allow numerical subdomains/hosts #602 

**Make sure that you've checked the boxes below before you submit PR:**
- [x] Tests exist or have been written that cover this particular change.

Change Details:

- Add regex based on hostname RFC1123 adding check for existence of TLD.
- Update `isFQDN` removing checks already done by regex

@go-playground/admins


Patch:
diff --git a/baked_in.go b/baked_in.go
index b504bff..36e8057 100644
--- a/baked_in.go
+++ b/baked_in.go
@@ -2002,12 +2002,7 @@ func isFQDN(fl FieldLevel) bool {
 		return false
 	}
 
-	if val[len(val)-1] == '.' {
-		val = val[0 : len(val)-1]
-	}
-
-	return strings.ContainsAny(val, ".") &&
-		hostnameRegexRFC952.MatchString(val)
+	return fqdnRegexRFC1123.MatchString(val)
 }
 
 // IsDir is the validation function for validating if the current field's value is a valid directory.
diff --git a/regexes.go b/regexes.go
index 466eb80..188d1ad 100644
--- a/regexes.go
+++ b/regexes.go
@@ -36,11 +36,12 @@ const (
 	latitudeRegexString              = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
 	longitudeRegexString             = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
 	sSNRegexString                   = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -]?([1-9][0-9]{3}|[0-9][1-9][0-9]{2}|[0-9]{2}[1-9][0-9]|[0-9]{3}[1-9])$`
-	hostnameRegexStringRFC952        = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`                                      // https://tools.ietf.org/html/rfc952
-	hostnameRegexStringRFC1123       = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
-	btcAddressRegexString            = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`                                                // bitcoin address
-	btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
-	btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+  hostnameRegexStringRFC952        = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA-Z0-9]$`                                                                      // https://tools.ietf.org/html/rfc952
+	hostnameRegexStringRFC1123       = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?$`                                 // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123
+	fqdnRegexStringRFC1123           = `^([a-zA-Z0-9]{1}[a-zA-Z0-9_-]{0,62})(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*?(\.[a-zA-Z]{1}[a-zA-Z0-9]{0,62})\.?$` // same as hostnameRegexStringRFC1123 but must contain a non numerical TLD (possibly ending with '.')
+	btcAddressRegexString            = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`                                                                                // bitcoin address
+	btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`                                                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
+	btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`                                                                                      // bitcoin bech32 address https://en.bitcoin.it/wiki/Bech32
 	ethAddressRegexString            = `^0x[0-9a-fA-F]{40}$`
 	ethAddressUpperRegexString       = `^0x[0-9A-F]{40}$`
 	ethAddressLowerRegexString       = `^0x[0-9a-f]{40}$`
@@ -86,6 +87,7 @@ var (
 	sSNRegex                   = regexp.MustCompile(sSNRegexString)
 	hostnameRegexRFC952        = regexp.MustCompile(hostnameRegexStringRFC952)
 	hostnameRegexRFC1123       = regexp.MustCompile(hostnameRegexStringRFC1123)
+	fqdnRegexRFC1123           = regexp.MustCompile(fqdnRegexStringRFC1123)
 	btcAddressRegex            = regexp.MustCompile(btcAddressRegexString)
 	btcUpperAddressRegexBech32 = regexp.MustCompile(btcAddressUpperRegexStringBech32)
 	btcLowerAddressRegexBech32 = regexp.MustCompile(btcAddressLowerRegexStringBech32)


Test patch:
diff --git a/validator_test.go b/validator_test.go
index 68e8132..e76a3cd 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -8038,6 +8038,8 @@ func TestFQDNValidation(t *testing.T) {
 		{"example24.com.", true},
 		{"test.example24.com.", true},
 		{"test24.example24.com.", true},
+		{"24.example24.com", true},
+		{"test.24.example.com", true},
 		{"test24.example24.com..", false},
 		{"example", false},
 		{"192.168.0.1", false},