From 8614f8768b7fc0d7032e9befb425c185ace24171 Mon Sep 17 00:00:00 2001 From: Stavros Date: Sun, 23 Aug 2026 00:58:11 +0300 Subject: [PATCH] fix: no need for idna conversion in domain validator --- internal/utils/app_utils.go | 11 +++++- internal/utils/app_utils_test.go | 9 ++++- pkg/validators/domain_validator.go | 18 ++-------- pkg/validators/domain_validator_test.go | 48 ------------------------- 4 files changed, 20 insertions(+), 66 deletions(-) diff --git a/internal/utils/app_utils.go b/internal/utils/app_utils.go index 3bc3546a..7c168423 100644 --- a/internal/utils/app_utils.go +++ b/internal/utils/app_utils.go @@ -38,7 +38,16 @@ func SafeParseAppURL(str string) (string, error) { return "", fmt.Errorf("ip addresses not allowed") } - hostname, err = idna.Lookup.ToASCII(hostname) + i := idna.New( + idna.MapForLookup(), + idna.Transitional(false), + idna.BidiRule(), + idna.StrictDomainName(false), + idna.CheckHyphens(true), + idna.CheckJoiners(false), + ) + + hostname, err = i.ToASCII(hostname) if err != nil { return "", fmt.Errorf("failed to convert hostname to ascii: %w", err) diff --git a/internal/utils/app_utils_test.go b/internal/utils/app_utils_test.go index 8c9e9bc5..6dbe4492 100644 --- a/internal/utils/app_utils_test.go +++ b/internal/utils/app_utils_test.go @@ -43,6 +43,13 @@ func TestSafeParseAPPURL(t *testing.T) { assert.NoError(t, err) assert.Equal(t, expected, result) + // Underscores + appURL = "http://sub_tinyauth.app" + expected = "http://sub_tinyauth.app" + result, err = utils.SafeParseAppURL(appURL) + assert.NoError(t, err) + assert.Equal(t, expected, result) + // Lowercase appURL = "HTTP://SUb.tinyAUth.aPP" expected = "http://sub.tinyauth.app" @@ -66,7 +73,7 @@ func TestSafeParseAPPURL(t *testing.T) { assert.ErrorContains(t, err, "invalid url") // Invalid punycode - appURL = "http://ab--cd.example.com" + appURL = "http://xn--h-kva.example.com" _, err = utils.SafeParseAppURL(appURL) assert.ErrorContains(t, err, "failed to convert hostname to ascii") diff --git a/pkg/validators/domain_validator.go b/pkg/validators/domain_validator.go index 612c52ae..cf2ce57c 100644 --- a/pkg/validators/domain_validator.go +++ b/pkg/validators/domain_validator.go @@ -11,8 +11,6 @@ import ( "net" "net/url" "strings" - - "golang.org/x/net/idna" ) // Errors @@ -114,23 +112,11 @@ func (v *DomainValidator) getURL(i string) (*url.URL, error) { } func (v *DomainValidator) getHostname(hostname string) (string, error) { - hostname = strings.ToLower(hostname) - hostname = strings.TrimSuffix(hostname, ".") if net.ParseIP(hostname) != nil { return "", fmt.Errorf("ip addresses are not supported") } - i := idna.New( - idna.MapForLookup(), - idna.Transitional(false), - idna.BidiRule(), - idna.StrictDomainName(false), - idna.CheckHyphens(false), - idna.CheckJoiners(false), - ) - hostname, err := i.ToASCII(hostname) - if err != nil { - return "", fmt.Errorf("failed to convert hostname to ascii: %w", err) - } + hostname = strings.ToLower(hostname) + hostname = strings.TrimSuffix(hostname, ".") return hostname, nil } diff --git a/pkg/validators/domain_validator_test.go b/pkg/validators/domain_validator_test.go index 0b3b81e1..b47c52ec 100644 --- a/pkg/validators/domain_validator_test.go +++ b/pkg/validators/domain_validator_test.go @@ -50,16 +50,6 @@ func TestDomainValidator_SafeHostname(t *testing.T) { input: "https://example.com", expected: "example.com", }, - { - description: "Domain with underscores should pass", - input: "https://my_domain.com", - expected: "my_domain.com", - }, - { - description: "Domain with leading hyphen should pass", - input: "https://-my-domain.com", - expected: "-my-domain.com", - }, { description: "Domain without scheme should parse if scheme is disabled", input: "example.com", @@ -111,18 +101,6 @@ func TestDomainValidator_SafeHostname(t *testing.T) { assert.ErrorContains(t, e, "ip addresses are not supported") }, }, - { - description: "Domains with unicode characters should be allowed", - input: "bücher.example.com", - expected: "xn--bcher-kva.example.com", - }, - { - description: "Invalid IDNA domain should fail", - input: "xn--r-kva.example.com", - errorFunc: func(t *testing.T, e error) { - assert.ErrorContains(t, e, "invalid label") - }, - }, { description: "With port enabled without any port should work", options: DomainValidatorOptions{WithPort: true}, @@ -204,22 +182,6 @@ func TestDomainValidator_Validate(t *testing.T) { expected: "https://example.com:443", actual: "https://example.com:443", }, - { - description: "Failure to format expected domain should fail", - expected: "xn--r-kva.example.com", - actual: "example.com", - errorFunc: func(t *testing.T, e error) { - assert.ErrorContains(t, e, "idna: invalid label") - }, - }, - { - description: "Failure to format check domain should fail", - expected: "example.com", - actual: "xn--r-kva.example.com", - errorFunc: func(t *testing.T, e error) { - assert.ErrorContains(t, e, "idna: invalid label") - }, - }, { description: "Valid domains with matching schemes and ports should pass", options: DomainValidatorOptions{WithScheme: true, AllowedSchemes: []string{"https", "http"}, WithPort: true}, @@ -246,16 +208,6 @@ func TestDomainValidator_Validate(t *testing.T) { actual: "example.com", expected: "example.com", }, - { - description: "Unicode valid domains should pass", - expected: "xn--bcher-kva.example.com", - actual: "bücher.example.com", - }, - { - description: "Unicode valid domains should pass (reverse)", - expected: "bücher.example.com", - actual: "xn--bcher-kva.example.com", - }, { description: "Non matching hostnames should fail", expected: "example.com",