Skip to content

feat: open pubky auth links - #722

Open
ovitrif wants to merge 85 commits into
codex/pubky-ring-signupfrom
codex/715-pubkyauth-links
Open

feat: open pubky auth links#722
ovitrif wants to merge 85 commits into
codex/pubky-ring-signupfrom
codex/715-pubkyauth-links

Conversation

@ovitrif

@ovitrif ovitrif commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

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

  • Applies Bitkit claim validation only to the uniquely targetable bitkit://pubky-auth/setup wrapper and normalizes that wrapper to Paykit rc51's pubkyauth://signin_grant request while preserving its raw query.
  • Accepts lightning:/lnurl*:-prefixed raw pubkyauth:// auth and signup requests from OS links through the same parsing path used by scanner and clipboard paste.
  • Retains setup requests, Ring callbacks, BIP21, BOLT11, and gift links through startup, restoration, PIN, scene, and app lifecycle gates until their destination UI can handle them.
  • Preserves feat: support Pubky signup #724's signup parsing, identity checks, scanner dismissal, loading state, and profile-setup continuation as the source of truth.
  • Requires wrapper requests to carry the supported watch-only-account-v1 claim with the exact server/private read-write capability set and rejects missing, duplicate, unsupported, or malformed authorization parameters before account material can be authorized.
  • Displays the parsed authorization relay origin on watch-only consent and authorization without representing it as a verified service identity.
  • Uses the separate pubkyring://signin scheme only for Bitkit's outbound Ring handoff.

Linked Issues/Tasks

Stack Note

#722 targets #724, which targets #697. Head 30cc049a merges the current #724 branch (51100a3a) and current master (7a828487) and was 0 commits behind both at publication. Until the parent branches sync with master, 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

  • 1. Terminated or PIN-locked wallet with Paykit UI and a Bitkit-generated Pubky identity → open a valid setup link → finish startup/unlock: watch-only consent shows the authorization relay origin.
  • 2. Watch-only consent → Cancel: returns without authorizing or exporting account material.
  • 3. Offline wallet → open 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

  • Previous focused clean-simulator tests: 135 passed across PubkyAuthRequestTests, PubkyAuthURLSchemeTests, SceneDelegateTests, PubkyProfileManagerTests, PubkyAuthApprovalSheetTests, PendingProfileSetupResumeTests, and ShopPaymentRequestTests on bcc07259.
  • Previous E2E Debug simulator build-and-run: passed on bcc07259; the app launched and produced a semantic UI snapshot.
  • Previous SwiftFormat, translation validation, and git diff --check: passed on bcc07259.
  • Current-head integration checks on 30cc049a: signed merge commits; current feat: support Pubky signup #724 and current master are ancestors; both were 0 commits behind at publication.
  • Current-head work was limited to source, git, and metadata inspection at user direction; tests, builds, formatters, translation validation, simulator/device QA, CI reruns, and CI watching were not run.

@greptile-apps

This comment has been minimized.

Comment thread Bitkit/Info.plist Outdated
jvsena42 and others added 3 commits September 2, 2026 07:27
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
ovitrif

This comment was marked as off-topic.

Comment thread Bitkit/AppScene.swift Outdated
Comment thread Bitkit/Models/PubkyAuthRequest.swift
@ovitrif
ovitrif force-pushed the codex/715-pubkyauth-links branch from d8110c0 to 48b2191 Compare September 2, 2026 21:43
@ovitrif
ovitrif requested a review from ben-kaufman September 2, 2026 21:45
Comment thread Bitkit/ViewModels/AppViewModel.swift
@ovitrif ovitrif changed the title feat: open Pubky auth links feat: open pubky auth links Sep 3, 2026
@ovitrif
ovitrif force-pushed the codex/715-pubkyauth-links branch from 48b2191 to c108dee Compare September 3, 2026 21:51
@ovitrif
ovitrif requested a review from ben-kaufman September 3, 2026 21:52
Comment thread Bitkit/ViewModels/AppViewModel.swift
@ovitrif
ovitrif requested a review from ben-kaufman September 3, 2026 22:45
Comment thread Bitkit/ViewModels/AppViewModel.swift
@ovitrif
ovitrif changed the base branch from master to codex/pubky-ring-signup September 8, 2026 17:05

@jvsena42 jvsena42 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/mastergit 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 immutable let) and passes config.request / config.request.rawUrl to performAuthorization. A second link arriving mid-approval goes through showSheet, which calls hideSheet() first — the .sheet(item:) tears the view and its @State down, dismissing the AuthCheck cover, 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 on rawUrl equality. 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 when walletExists, not initializing/restoring, and isPinVerified || !pinEnabled; backgrounding resets isPinVerified, which unmounts it and the sheet. routePendingDeepLinkIfReady clears the slot before its first await, so the .task(id:) + .onChange double-trigger can't double-handle.
  • Wrapper trust boundary. isBitkitSetupHandoff requires exact scheme/host/path, no userinfo/port/fragment, non-empty query not starting with ?. normalizedProtocolURL hardcodes host signin_grant and passes raw query bytes through. parse rejects duplicate relay/secret, then forces the claim check — exactly one x-bitkit-claim=watch-only-account-v1 and caps set-equal to the fixed constant. parseSignup throws if a wrapper carried a claim, and a wrapper can't be a signup URL anyway. Companion approval passes the hardcoded watchOnlyAccountCapabilities, never request.capabilities.
  • Rendered attacker text. relayOrigin is rebuilt as scheme://host[:port] from URLComponents — no path, query or userinfo — so it can't contain < to break the <accent> markup. sanitizedDeeplinkDescription strips query and userinfo, and for opaque lightning: URLs logs only the scheme, so secret never 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 exposure pubkyauth:// had before this PR. Ring callbacks are nonce-pinned.
  • Lifecycle. The .task(id:) restarting when LDK reaches .running can't lose a pubky link: handleScannedData reaches showSheet with no await before 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.

Comment thread journeys/pubky-auth/README.md Outdated
@ovitrif
ovitrif requested a review from jvsena42 September 8, 2026 19:07
@ben-kaufman
ben-kaufman force-pushed the codex/pubky-ring-signup branch from 6646af9 to 7f26e99 Compare September 9, 2026 08:39
@ben-kaufman
ben-kaufman force-pushed the codex/pubky-ring-signup branch from 7f26e99 to a3ebbc7 Compare September 9, 2026 09:33
pwltr and others added 3 commits September 9, 2026 15:29
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: open Pubky auth links from iOS

4 participants