[server] Improve support for idn domains (#7124)
## Description ## Tests
This commit is contained in:
@@ -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 idn domain format: %s", trimmed))
|
||||
}
|
||||
|
||||
// Validate the ASCII version
|
||||
if !domainRegex.MatchString(asciiDomain) {
|
||||
return NewBadRequestWithMessage(fmt.Sprintf("invalid domain format: %s", trimmed))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"golang.org/x/net/idna"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -220,11 +221,26 @@ 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, err := idna.ToUnicode(*domain)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("domainToUnicodeFailed")
|
||||
m.DiscordController.NotifyPotentialAbuse(alertMessage + " - domainToUnicodeFailed")
|
||||
return nil
|
||||
}
|
||||
|
||||
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")
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user