From 9d4033d950c095ae804a7a8bd5cf972951b8022e Mon Sep 17 00:00:00 2001 From: Jonathan Singer Date: Mon, 20 Jul 2026 13:31:19 -0400 Subject: [PATCH] Pass the relay's work_email_required error through the viewer server Classify the relay's 400 work_email_required separately from a malformed address so the browser can show the "use your work email" message. --- strix/viewer/auth.py | 6 +++++- strix/viewer/server.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/strix/viewer/auth.py b/strix/viewer/auth.py index e830a478..353b9e30 100644 --- a/strix/viewer/auth.py +++ b/strix/viewer/auth.py @@ -123,12 +123,16 @@ def _parse_body(raw: bytes) -> dict[str, Any]: def otp_start(email: str) -> None: """Ask the relay to email a verification code. Raises RelayError on failure.""" - status, _ = _post_json("/api/oss/otp/start", {"email": email}, timeout=_OTP_TIMEOUT) + status, data = _post_json("/api/oss/otp/start", {"email": email}, timeout=_OTP_TIMEOUT) if status == 200: return if status == 429: raise RelayError("rate_limited") if status == 400: + # The relay uses 400 both for a malformed address and, separately, to + # reject a free/personal email domain (it wants a work email). + if data.get("error") == "work_email_required": + raise RelayError("work_email_required") raise RelayError("invalid_email") raise RelayError("unavailable") diff --git a/strix/viewer/server.py b/strix/viewer/server.py index 2799c879..6922663b 100644 --- a/strix/viewer/server.py +++ b/strix/viewer/server.py @@ -284,6 +284,7 @@ def _make_handler(state: _ViewerState) -> type[BaseHTTPRequestHandler]: status_by_code = { "rate_limited": HTTPStatus.TOO_MANY_REQUESTS, "invalid_email": HTTPStatus.BAD_REQUEST, + "work_email_required": HTTPStatus.BAD_REQUEST, "invalid_code": HTTPStatus.FORBIDDEN, "reverify": HTTPStatus.UNAUTHORIZED, "forbidden": HTTPStatus.FORBIDDEN,