Skip to content

feat(sw): finish background scanning without spending authority (#212) - #237

Open
Jerryvic911 wants to merge 5 commits into
wraith-protocol:developfrom
Jerryvic911:feat/212-background-scanning
Open

Jerryvic911 wants to merge 5 commits into
wraith-protocol:developfrom
Jerryvic911:feat/212-background-scanning

Conversation

@Jerryvic911

Copy link
Copy Markdown
Contributor

Summary

Finishes background scanning for #212 without exposing spending authority.

  • The page seals only the viewing key and the spending public key (AES-GCM, fresh non-extractable key) directly into IndexedDB. postMessage carries only { type, publicKey }.
  • The service worker opens the sealed key on every scan pass and holds no state between runs. Lock deletes the wrapping key, so the worker can't decrypt and the scan cursor doesn't advance. Re-registering resumes from the saved cursor.
  • Matching uses a new findMatches that needs no spending scalar (parity-tested against scanWithStrategy for fast/balanced/full). Notifications contain only the stealth address.
  • Workers drop any message containing a spending-secret field, and legacy encrypted* fields are scrubbed from old records on activate.
  • Event fetching in the worker now follows RPC pagination.
  • Tests cover lock, restart, key removal, lock during a scan, account binding, and a static guard against the spending scalar reappearing in worker-facing files.

Notes

  • The page now uses the registered app-sw (serviceWorker.ready). It previously registered /sw/stellar-notification-sw.js, which isn't built into dist.
  • Existing users need to re-enable notifications once.
  • Threat model: the wrapping key lives in the same origin's IndexedDB. It can't be exported via the API, but same-origin code can use it. The guarantee is that no spend authority exists in workers or storage; a leaked viewing key reveals payments, not funds.
  • Out of scope: the foreground stellar-scanner.worker.ts still receives the spending scalar from the page.

Closes #212

@vercel

vercel Bot commented Oct 17, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the truthixify's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@Jerryvic911 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking findings:

  1. src/workers/stellarScanMatch.ts:33 rejects every announcement whose scheme is not SCHEME_ID (v1 = 1), but this worker fetches from the configured v2 announcer in src/sw/app-sw.ts:96; that contract only emits scheme 2. The SDK scanner already treats SCHEME_ID_V2 as supported. As written, background scans complete and advance the cursor while silently reporting zero matches for deployed v2 payments. Add a scheme-aware v2 matching path (including the v2 view-tag derivation) and a non-vacuous scheme-2 fixture.

  2. The claimed lock behavior is not connected to production. lockScanKey / lockAllScanKeys are exported from src/sw/scanKeyStore.ts:160-162, but no non-test code calls either function. Wallet/app lock or disconnect therefore leaves the IndexedDB wrapping key usable and the worker able to decrypt scan material. Wire key locking into the real lock/disconnect lifecycle and cover that lifecycle end-to-end, not only the backend helper.

  3. src/sw/announcementFetch.ts:66-69 stops whenever a page contains fewer than 1,000 events even if RPC returned a continuation cursor. That can discard later pages and then advance lastScannedLedger, permanently skipping announcements. Also, a malformed/missing result.events is treated as an empty successful page. Consume until the cursor is absent and validate the JSON-RPC result before allowing the scan cursor to advance; add short-page-with-cursor and malformed-envelope tests.

@Jerryvic911

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Status:

  1. v2 matching: findMatches now handles scheme 1 and 2, including the v2 public view tag
    (SHA-256("wraith:stellar:view-tag:v2:" || R || V)[0], mirrored from the SDK source since
    the released 1.4.5 doesn't export it). The event parser handles both layouts (3-topic v1,
    4-topic v2 with the stealth address in the value). Scheme-2 tests use fixtures whose v2 tag
    differs from the legacy tag.
  2. Lock: scan keys are locked whenever the Stellar stealth keys are cleared (wallet disconnect,
    app idle lock, leaving recovery mode), with lifecycle tests against the real provider.
  3. Pagination/validation: pages are consumed until the cursor stops advancing, and malformed
    JSON-RPC responses throw instead of advancing the scan cursor.

One question: ANNOUNCER_CONTRACT in app-sw.ts is CCJLJ2QR…WVWL, which the SDK lists as the
v1 announcer, and announcerV2 isn't set in the SDK deployments. Which contract ID emits scheme 2?
If it's a separate contract, I'll add it to the scan.

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The prior pagination, lock-lifecycle, and scheme-2 findings are fixed, but src/sw/announcementFetch.ts:102-106 now treats a repeated continuation cursor as successful exhaustion. That returns a partial announcement list with latestLedger, and the caller can advance its durable scan cursor past unread events. A repeated non-empty cursor is a malformed/stalled RPC response and must fail without advancing; update the current "stops when the cursor stops advancing" test to assert rejection. The six focused suites (46 tests) and build otherwise pass locally.

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The stalled-cursor follow-up resolves the reliability blocker. Reviewed exact head 3c01c7b: all 49 focused background-scan tests pass and the production build succeeds. Approved, but the branch still conflicts with current develop and must be rebased before merge.

This branch has not been deployed

No deployments
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.

[Wave 10][Carryover] Finish background scanning without exposing spending authority

2 participants