fix(checkout): guard decrypt-failure sentinel + client-side INR QR (closes #44) - #45
fix(checkout): guard decrypt-failure sentinel + client-side INR QR (closes #44)#45gitchadd wants to merge 1 commit into
Conversation
On decrypt failure order-machine sets decryptedUpi="Session changed". main rendered that sentinel as a copyable VPA (CopyRow) and encoded it into the INR QR, and shipped the QR (VPA + amount + order id) to third-party api.qrserver.com on every INR accepted screen. - Show "Couldn't load payment details. Please contact support." for the sentinel (any currency) instead of rendering it as a payment address. - Gate the INR QR on a resolved VPA (not the sentinel) + a real amount. - Replace the api.qrserver.com <img> with a lazy client-side qrcode.react QR, closing the third-party data leak. Same upi:// QR content, generated locally. Closes #44 (surfaced in the PR #43 review). verify green: typecheck + build + 142 tests; no api.qrserver.com in the runtime bundle.
Agentic adversarial review — PRs #43 + #45 reviewed togetherThree independent read-only agents (bug-hunter; system-architect; compliance) over both branches, plus my own verification of the load-bearing claims. Verdict: both clean — no production bugs, compliance PASS. Ship them as a PAIR. #43's test is genuine red/green (143 tests); #45's 142 is accurate and the Merge-ordering coupling — the one real interaction findingIndependent branches, but a coupled pair:
Follow-ups the review generated (being fixed, not filed-and-forgotten)
Repo-completeness verified myself: Deploy gate: merge needs explicit per-merge approval. This review is the agentic step. |
What
Closes #44 (surfaced in the PR #43 adversarial review). Two coupled decrypt-failure warts on
main:"Session changed"was rendered as a copyable VPA (CopyRow) and encoded into the INR QR — on a decrypt failure the user saw/copied/scanned a bogus address.api.qrserver.com, leaking the counterparty VPA + amount + order id to a third party on every INR accepted screen.Changes
decryptedUpi === "Session changed"→ "Couldn't load payment details. Please contact support." instead of a payment address. Placed first so it covers compound currencies too, and never misfires on a valid value.fiatDisplay.api.qrserver.com<img>is replaced by a lazyqrcode.reactQRCodeSVG(split chunk, out of the main/checkoutbundle). Sameupi://pay?...content, generated locally → third-party leak closed.Adds the
qrcode.reactdependency (small, lazy-loaded, already used in user-app-spa). Focused port of the fix that shipped on the archivedfeat/upi-intentbranch (tagarchive/feat-upi-intent).Verification
npm run verifygreen: typecheck, build, 142 tests.api.qrserver.comin the runtimedist/*.js|*.cjs(the only.mapmatch is this PR's own code comment);QRCodeSVGpresent in the runtime bundle.Checkouthas no render-test harness, so the sentinel→error branch is verified by read + typecheck, not a unit test. The client-side QR is the sameQRCodeSVGapproach e2e-verified earlier on the archived branch (renders, noapi.qrserver.comrequest). A Checkout render-harness is a worthwhile follow-up.Deploy gate: human review + explicit per-merge approval. Not for auto-merge.