Pair a Blox via FxBlox Web (blox.fx.land) + web receiver - #114
Closed
ehsan6sha wants to merge 5 commits into
Closed
Conversation
…tive) Adds lib/core/services/blox_pairing_links.dart (dart:io-free): the buildBloxWebPairUrl / buildBloxNativePairUrl builders, the v1 return template in the https FRAGMENT form (the bearer secret never reaches a server), and parseAutopinCompleteParams(Uri) which reads the fragment first, then the query, plus AutopinCompleteParams validation (non-empty secret, per-field length caps, no control chars). The four $placeholders stay literal (raw strings). Unit-tested. Sender (blox_pairing_screen.dart): builds the blox.fx.land URL with the SAME params; on kIsWeb uses it directly; on native tries fxblox:// first and, when launchUrl returns false or throws, offers "Pair in browser" instead of the old "app not installed" dead end. Desktop's manual pairing dialog gains a "Pair in browser" button. Receiver (deep_link_service.dart): /autopin-complete arm in the universal-link handler reusing _handleAutoPinComplete, which now uses the shared parser + validation. Android app-link <data> for /autopin-complete and the AASA path so the OS opens FxFiles directly (both preserve the fragment). Contract: docs/AUTOPIN-HANDOFF.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw
captureAutopinReturn() runs in main_web.dart BEFORE runApp: it reads #/autopin-complete?secret=... (or the bare-fragment / query forms) from the location, stashes the params (memory + sessionStorage so a refresh mid-sign-in does not lose them) and history.replaceState-strips them to #/ so the secret leaves the address bar and the logged-out router redirect cannot drop it. The web home's post-login init takes the pending return and navigates to /blox-pairing with the params as go_router extra (never a query). /autopin-complete also exists as a router fallback (logged out: the redirect parks the params; signed in: the screen persists them then cleans the URL). New dart:io-free lib/web/screens/web_blox_pairing_screen.dart: shows the paired state from SecureStorageKeys.blox*, validates + writes incoming params, "Pair Blox" opens buildBloxWebPairUrl(...) in the same tab, "Unpair" clears the keys, reveal/copy of the secret behind a confirm, and the inline LAN-gateway limitation note. Settings gains a "My Devices" section linking to /blox-pairing. The pure parsing/stripping/session-encoding lives in web_autopin_return_logic.dart (VM-tested) behind the same conditional-export pattern as web_hosted_oauth. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw
site/autopin-complete/index.html (cloned from nft-claim): reads secret/hardwareId/bloxPeerId/bloxName from the fragment (query fallback); on mobile UA auto-tries fxfiles://autopin-complete?... with the 2.5 s document.hidden fallback (store links only, never a second navigation); otherwise "Open in FxFiles" + "Continue in web app" -> https://files.fx.land/app/#/autopin-complete?... (params stay in the hash, client-side). Docs: docs/AUTOPIN-HANDOFF.md (copy of the v1 contract), architecture.md section 2 (entry points + URL schemes incl. the web hand-off and the web LAN limitation), README web section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw
From the advisor review of the hand-off: - Web fallback route: after persisting the /autopin-complete?secret=... params, REPLACE the route (context.replace) instead of go() so the secret-carrying history entry is overwritten and Back cannot re-run the persist. - Forwarder (site/autopin-complete): history.replaceState-strip the fragment as soon as the params are captured so the secret does not linger in history / a shared URL; a reload shows "incomplete or already used". - Shared isAutopinReturnRoutePath() (tolerates a trailing slash) used by the parser, the web strip logic and the native universal-link arm; tests added for the trailing-slash forms. Not changed (contract): the outbound token stays in the query per AUTOPIN-HANDOFF.md v1; the fragment-form recommendation is recorded in the status doc for the spec owner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw
…MENT (v1.1) buildBloxWebPairUrl now emits https://blox.fx.land/autopin-pair#token=<t>&endpoint=<e>&returnUrl=<r> (no query) so the cloud JWT never reaches the blox.fx.land server / CDN logs, a Referer header, or synced history. The native fxblox:// URL is unchanged (query; OS-routed, no server). Call sites are untouched (they use the builder). Contract bumped to v1.1 in docs/AUTOPIN-HANDOFF.md with the receiver rule: read location.hash first, the v1 query form stays accepted as a fallback. architecture.md updated. Tests updated + a new "no query / JWT not before the #" test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw
Member
Author
|
Superseded by #115, which is rebuilt on the current main. This branch was created before ~79 commits landed, so merging it would have reverted them — deleting test files and rolling back web/pkg/fula_flutter_bg.wasm, windows/fula_flutter.dll and web/pkg/VERSION. #115 leaves those byte-identical to main and deletes nothing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lets FxFiles hand pairing off to FxBlox Web (
https://blox.fx.land) when the mobile FxBlox app isn't available, and receive the result on the web build.lib/core/services/blox_pairing_links.dart(dart:io-free):buildBloxWebPairUrl(v1.1 fragment carrier:https://blox.fx.land/autopin-pair#token=…&endpoint=…&returnUrl=…— the cloud JWT never reaches a server/CDN log orReferer),buildBloxNativePairUrl(unchangedfxblox://…),kAutopinReturnTemplate(https fragment form with the four$placeholdersFxBlox substitutes),parseAutopinCompleteParams(fragment-first). 32 tests.kIsWeb→ web URL; native triesfxblox://first, then offers "Pair in browser"; desktop manual dialog gets the same button.site/autopin-complete/index.htmlforwarder (open app or "Continue in web app"), native universal-link arm/autopin-complete(+ AASA path, Android app-link data), web receivercaptureAutopinReturn()beforerunApp(stash +replaceState), post-login hand-off to the new dart:io-freeweb_blox_pairing_screen.dart(paired state, validate + persist, Pair/Unpair, reveal/copy secret), Settings "My Devices".docs/AUTOPIN-HANDOFF.md(v1.1 spec),architecture.md§2, README.Verified: Flutter 3.41.9 — new tests 52/52;
flutter analyzeon touched files clean except a pre-existing unused import inblox_pairing_screen.dart:13;flutter build web --release -t lib/main_web.dart --base-href /app/ --pwa-strategy=none --no-wasm-dry-runbuilds. Not verified: a real round-trip (blox.fx.land/autopin-pairships with functionland/fxblox-web).🤖 Generated with Claude Code
https://claude.ai/code/session_01QyQw3WtVXDTtvJKN7ykczw