From 97ce10dd6fc1eed02de5e5db27725bb3fb37e89f Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 9 Sep 2026 19:10:01 +0000 Subject: [PATCH] Improved formatting of origin configuration in startup box. --- paskia/util/startupbox.py | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/paskia/util/startupbox.py b/paskia/util/startupbox.py index bf4cde7..87abab3 100644 --- a/paskia/util/startupbox.py +++ b/paskia/util/startupbox.py @@ -6,11 +6,13 @@ import os import re from sys import stderr from typing import TYPE_CHECKING +from urllib.parse import urlparse from fastapi_vue.hostutil import parse_endpoints from paskia._version import __version__ from paskia.domains import auth_host_url, origin_url, partition_origins +from paskia.util import hostutil from paskia.util.constants import DEFAULT_PORT, DEVMODE from paskia.util.hostutil import format_endpoint, wildcard_base @@ -85,9 +87,47 @@ def _origin_phrase(key: str, rp_id: str) -> str: return _compact_url(origin_url(key)) +def _covered_by_wildcard(key: str, pattern: str) -> bool: + """Whether an origins-table key is redundant given a wildcard key. + + Mirrors DomainConfig matching (sansio._allowlisted): a wildcard covers + hostnames under its base over https (any port), except under localhost + where any scheme and any port match. Plain http entries outside + localhost are therefore never covered and stay listed. + """ + base = wildcard_base(pattern) + if base is None: + return False + # Keys are bare hosts (https:// and '/' stripped by origin_key, port + # kept) or full origins; urlparse needs a scheme or '//' prefix. + hostname = urlparse(key if "://" in key else f"//{key}").hostname + if not hostname: + return False + if pattern.startswith("**."): + matched = hostutil.is_subdomain(hostname, base) + else: + # '*.base' covers exactly one subdomain level + matched = hostname.endswith(f".{base}") and "." not in hostname[ + : -len(base) - 1 + ] + if not matched: + return False + if hostutil.is_subdomain(base, "localhost"): + return True # localhost: any scheme, any port + return "://" not in key or key.startswith("https://") + + def _signin_summary(in_domain: list[str], rp_id: str) -> str: """Compact summary of a domain's in-domain sign-in sites.""" - phrases = [_origin_phrase(key, rp_id) for key in sorted(in_domain)] + # Prune entries already covered by a reported wildcard (e.g. the auth + # host under '**.{rp-id}'); http origins outside localhost survive. + wildcards = [k for k in in_domain if wildcard_base(k)] + keys = [ + k + for k in in_domain + if wildcard_base(k) or not any(_covered_by_wildcard(k, w) for w in wildcards) + ] + phrases = [_origin_phrase(key, rp_id) for key in sorted(keys)] if len(phrases) > 2: n = len(phrases) - 1 return f"{phrases[0]}, +{n} site{'s' if n > 1 else ''}"