diff --git a/packages/agami-core/src/onboarding.py b/packages/agami-core/src/onboarding.py index d4c9e46..8630f64 100644 --- a/packages/agami-core/src/onboarding.py +++ b/packages/agami-core/src/onboarding.py @@ -179,11 +179,26 @@ def is_pending(user: dict[str, Any]) -> bool: } -def claim_page_html(token: str, purpose: str = _SETUP_PURPOSE, error: str = "") -> str: - """The choose-a-password page reached from a valid link, worded for what the link is for.""" +def claim_page_html( + token: str, purpose: str = _SETUP_PURPOSE, error: str = "", username: str = "" +) -> str: + """The choose-a-password page reached from a valid link, worded for what the link is for. + + **It names the account.** Without that, somebody following a link is asked to choose a password + with no way to tell WHOSE it is — and the link is shared out-of-band, so the person holding it may + have been sent the wrong one, or two of them. That was tolerable while the only link set a first + password on an account the recipient was expecting; it is not now that a link can REPLACE a working + password, where following the wrong one silently locks somebody out of their own account. + + It discloses nothing new: whoever holds the link already holds a token whose payload is base64url + and carries this same address in the clear (the module note says so). Showing it turns something + they could decode into something they can check. + """ words = _WORDING[purpose] alert = f'
for {ui.esc(username)}
' if username else "" body = f""" {alert}