fix: dup/modularisation findings — account gift-card 2FA gate, single-source 2FA predicate, login store delegation

Restart-loop dup/mod review findings:
- Account page gift-card buy flow now passes the 2FA verification-code gate end-to-end: TwoFactorCodeInput + Request-a-new-code wired for saved-card/save-card charges, verification_code in the /api/user/giftcards/buy body, 403/429 gate-failure self-heal, buy button gated on missing code (backend BuyGiftCard gate at giftcards.go:1471 already required it — the frontend never sent it)
- Removed dead requires2FACodeForSavedCard export from square.ts (zero consumers; all surfaces use authStore.savedCardChargeRequires2FACode) + its test; auth store getter documented as THE single source of truth
- Login page now delegates token persistence to authStore.setToken instead of direct localStorage writes (drift-risk closed; setToken persists both tokens identically so the full-reload init still works)
- Pence comment corrected (GBP minor unit)
- account/+page.svelte:84+6; square.ts -16; square.test.ts -26; auth.svelte.ts comment; login/+page.svelte delegation

Frontend 72/72 tests + build clean; backend builds.
This commit is contained in:
2026-08-22 00:34:50 +01:00
parent 4d5d2cd381
commit a8bf24ee23
5 changed files with 95 additions and 59 deletions
-26
View File
@@ -11,7 +11,6 @@ import {
isSavedCardVerificationRequired,
isTwoFactorVerificationGateFailure,
requestNewTwoFactorCode,
requires2FACodeForSavedCard,
sanitizeDecimalInput,
submitPaymentWithRetry
} from './square';
@@ -220,31 +219,6 @@ describe('payment failure classification', () => {
});
});
describe('requires2FACodeForSavedCard', () => {
it('is true when the session user has twoFactorRequired set', () => {
expect(requires2FACodeForSavedCard({ twoFactorRequired: true })).toBe(true);
});
it('is false when twoFactorRequired is unset or false', () => {
expect(requires2FACodeForSavedCard({ twoFactorRequired: false })).toBe(false);
expect(requires2FACodeForSavedCard({})).toBe(false);
});
it('is false for a null/undefined session user', () => {
expect(requires2FACodeForSavedCard(null)).toBe(false);
expect(requires2FACodeForSavedCard(undefined)).toBe(false);
});
it('does not depend on the 2FA setup flag (B6/B10: the code is required per charge)', () => {
expect(requires2FACodeForSavedCard({ twoFactorRequired: true, twoFactorEnabled: true })).toBe(
true
);
expect(requires2FACodeForSavedCard({ twoFactorRequired: true, twoFactorEnabled: false })).toBe(
true
);
});
});
describe('isTwoFactorVerificationGateFailure', () => {
it.each([
[403, 'A two-factor verification code is required to use this saved card', true],