diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index b7c08ca..9d4880d 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -4091,8 +4091,11 @@ def _validate_safe_name(name: str) -> bool: return bool(name) and _SAFE_NAME_RE.match(name) is not None -# Hostname characters: letters, digits, hyphens, dots (no underscores in FQDNs) -_HOSTNAME_RE = re.compile(r'^[a-z0-9]([a-z0-9\-\.]*[a-z0-9])?$') +# Hostname characters: letters, digits, hyphens only within labels; dots separate labels. +# Each label must start and end with a letter or digit; no consecutive dots. +_HOSTNAME_RE = re.compile( + r'^[a-z0-9]([a-z0-9\-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9\-]*[a-z0-9])?)*$' +) # Managed domain keys that produce Caddy virtual-host blocks (excluding sslemail) _MANAGED_DOMAIN_KEYS: frozenset[str] = frozenset([ diff --git a/app/sovran_systemsos_web/static/css/domain-setup.css b/app/sovran_systemsos_web/static/css/domain-setup.css index 8b0e770..2db406e 100644 --- a/app/sovran_systemsos_web/static/css/domain-setup.css +++ b/app/sovran_systemsos_web/static/css/domain-setup.css @@ -171,3 +171,15 @@ domain-field-actions { .port-req-status { font-weight: 600; } + +/* ── Wallet Connections unique-hostname warning ───────────────────── */ + +.domain-nwc-warning { + margin-bottom: 14px; + padding: 10px 14px; + background: rgba(255, 180, 0, 0.10); + border: 1px solid var(--warning-color, #f59e0b); + border-radius: 8px; + font-size: 0.88rem; + line-height: 1.6; +} diff --git a/app/sovran_systemsos_web/static/js/features.js b/app/sovran_systemsos_web/static/js/features.js index 8b4339c..fcb7b8d 100644 --- a/app/sovran_systemsos_web/static/js/features.js +++ b/app/sovran_systemsos_web/static/js/features.js @@ -76,7 +76,7 @@ function openDomainSetupModal(feat, onSaved) { } var nwcWarning = isWalletConnections - ? '
lightning.yourdomain.com, or a separate domain. ' +
'Do not reuse a domain already assigned to Matrix, Nextcloud, WordPress, BTCPay Server, Vaultwarden, Haven, or another Caddy site.' +
@@ -193,7 +193,7 @@ function openDomainReconfigureModal(feat, existingDomain, onSaved) {
}
var nwcWarning = isWalletConnections
- ? 'lightning.yourdomain.com, or a separate domain. ' +
'Do not reuse a domain already assigned to Matrix, Nextcloud, WordPress, BTCPay Server, Vaultwarden, Haven, or another Caddy site.' +
diff --git a/app/tests/test_domain_conflict.py b/app/tests/test_domain_conflict.py
index f28bffd..01605bc 100644
--- a/app/tests/test_domain_conflict.py
+++ b/app/tests/test_domain_conflict.py
@@ -165,7 +165,10 @@ class ValidateHostnameTests(unittest.TestCase):
self.assertFalse(server._validate_hostname(""))
def test_invalid_trailing_dot(self):
- # After normalization a trailing dot should have been removed.
+ # The hostname validator rejects trailing dots directly.
+ # In the API flow, normalization removes exactly one trailing dot before
+ # this validator is called, so a single trailing dot in user input is
+ # handled before reaching validation.
self.assertFalse(server._validate_hostname("foo.example.com."))
def test_invalid_with_underscore(self):