diff --git a/pkg/validate/validate.go b/pkg/validate/validate.go index 3683941cf..f647d1e17 100644 --- a/pkg/validate/validate.go +++ b/pkg/validate/validate.go @@ -6,62 +6,33 @@ import ( "regexp" "strings" "unicode/utf8" -) -const ( - minURLRuneCount = 3 - maxURLRuneCount = 2083 - - ipPattern = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))` - urlSchemaPattern = `((ftp|tcp|udp|wss?|https?):\/\/)` - urlUsernamePattern = `(\S+(:\S*)?@)` - urlPathPattern = `((\/|\?|#)[^\s]*)` - urlPortPattern = `(:(\d{1,5}))` - urlIPPattern = `([1-9]\d?|1\d\d|2[01]\d|22[0-3]|24\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-5]))` - urlSubdomainPattern = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))` - urlPattern = `^` + urlSchemaPattern + `?` + urlUsernamePattern + `?` + `((` + urlIPPattern + `|(\[` + ipPattern + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + urlSubdomainPattern + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + urlPortPattern + `?` + urlPathPattern + `?$` + "github.com/google/uuid" ) var ( - urlRegex = regexp.MustCompile(urlPattern) - uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) hexadecimalRegex = regexp.MustCompile(`^[0-9a-fA-F]+$`) - whitespaceRegex = regexp.MustCompile(`^[[:space:]]+$`) dnsNameRegex = 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})*[\._]?$`) ) func IsURL(urlString string) bool { - if urlString == "" || - utf8.RuneCountInString(urlString) >= maxURLRuneCount || - len(urlString) <= minURLRuneCount || - strings.HasPrefix(urlString, ".") { + if len(urlString) == 0 { return false } strTemp := urlString - if strings.Contains(urlString, ":") && !strings.Contains(urlString, "://") { - // support no indicated urlscheme but with colon for port number - // http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString + if !strings.Contains(urlString, "://") { + // support no indicated urlscheme + // http:// is appended so url.Parse will succeed strTemp = "http://" + urlString } u, err := url.Parse(strTemp) - if err != nil { - return false - } - - if strings.HasPrefix(u.Host, ".") { - return false - } - if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) { - return false - } - - return urlRegex.MatchString(urlString) + return err == nil && u.Host != "" } func IsUUID(uuidString string) bool { - return uuidRegex.MatchString(uuidString) + return uuid.Validate(uuidString) == nil } func IsHexadecimal(hexString string) bool { @@ -69,7 +40,7 @@ func IsHexadecimal(hexString string) bool { } func HasWhitespaceOnly(s string) bool { - return len(s) > 0 && whitespaceRegex.MatchString(s) + return len(s) > 0 && strings.TrimSpace(s) == "" } func MinStringLength(s string, len int) bool { diff --git a/pkg/validate/validate_test.go b/pkg/validate/validate_test.go index e8b62288e..f3cb6a01c 100644 --- a/pkg/validate/validate_test.go +++ b/pkg/validate/validate_test.go @@ -17,6 +17,11 @@ func Test_IsURL(t *testing.T) { url: "https://google.com", expectedResult: true, }, + { + name: "empty", + url: "", + expectedResult: false, + }, { name: "no schema", url: "google.com", @@ -33,9 +38,14 @@ func Test_IsURL(t *testing.T) { expectedResult: true, }, { - name: "invalid", + name: "no top level domain", url: "google", - expectedResult: false, + expectedResult: true, + }, + { + name: "Unicode URL", + url: "www.xn--exampe-7db.ai", + expectedResult: true, }, } @@ -145,6 +155,11 @@ func Test_HasWhitespaceOnly(t *testing.T) { s: "something like this", expectedResult: false, }, + { + name: "all whitespace", + s: "\t\n\v\f\r ", + expectedResult: true, + }, } for _, tc := range testCases {