From 270cee8b0933d7a32fc73acbf96462b612082d4a Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 10 Sep 2025 04:40:27 +0530 Subject: [PATCH 1/3] [server] Support for idn domain --- server/ente/remotestore.go | 12 +++++++++++- server/ente/remotestore_test.go | 2 ++ server/pkg/middleware/collection_link.go | 7 +++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/server/ente/remotestore.go b/server/ente/remotestore.go index ea96d8de1c..c71d40fdf1 100644 --- a/server/ente/remotestore.go +++ b/server/ente/remotestore.go @@ -3,6 +3,7 @@ package ente import ( "fmt" "github.com/ente-io/stacktrace" + "golang.org/x/net/idna" "regexp" "strings" ) @@ -139,8 +140,17 @@ func isValidDomainWithoutScheme(input string) error { if strings.Contains(trimmed, "://") { return NewBadRequestWithMessage("domain should not contain scheme (e.g., http:// or https://)") } - if !domainRegex.MatchString(trimmed) { + + // Convert IDN to ASCII (Punycode) for validation + asciiDomain, err := idna.ToASCII(trimmed) + if err != nil { return NewBadRequestWithMessage(fmt.Sprintf("invalid domain format: %s", trimmed)) } + + // Validate the ASCII version + if !domainRegex.MatchString(asciiDomain) { + return NewBadRequestWithMessage(fmt.Sprintf("invalid domain format: %s", trimmed)) + } + return nil } diff --git a/server/ente/remotestore_test.go b/server/ente/remotestore_test.go index 1056e5ca6b..636df4b40b 100644 --- a/server/ente/remotestore_test.go +++ b/server/ente/remotestore_test.go @@ -11,7 +11,9 @@ func TestIsValidDomainWithoutScheme(t *testing.T) { // ✅ Valid cases {"simple domain", "google.com", false}, {"multi-level domain", "sub.example.co.in", false}, + {"multi-level domain", "photos.ä.com", false}, {"numeric in label", "a1b2c3.com", false}, + {"idn", "テスト.jp", false}, {"long but valid label", "my-very-long-subdomain-name.example.com", false}, // ❌ Leading/trailing spaces diff --git a/server/pkg/middleware/collection_link.go b/server/pkg/middleware/collection_link.go index 71f9a9e69b..31916b90f0 100644 --- a/server/pkg/middleware/collection_link.go +++ b/server/pkg/middleware/collection_link.go @@ -5,6 +5,7 @@ import ( "context" "crypto/sha256" "fmt" + "golang.org/x/net/idna" "net/http" "net/url" "strings" @@ -220,8 +221,10 @@ func (m *CollectionLinkMiddleware) validateOrigin(c *gin.Context, ownerID int64) m.DiscordController.NotifyPotentialAbuse(alertMessage + " - originParseFailed") return nil } - if !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(*domain)) { - logger.Warnf("domainMismatch for owner %d, origin %s, domain %s host %s", ownerID, origin, *domain, parse.Host) + + unicodeDomain, _ := idna.ToUnicode(*domain) + if !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(*domain)) && !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(unicodeDomain)) { + logger.Warnf("domainMismatch for owner domain %s (unicode %s) vs host %s", *domain, unicodeDomain, parse.Host) m.DiscordController.NotifyPotentialAbuse(alertMessage + " - domainMismatch") return ente.NewPermissionDeniedError("unknown custom domain") } From d3c53794cf3a16802ae12bbdcde8c8b2fc264b17 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 10 Sep 2025 04:52:20 +0530 Subject: [PATCH 2/3] Add alert for exactDomain mismatch --- server/pkg/middleware/collection_link.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/pkg/middleware/collection_link.go b/server/pkg/middleware/collection_link.go index 31916b90f0..55441d5fd7 100644 --- a/server/pkg/middleware/collection_link.go +++ b/server/pkg/middleware/collection_link.go @@ -224,10 +224,18 @@ func (m *CollectionLinkMiddleware) validateOrigin(c *gin.Context, ownerID int64) unicodeDomain, _ := idna.ToUnicode(*domain) if !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(*domain)) && !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(unicodeDomain)) { - logger.Warnf("domainMismatch for owner domain %s (unicode %s) vs host %s", *domain, unicodeDomain, parse.Host) + logger.Warnf("domainMismatch: domain %s (unicode %s) vs originHost %s", *domain, unicodeDomain, parse.Host) m.DiscordController.NotifyPotentialAbuse(alertMessage + " - domainMismatch") return ente.NewPermissionDeniedError("unknown custom domain") } + // Additional exact match check. In the future, remove the contains check above and only keep this exact match check. + if !strings.EqualFold(parse.Host, *domain) && !strings.EqualFold(parse.Host, unicodeDomain) { + logger.Warnf("exactDomainMismatch: domain %s (unicode %s) vs originHost %s", *domain, unicodeDomain, parse.Host) + m.DiscordController.NotifyPotentialAbuse(alertMessage + " - exactDomainMismatch") + // Do not return error here till we are fully sure that this won't cause any issues for existing + // custom domains. + // return ente.NewPermissionDeniedError("unknown custom domain") + } return nil } From 135124a48770f9f0d80fe3ded31b993e70983865 Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 10 Sep 2025 05:01:40 +0530 Subject: [PATCH 3/3] Improve err handling --- server/ente/remotestore.go | 2 +- server/pkg/middleware/collection_link.go | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/server/ente/remotestore.go b/server/ente/remotestore.go index c71d40fdf1..d4468c04d6 100644 --- a/server/ente/remotestore.go +++ b/server/ente/remotestore.go @@ -144,7 +144,7 @@ func isValidDomainWithoutScheme(input string) error { // Convert IDN to ASCII (Punycode) for validation asciiDomain, err := idna.ToASCII(trimmed) if err != nil { - return NewBadRequestWithMessage(fmt.Sprintf("invalid domain format: %s", trimmed)) + return NewBadRequestWithMessage(fmt.Sprintf("invalid idn domain format: %s", trimmed)) } // Validate the ASCII version diff --git a/server/pkg/middleware/collection_link.go b/server/pkg/middleware/collection_link.go index 55441d5fd7..c80cb8e9c5 100644 --- a/server/pkg/middleware/collection_link.go +++ b/server/pkg/middleware/collection_link.go @@ -221,8 +221,13 @@ func (m *CollectionLinkMiddleware) validateOrigin(c *gin.Context, ownerID int64) m.DiscordController.NotifyPotentialAbuse(alertMessage + " - originParseFailed") return nil } + unicodeDomain, err := idna.ToUnicode(*domain) + if err != nil { + logger.WithError(err).Error("domainToUnicodeFailed") + m.DiscordController.NotifyPotentialAbuse(alertMessage + " - domainToUnicodeFailed") + return nil + } - unicodeDomain, _ := idna.ToUnicode(*domain) if !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(*domain)) && !strings.Contains(strings.ToLower(parse.Host), strings.ToLower(unicodeDomain)) { logger.Warnf("domainMismatch: domain %s (unicode %s) vs originHost %s", *domain, unicodeDomain, parse.Host) m.DiscordController.NotifyPotentialAbuse(alertMessage + " - domainMismatch")