From 1223ffbe38996d33a6be5357600ca2ccf42ecfb3 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Thu, 1 Oct 2026 21:51:09 +0530 Subject: [PATCH] refactor(auth): table-drive loopback redirect host canonicalisation The host check was a three-branch if/elif mapping each accepted loopback literal to its URL authority spelling; a lookup table states the same allow-list in one place. The final urlunparse also re-set scheme, netloc and fragment even though every earlier check already guarantees they are canonical (http, netloc == canonical_netloc, '#' rejected), so only the empty-path -> "/" normalisation is applied. Behaviour and 400 messages are unchanged. --- hermes_cli/dashboard_auth/routes.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/hermes_cli/dashboard_auth/routes.py b/hermes_cli/dashboard_auth/routes.py index 300dec2a39..4115a21c2a 100644 --- a/hermes_cli/dashboard_auth/routes.py +++ b/hermes_cli/dashboard_auth/routes.py @@ -215,6 +215,10 @@ async def auth_login(request: Request, provider: str, next: str = ""): # --- Public: RFC 8252 native-app authorization (system browser + loopback + PKCE) +# RFC 8252 loopback IP literals -> their canonical URL authority spelling. +_LOOPBACK_NETLOC_HOSTS = {"127.0.0.1": "127.0.0.1", "::1": "[::1]"} + + def _validate_loopback_redirect_uri(raw: str) -> str: """Return a canonical RFC 8252 loopback URI or reject it. @@ -242,23 +246,14 @@ def _validate_loopback_redirect_uri(raw: str) -> str: raise _http(400, "native redirect_uri must not contain a fragment") if parsed.username is not None or parsed.password is not None: raise _http(400, "native redirect_uri must not contain userinfo") - if hostname == "127.0.0.1": - canonical_host = "127.0.0.1" - elif hostname == "::1": - canonical_host = "[::1]" - else: + canonical_host = _LOOPBACK_NETLOC_HOSTS.get(hostname) + if canonical_host is None: raise _http(400, "native redirect_uri host must be a loopback IP literal (127.0.0.1 / ::1)") canonical_netloc = canonical_host + (f":{port}" if port is not None else "") if parsed.netloc != canonical_netloc: raise _http(400, "native redirect_uri must use a canonical loopback authority") - return urlunparse( - parsed._replace( - scheme="http", - netloc=canonical_netloc, - path=parsed.path or "/", - fragment="", - ) - ) + # scheme/netloc are already canonical and fragments rejected; only an empty path needs "/". + return urlunparse(parsed._replace(path=parsed.path or "/")) def _select_native_provider(provider: str):