Merge pull request #563 from terala/master

Add hostname_port validator feature
pull/575/head
Dean Karn 5 years ago committed by GitHub
commit 68e8e137fa
  1. 20
      baked_in.go
  2. 7
      doc.go
  3. 10
      regexes.go
  4. 37
      validator_test.go

@ -166,6 +166,7 @@ var (
"html_encoded": isHTMLEncoded, "html_encoded": isHTMLEncoded,
"url_encoded": isURLEncoded, "url_encoded": isURLEncoded,
"dir": isDir, "dir": isDir,
"hostname_port": isHostnamePort,
"lowercase": isLowercase, "lowercase": isLowercase,
"uppercase": isUppercase, "uppercase": isUppercase,
} }
@ -2010,6 +2011,25 @@ func isDir(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface())) panic(fmt.Sprintf("Bad field type %T", field.Interface()))
} }
// isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
func isHostnamePort(fl FieldLevel) bool {
val := fl.Field().String()
host, port, err := net.SplitHostPort(val)
if err != nil {
return false
}
// Port must be a iny <= 65535.
if portNum, err := strconv.ParseInt(port, 10, 32); err != nil || portNum > 65535 || portNum < 1 {
return false
}
// If host is specified, it should match a DNS name
if host != "" {
return hostnameRegexRFC1123.MatchString(host)
}
return true
}
// isLowercase is the validation function for validating if the current field's value is a lowercase string. // isLowercase is the validation function for validating if the current field's value is a lowercase string.
func isLowercase(fl FieldLevel) bool { func isLowercase(fl FieldLevel) bool {
field := fl.Field() field := fl.Field()

@ -1049,6 +1049,13 @@ This is done using os.Stat, which is a platform independent function.
Usage: dir Usage: dir
HostPort
This validates that a string value contains a valid DNS hostname and port that
can be used to valiate fields typically passed to sockets and connections.
Usage: hostname_port
Alias Validators and Tags Alias Validators and Tags
NOTE: When returning an error, the tag returned in "FieldError" will be NOTE: When returning an error, the tag returned in "FieldError" will be

@ -36,11 +36,11 @@ const (
latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$" latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$" 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])$` 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 hostnameRegexStringRFC952 = `^[a-zA-Z][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // https://tools.ietf.org/html/rfc952
hostnameRegexStringRFC1123 = `^[a-zA-Z0-9][a-zA-Z0-9\-\.]+[a-zA-Z0-9]$` // accepts hostname starting with a digit https://tools.ietf.org/html/rfc1123 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 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 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 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}$` ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
ethAddressUpperRegexString = `^0x[0-9A-F]{40}$` ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
ethAddressLowerRegexString = `^0x[0-9a-f]{40}$` ethAddressLowerRegexString = `^0x[0-9a-f]{40}$`

@ -7954,15 +7954,15 @@ func TestHostnameRFC1123Validation(t *testing.T) {
if test.expected { if test.expected {
if !IsEqual(errs, nil) { if !IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs) t.Fatalf("Hostname: %v failed Error: %v", test, errs)
} }
} else { } else {
if IsEqual(errs, nil) { if IsEqual(errs, nil) {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs) t.Fatalf("Hostname: %v failed Error: %v", test, errs)
} else { } else {
val := getError(errs, "", "") val := getError(errs, "", "")
if val.Tag() != "hostname_rfc1123" { if val.Tag() != "hostname_rfc1123" {
t.Fatalf("Index: %d hostname failed Error: %v", i, errs) t.Fatalf("Hostname: %v failed Error: %v", i, errs)
} }
} }
} }
@ -9004,6 +9004,37 @@ func TestGetTag(t *testing.T) {
Equal(t, tag, "mytag") Equal(t, tag, "mytag")
} }
func Test_hostnameport_validator(t *testing.T) {
type Host struct {
Addr string `validate:"hostname_port"`
}
type testInput struct {
data string
expected bool
}
testData := []testInput{
{"bad..domain.name:234", false},
{"extra.dot.com.", false},
{"localhost:1234", true},
{"192.168.1.1:1234", true},
{":1234", true},
{"domain.com:1334", true},
{"this.domain.com:234", true},
{"domain:75000", false},
{"missing.port", false},
}
for _, td := range testData {
h := Host{Addr: td.data}
v := New()
err := v.Struct(h)
if td.expected != (err == nil) {
t.Fatalf("Test failed for data: %v Error: %v", td.data, err)
}
}
}
func TestLowercaseValidation(t *testing.T) { func TestLowercaseValidation(t *testing.T) {
tests := []struct { tests := []struct {
param string param string

Loading…
Cancel
Save