|
|
@@ -12,12 +12,9 @@ import (
|
|
|
|
|
|
/* validation errors */
|
|
|
var (
|
|
|
- EInvalidInteger = errors.New("not a valid integer value")
|
|
|
- EInvalidFloat = errors.New("not a valid float value")
|
|
|
- ERequired = errors.New("this field is required")
|
|
|
- EInvalidEmail = errors.New("invalid email address")
|
|
|
- EInvalidDomain = errors.New("invalid domain name")
|
|
|
- EInvalidDomainTLD = errors.New("invalid domain TLD")
|
|
|
+ EInvalidInteger = errors.New("not a valid integer value")
|
|
|
+ EInvalidFloat = errors.New("not a valid float value")
|
|
|
+ ERequired = errors.New("this field is required")
|
|
|
)
|
|
|
|
|
|
/* A globaly defined set with valid domain TLDs */
|
|
|
@@ -65,13 +62,12 @@ func ValidLettersGeneric(Letters string, Error error) ValidatorFunc {
|
|
|
return Callback
|
|
|
}
|
|
|
|
|
|
-/* ValidLength makes sure that a string length is between specified min and max values. */
|
|
|
-func ValidLength(min, max int) ValidatorFunc {
|
|
|
- var ELength = errors.New(
|
|
|
- fmt.Sprintf("must be a string between %d and %d characters in length", min, max))
|
|
|
+/* ValidLength makes sure that a string length is between specified vMin and vMax values. */
|
|
|
+func ValidLength(vMin, vMax int, err error) ValidatorFunc {
|
|
|
+ ELength := fmt.Errorf("must be a string between %d and %d characters in length", vMin, vMax)
|
|
|
return func(field *FormField, ctx context.Context) error {
|
|
|
- if len(field.GetString()) != 0 && (len(field.GetString()) < min || len(field.GetString()) > max) {
|
|
|
- return ELength
|
|
|
+ if len(field.GetString()) != 0 && (len(field.GetString()) < vMin || len(field.GetString()) > vMax) {
|
|
|
+ return fallbackError(err, ELength)
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
@@ -146,79 +142,117 @@ func ValidBetweenFloat(min, max float64) ValidatorFunc {
|
|
|
}
|
|
|
|
|
|
/* ValidFieldEqualTo is a validator that checks if two fields have the same value. */
|
|
|
-func ValidFieldEqualTo(Other *FormField, err error) ValidatorFunc {
|
|
|
+func ValidFieldEqualTo(other *FormField, err error) ValidatorFunc {
|
|
|
+ defaultErr := errors.New("The text field must match other field's text exactly")
|
|
|
return func(field *FormField, ctx context.Context) error {
|
|
|
- if field.GetString() != Other.GetString() {
|
|
|
- return err
|
|
|
+ if field.GetString() != other.GetString() {
|
|
|
+ return fallbackError(err, defaultErr)
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* validDomainNameStr performs checks if the domain name stored in *FormField is valid */
|
|
|
-func validDomainNameStr(domain string) error {
|
|
|
- domain = strings.ToLower(strings.TrimSpace(domain))
|
|
|
- domainLen := len(domain)
|
|
|
- /* common domain name checks */
|
|
|
- if domainLen == 0 || domainLen > 253 || strings.ContainsAny(domain, " \t\r\n") {
|
|
|
- return EInvalidDomain
|
|
|
- }
|
|
|
- if domain[0] == '.' || domain[domainLen-1] == '.' {
|
|
|
- return EInvalidDomain
|
|
|
- }
|
|
|
- /* make sure domain name only contains allowed letters */
|
|
|
- for _, r := range domain {
|
|
|
- if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '.' || r == '-' {
|
|
|
- continue
|
|
|
+/* ValidExct checks if text field has exact value */
|
|
|
+func ValidExact(text string, err error) ValidatorFunc {
|
|
|
+ defaultErr := fmt.Errorf("The the text field must be exactly '%s'", text)
|
|
|
+ return func(field *FormField, ctx context.Context) error {
|
|
|
+ if field.GetString() != text {
|
|
|
+ return fallbackError(err, defaultErr)
|
|
|
}
|
|
|
- return EInvalidDomain
|
|
|
- }
|
|
|
- /* split to levels (tld, domain[, subdomain...] */
|
|
|
- levels := strings.Split(domain, ".")
|
|
|
- levelsLen := len(levels)
|
|
|
- if levelsLen < 2 {
|
|
|
- return EInvalidDomain
|
|
|
+ return nil
|
|
|
}
|
|
|
- /* perform common checks on levels */
|
|
|
- for _, level := range levels {
|
|
|
- levelLen := len(level)
|
|
|
- if levelLen == 0 || levelLen > 63 {
|
|
|
- return EInvalidDomain
|
|
|
+}
|
|
|
+
|
|
|
+/* validDomainNameStr performs checks if the domain name stored in *FormField is valid */
|
|
|
+func validDomainNameStr(err error) func(string) error {
|
|
|
+ EInvalidDomain := errors.New("invalid domain name")
|
|
|
+ return func(domain string) error {
|
|
|
+ domain = strings.ToLower(strings.TrimSpace(domain))
|
|
|
+ domainLen := len(domain)
|
|
|
+ /* common domain name checks */
|
|
|
+ if domainLen == 0 || domainLen > 253 || strings.ContainsAny(domain, " \t\r\n") {
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
+ }
|
|
|
+ if domain[0] == '.' || domain[domainLen-1] == '.' {
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
}
|
|
|
- if level[0] == '-' || level[levelLen-1] == '-' {
|
|
|
- return EInvalidDomain
|
|
|
+ /* make sure domain name only contains allowed letters */
|
|
|
+ for _, r := range domain {
|
|
|
+ if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '.' || r == '-' {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
}
|
|
|
+ /* split to levels (tld, domain[, subdomain...] */
|
|
|
+ levels := strings.Split(domain, ".")
|
|
|
+ levelsLen := len(levels)
|
|
|
+ if levelsLen < 2 {
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
+ }
|
|
|
+ /* perform common checks on levels */
|
|
|
+ for _, level := range levels {
|
|
|
+ levelLen := len(level)
|
|
|
+ if levelLen == 0 || levelLen > 63 {
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
+ }
|
|
|
+ if level[0] == '-' || level[levelLen-1] == '-' {
|
|
|
+ return fallbackError(err, EInvalidDomain)
|
|
|
+ }
|
|
|
|
|
|
+ }
|
|
|
+ return nil
|
|
|
}
|
|
|
- /* make sure tld has proper size and is whitelisted */
|
|
|
- domainTLD := levels[len(levels)-1]
|
|
|
- if len(domainTLD) < 2 {
|
|
|
- return EInvalidDomainTLD
|
|
|
+}
|
|
|
+
|
|
|
+/* ValidDomainName performs basic domain name checks */
|
|
|
+func ValidDomainName(err error) ValidatorFunc {
|
|
|
+ callbackCheck := validDomainNameStr(err)
|
|
|
+ /* domain name checks */
|
|
|
+ return func(field *FormField, ctx context.Context) error {
|
|
|
+ return callbackCheck(field.GetString())
|
|
|
}
|
|
|
- if _, ok := validTLDs[domainTLD]; !ok {
|
|
|
- return EInvalidDomainTLD
|
|
|
+}
|
|
|
+
|
|
|
+/* ValidDomainNameTLD checks if a field in a domain name has a whitelisted TLD */
|
|
|
+func ValidDomainNameTLD(err error) ValidatorFunc {
|
|
|
+ EInvalidDomainTLD := errors.New("invalid domain TLD")
|
|
|
+ return func(field *FormField, ctx context.Context) error {
|
|
|
+ /* make sure tld has proper size and is whitelisted */
|
|
|
+ domain := strings.ToLower(strings.TrimSpace(field.GetString()))
|
|
|
+ levels := strings.Split(domain, ".")
|
|
|
+ domainTLD := levels[len(levels)-1]
|
|
|
+ if len(domainTLD) < 2 {
|
|
|
+ return fallbackError(err, EInvalidDomainTLD)
|
|
|
+ }
|
|
|
+ if _, ok := validTLDs[domainTLD]; !ok {
|
|
|
+ return fallbackError(err, EInvalidDomainTLD)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
}
|
|
|
- return nil
|
|
|
}
|
|
|
|
|
|
/* ValidEmail checks if field contains a valid email address */
|
|
|
-func ValidEmail(field *FormField, ctx context.Context) error {
|
|
|
- /* sanitize input */
|
|
|
- addrStr := strings.TrimSpace(field.GetString())
|
|
|
- if addrStr == "" || !utf8.ValidString(addrStr) || strings.ContainsAny(addrStr, " \t\r\n") {
|
|
|
- return EInvalidEmail
|
|
|
- }
|
|
|
- /* use mail.ParseAddress on the sanitized text */
|
|
|
- addr, err := mail.ParseAddress(addrStr)
|
|
|
- if err != nil || addr.Address != addrStr {
|
|
|
- return EInvalidEmail
|
|
|
- }
|
|
|
- /* make sure email address has a valid domain name */
|
|
|
- parts := strings.Split(addrStr, "@")
|
|
|
- if err := validDomainNameStr(parts[len(parts)-1]); err != nil {
|
|
|
- return EInvalidEmail
|
|
|
+func ValidEmail(err error) ValidatorFunc {
|
|
|
+ EInvalidEmail := errors.New("invalid email address")
|
|
|
+ domainValidator := validDomainNameStr(nil)
|
|
|
+ return func(field *FormField, ctx context.Context) error {
|
|
|
+ /* sanitize input */
|
|
|
+ addrStr := strings.TrimSpace(field.GetString())
|
|
|
+ if addrStr == "" || !utf8.ValidString(addrStr) || strings.ContainsAny(addrStr, " \t\r\n") {
|
|
|
+ return fallbackError(err, EInvalidEmail)
|
|
|
+ }
|
|
|
+ /* use mail.ParseAddress on the sanitized text */
|
|
|
+ addr, err := mail.ParseAddress(addrStr)
|
|
|
+ if err != nil || addr.Address != addrStr {
|
|
|
+ return fallbackError(err, EInvalidEmail)
|
|
|
+ }
|
|
|
+ /* make sure email address has a valid domain name */
|
|
|
+ domain := strings.SplitN(addrStr, "@", 2)[1]
|
|
|
+ if err := domainValidator(domain); err != nil {
|
|
|
+ return fallbackError(err, EInvalidEmail)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
}
|
|
|
- return nil
|
|
|
}
|
|
|
|
|
|
/* ValidCSRF checks if CSRF token is valid */
|