feat: open pubky auth links - #722
Conversation
This comment has been minimized.
This comment has been minimized.
The receiving-capacity journey now walks the behaviour this branch adds: the number pad held disabled while the maximum settles, an entered capacity snapping down to the settled maximum with the toast naming it, and an early Max corrected once the maximum lands. It sizes the transfer at MAX rather than 25%, since settling only bites when the client balance and the capacity together crowd the funding budget. Walked on an iPhone 17 simulator against the stag0 regtest LSP. Two findings are recorded in the suite README and the journey description: the settle finishes faster than a snapshot round-trip, so the disabled pad cannot be caught there, and once LSP headroom is consumed the offered minimum can exceed the offered maximum, which leaves Continue disabled and the order-creation tail unwalkable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KpAgJrxa5FmL8PHuXUg7So
…nymdev/bitkit-ios into fix/spending-transfer-affordability
d8110c0 to
48b2191
Compare
48b2191 to
c108dee
Compare
42affae to
4d0a0b6
Compare
jvsena42
left a comment
There was a problem hiding this comment.
One LOW inline — a documentation claim rather than a code defect. Not blocking.
Scope note, so nobody reviews #729 twice: the four hardware-wallet files (HwFundingSigner.swift, HwSendSignView.swift, HwFundingSignerTests.swift, changelog.d/next/729.fixed.md) plus the .broadcastConnectivity toast strings are byte-identical to origin/master — git diff --quiet pr722 origin/master passes for all four. They're #729, merged to master at 12:27Z, showing up here only because the base branch codex/pubky-ring-signup hasn't synced master. The whole block vanishes once #724 merges master. Nothing about what the device signs changed.
Similarly, bcc07259a re-carries #724's signup parsing under this branch; I assessed it only for interaction with this PR's link delivery, not as new work.
Delta since my last review: the branch was rebased, then formatting-only 4d0a0b659 and the #724 re-stack. My relay-origin thread is addressed and survives the rebase unchanged. No over-correction, and nothing in the retention/gating design moved.
Checked and clean:
- Request pinning (TOCTOU). The sheet reads only
config.request(an immutablelet) and passesconfig.request/config.request.rawUrltoperformAuthorization. A second link arriving mid-approval goes throughshowSheet, which callshideSheet()first — the.sheet(item:)tears the view and its@Statedown, dismissing theAuthCheckcover, and re-presents after 0.7s starting fresh at.watchOnlyConsent. An approval already past PIN completes on the captured request, never the new one. The signup path additionally guards onrawUrlequality. This is the approve-A-grant-B case and it's genuinely closed. - Lock-screen bypass. All five entry points only store. The sole consumer is
MainNavView, mounted only whenwalletExists, not initializing/restoring, andisPinVerified || !pinEnabled; backgrounding resetsisPinVerified, which unmounts it and the sheet.routePendingDeepLinkIfReadyclears the slot before its firstawait, so the.task(id:)+.onChangedouble-trigger can't double-handle. - Wrapper trust boundary.
isBitkitSetupHandoffrequires exact scheme/host/path, no userinfo/port/fragment, non-empty query not starting with?.normalizedProtocolURLhardcodes hostsignin_grantand passes raw query bytes through.parserejects duplicate relay/secret, then forces the claim check — exactly onex-bitkit-claim=watch-only-account-v1andcapsset-equal to the fixed constant.parseSignupthrows if a wrapper carried a claim, and a wrapper can't be a signup URL anyway. Companion approval passes the hardcodedwatchOnlyAccountCapabilities, neverrequest.capabilities. - Rendered attacker text.
relayOriginis rebuilt asscheme://host[:port]fromURLComponents— no path, query or userinfo — so it can't contain<to break the<accent>markup.sanitizedDeeplinkDescriptionstrips query and userinfo, and for opaquelightning:URLs logs only the scheme, sosecretnever reaches logs. - URL-scheme hijack. No security-relevant inbound secret rides on a claimable scheme. The one outbound URL carrying a secret is the Ring handoff, where Bitkit is the requester — a hijacker of
pubkyring://could only act as the signer, the same exposurepubkyauth://had before this PR. Ring callbacks are nonce-pinned. - Lifecycle. The
.task(id:)restarting when LDK reaches.runningcan't lose a pubky link:handleScannedDatareachesshowSheetwith noawaitbefore it, and BitkitCore's uniffi async has no cancellation handler on the decode path.
One thing I could not settle, stated as unverified rather than cleared: my local paykit-rs checkout is older than the pinned rc51, and pubky_session.rs delegates host handling to pubky::DeepLink::from_str, so while PubkyAuthRequestTests proves rc51 parses signin_grant, I couldn't confirm the Rust approval path accepts it — the E2E journey deliberately cancels before approval. Worth one manual approve on rc51 to close.
Cross-repo: the alias-gating concern raised on synonymdev/bitkit-android#1224 is structural here rather than a bug — iOS registers URL schemes statically in Info.plist and can't runtime-gate them the way Android's manifest aliases can.
I've corrected two statements in my own earlier review bodies on this PR that the trace below showed were wrong.
…bility fix: settle spending transfer maximums
6646af9 to
7f26e99
Compare
feat: add Paykit subscriptions
7f26e99 to
a3ebbc7
Compare
* fix(receive): handle additional receive liquidity edge cases * fix(receive): address CJIT review follow-ups * fix(receive): address CJIT review feedback * fix(receive): address CJIT review feedback
Closes #715
This PR extends the #697 → #724 signup/auth stack with Bitkit-targeted Pubky marketplace setup-link delivery and explicit watch-only account authorization.
Description
bitkit://pubky-auth/setupwrapper and normalizes that wrapper to Paykit rc51'spubkyauth://signin_grantrequest while preserving its raw query.lightning:/lnurl*:-prefixed rawpubkyauth://auth and signup requests from OS links through the same parsing path used by scanner and clipboard paste.watch-only-account-v1claim with the exact server/private read-write capability set and rejects missing, duplicate, unsupported, or malformed authorization parameters before account material can be authorized.pubkyring://signinscheme only for Bitkit's outbound Ring handoff.Linked Issues/Tasks
Stack Note
#722 targets #724, which targets #697. Head
30cc049amerges the current #724 branch (51100a3a) and currentmaster(7a828487) and was 0 commits behind both at publication. Until the parent branches sync withmaster, GitHub's stacked diff also shows the inherited master changes. The #722-specific behavior is the marketplace wrapper, lifecycle routing, watch-only validation, relay display, Ring handoff, and journey coverage described above.Preview
QA Notes
Manual Tests
bitkit://gift-…: Gift Loading opens and owns node failure presentation.These external-handoff scenarios remain open; the prior automated validation below does not mark them complete.
Automated Checks
PubkyAuthRequestTests,PubkyAuthURLSchemeTests,SceneDelegateTests,PubkyProfileManagerTests,PubkyAuthApprovalSheetTests,PendingProfileSetupResumeTests, andShopPaymentRequestTestsonbcc07259.bcc07259; the app launched and produced a semantic UI snapshot.git diff --check: passed onbcc07259.30cc049a: signed merge commits; current feat: support Pubky signup #724 and currentmasterare ancestors; both were 0 commits behind at publication.