From cca1f723be42f397af1be7be4c79992f52782922 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Thu, 28 Nov 2024 09:29:39 +0800 Subject: [PATCH 1/2] fix: Add validation domain function Signed-off-by: Alan Tang --- pkg/utils/helper.go | 37 +++++++++++++++++++++++++++++++++++++ pkg/views/login/create.go | 8 ++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/pkg/utils/helper.go b/pkg/utils/helper.go index ba11029e..c068a2ec 100644 --- a/pkg/utils/helper.go +++ b/pkg/utils/helper.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" "time" + "unicode" ) func FormatCreatedTime(timestamp string) (string, error) { @@ -39,6 +40,42 @@ func FormatUrl(url string) string { return url } +// ValidateDomain checks if the given domain string is non-empty, properly formatted, and a valid domain. +func FormatToValidDomain(input string) (string, error) { + parts := strings.Split(input, ".") + if len(parts) != 3 { + return "", fmt.Errorf("invalid server address input, must be in the format: subdomain.example.tld") + } + + for _, part := range parts { + if !isValidLabel(part) { + return "", fmt.Errorf("invalid domain label: %s", part) + } + } + + return strings.Join(parts, "."), nil +} + +// isValidLabel checks if a domain label is valid according to DNS rules +func isValidLabel(label string) bool { + if len(label) == 0 || len(label) > 63 { + return false + } + trimedLabel := strings.TrimSpace(label) + if len(trimedLabel) != len(label) { + return false + } + for _, ch := range label { + if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '-' { + return false + } + } + if label[0] == '-' || label[len(label)-1] == '-' { + return false + } + return true +} + func FormatSize(size int64) string { mbSize := float64(size) / (1024 * 1024) return fmt.Sprintf("%.2fMiB", mbSize) diff --git a/pkg/views/login/create.go b/pkg/views/login/create.go index ad653521..706d34b0 100644 --- a/pkg/views/login/create.go +++ b/pkg/views/login/create.go @@ -3,7 +3,6 @@ package login import ( "errors" "fmt" - "net/url" "strings" "github.com/charmbracelet/huh" @@ -32,10 +31,11 @@ func CreateView(loginView *LoginView) { if strings.TrimSpace(str) == "" { return errors.New("server cannot be empty or only spaces") } - formattedUrl := utils.FormatUrl(str) - if _, err := url.ParseRequestURI(formattedUrl); err != nil { - return errors.New("please enter the correct server format") + _, err := utils.FormatToValidDomain(str) + if err != nil { + return err } + return nil }), huh.NewInput(). From 250d6f87e07f3c560b5646217c814ee2a8b2beb2 Mon Sep 17 00:00:00 2001 From: Alan Tang Date: Wed, 4 Dec 2024 09:58:34 +0800 Subject: [PATCH 2/2] enhance: check the subdomain with port, IP and top level domain Signed-off-by: Alan Tang --- pkg/utils/helper.go | 53 ++++++++++++++++++++++++++------------- pkg/views/login/create.go | 2 +- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/pkg/utils/helper.go b/pkg/utils/helper.go index c068a2ec..7919e2fd 100644 --- a/pkg/utils/helper.go +++ b/pkg/utils/helper.go @@ -3,11 +3,11 @@ package utils import ( "errors" "fmt" + "net" "regexp" "strconv" "strings" "time" - "unicode" ) func FormatCreatedTime(timestamp string) (string, error) { @@ -40,38 +40,55 @@ func FormatUrl(url string) string { return url } -// ValidateDomain checks if the given domain string is non-empty, properly formatted, and a valid domain. -func FormatToValidDomain(input string) (string, error) { - parts := strings.Split(input, ".") - if len(parts) != 3 { - return "", fmt.Errorf("invalid server address input, must be in the format: subdomain.example.tld") +// ValidateDomain validates subdomain, IP, or top-level domain formats +func ValidateDomain(domain string) error { + if strings.Contains(domain, ":") { + parts := strings.Split(domain, ":") + if len(parts) != 2 { + return errors.New("invalid domain format: too many colons") + } + port, err := strconv.Atoi(parts[1]) + if err != nil || port < 0 || port > 65535 { + return errors.New("invalid port number") + } + domain = parts[0] + } + + if net.ParseIP(domain) != nil { + return nil + } + + parts := strings.Split(domain, ".") + if len(parts) < 2 { + return errors.New("invalid domain: must have at least one dot") } for _, part := range parts { if !isValidLabel(part) { - return "", fmt.Errorf("invalid domain label: %s", part) + return fmt.Errorf("invalid domain label: %s", part) } } - return strings.Join(parts, "."), nil + if len(parts[len(parts)-1]) < 2 { + return errors.New("invalid top-level domain: must be at least 2 characters") + } + + return nil } -// isValidLabel checks if a domain label is valid according to DNS rules +// Helper function to validate individual domain labels func isValidLabel(label string) bool { if len(label) == 0 || len(label) > 63 { return false } - trimedLabel := strings.TrimSpace(label) - if len(trimedLabel) != len(label) { - return false - } - for _, ch := range label { - if !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '-' { + + for i, ch := range label { + if !(ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-') { + return false + } + if (i == 0 || i == len(label)-1) && ch == '-' { return false } - } - if label[0] == '-' || label[len(label)-1] == '-' { - return false } return true } diff --git a/pkg/views/login/create.go b/pkg/views/login/create.go index 706d34b0..17bb9c90 100644 --- a/pkg/views/login/create.go +++ b/pkg/views/login/create.go @@ -31,7 +31,7 @@ func CreateView(loginView *LoginView) { if strings.TrimSpace(str) == "" { return errors.New("server cannot be empty or only spaces") } - _, err := utils.FormatToValidDomain(str) + err := utils.ValidateDomain(str) if err != nil { return err }