* Make Discord sign-in and share links work on the web beta Discord sign-in on web asked Supabase to return to icarus://auth/callback, which a browser cannot open. On web the redirect is now the root of the page's own origin, and the callback check accepts a URI that lands on this build's redirect with a sign-in result. The page URL is published at startup when it is an auth callback or a share link (app_links on web only echoed it), and after the handler runs the sign-in parameters are removed from the address bar so a refresh does not replay a spent code. detectSessionInUri stays false: Supabase's detector would treat a ?code= share link as a sign-in and bypass authProvider's loading and error states. Share links were fixed to icarusstrats.com. They now take an origin: native builds keep production, web uses the page origin, so the beta hands out beta links. The recognizer accepts production plus the current origin. Uri.base is read only in currentShareOrigin() and currentAuthRedirectUri(); the format helpers stay pure. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Keep a pending share code across the web Discord sign-in On web, Discord sign-in navigates the tab away and back, which restarts the app and dropped a share code opened while signed out. The pending code now lives in a PendingShareCodeStore: the tab's sessionStorage on web (memory if the browser refuses storage), memory on native. The controller restores it when created, so the auth-ready listener redeems it once the returning session is ready. It is cleared once redeemed, or after a failed redemption the user was told about, so a revoked link does not replay its failure on every reload. Docs list the real Pages host, icarus-web-a50.pages.dev, in the Supabase redirect allowlist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Reject injected auth tokens, scope share-code clears, redact share codes A link to the auth redirect carrying access_token/refresh_token (query or fragment) was treated as a sign-in and handed to getSessionFromUrl, which imports token payloads even in PKCE mode. Anyone could craft one and sign the victim into the attacker's account, on web and through icarus:// on desktop alike. classifyAuthCallbackUri now accepts only a PKCE code or an error; token-bearing or undecodable links are rejected, logged redacted, never sent to Supabase, and on web scrubbed from the address bar. We only use the PKCE flow, so no genuine callback carries tokens. A redeem attempt that failed late cleared whatever code was pending, even a newer one. Each held code now has a generation, and an attempt clears only its own. Deep-link and launch-argument logs printed share codes in full. They go through redactDeepLinkUri, which hides the /share/<code> path, ?code=, ?token=, and sign-in secrets, and never throws on undecodable escapes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Harden link parsing: any-case token names, total redaction and share parsing Token parameter names are compared in lowercase, so ACCESS_TOKEN= is rejected like access_token= and scrubbed from the address bar. redactDeepLinkUri no longer throws on a path that does not decode (e.g. icarus://share/%FF?token=secret): it logs <unparseable link> instead, so one bad startup argument cannot abort the loop over the rest. Launch arguments shaped like links are always redacted, or logged as the placeholder when they do not parse; plain file paths stay readable. isIcarusShareUri and extractIcarusShareCode treat an undecodable path or query as "not a share link" instead of throwing. On web isIcarusShareUri runs on Uri.base before runApp, so a crafted /share/%FF URL could otherwise stop the beta from starting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
18 files changedLine totals unavailable