fix: frontend payment surfaces — SCA wire shapes (explicit token precedence), mock token parity, infinite-loop guard, money display, delete-account re-auth, admin progress UI, mobile touch targets
- new_card_token uses explicit newCardToken ?? verificationToken precedence on every charge surface (BookingFlow, UserPaymentModal, TipPayment, PaymentModal, TillPurchases, account gift-card buy); dead verification_code/consent fields + ScaFallbackConsentDialog removed from payment flows
- mock mints cnon:sca-... tokenize-results and tokenizeWithVerification returns verificationToken:null for new cards (real-SDK parity so save-card works in dev)
- UserPaymentModal infinite /payment-methods fetch loop guarded; formatCurrency(totalPaid) no longer 100x too small
- delete-account dialog collects current_password + fresh 2FA code; admin 'Begin appointment'/'Complete' wired to /admin/bookings/{id}/progress
- mobile: 44px touch targets, active: feedback, TimeSlotPicker 50dvh, dialog close sizing, .no-scrollbar utility, CSP meta, receipt fields escaped
- vitest: policy.ts cross-check + ScaFallbackConsentDialog component tests (svelte project via happy-dom)
This commit is contained in:
@@ -205,6 +205,28 @@ export interface SavedCardVerificationResult {
|
||||
outcome: SavedCardVerificationOutcome;
|
||||
}
|
||||
|
||||
/** Result of a NEW-card `tokenizeWithVerification` — the SCA-verified cnon
|
||||
* nonce is the charge source and there is NO separate verificationToken. This
|
||||
* is the exact contract of the real Square Web Payments SDK (`card.tokenize()`
|
||||
* returns the verified token in the single `token` field — a separate
|
||||
* verification token only exists on the saved-card-on-file SCA flow), and it
|
||||
* is what the charge surfaces depend on: they send
|
||||
* `new_card_token: newCardToken ?? verificationToken` and gate
|
||||
* `save_card: X && !verificationToken`, so a new-card tokenize MUST yield a
|
||||
* null verificationToken or the save is silently suppressed. */
|
||||
export interface NewCardTokenizeResult {
|
||||
nonce: string;
|
||||
verificationToken: null;
|
||||
}
|
||||
|
||||
/** Builds a new-card tokenize-with-verification result: the cnon nonce is the
|
||||
* charge source, verificationToken is always null (mirroring the real SDK).
|
||||
* The dev mock (MockCardForm.tokenizeWithVerification) returns this so it can
|
||||
* never drift from the real contract. */
|
||||
export function newCardTokenizeResult(nonce: string): NewCardTokenizeResult {
|
||||
return { nonce, verificationToken: null };
|
||||
}
|
||||
|
||||
/** Square Web Payments `card.tokenize()` result shape. Per the CURRENT SDK
|
||||
* (Square.js /v1/), tokenize returns `{ status, token, details?, errors }` —
|
||||
* the SCA-verified token for both the new-card and the card-on-file
|
||||
@@ -292,8 +314,13 @@ export async function tokenizeSavedCardWithVerification(
|
||||
if (isSquareMock()) {
|
||||
// DEV-ONLY mock: the mock agent extends MockCardForm with a saved-card
|
||||
// SCA method. Use it when present (so the mock exercises the same
|
||||
// challenge path), otherwise fall back to a deterministic fake token
|
||||
// the backend dev mock accepts.
|
||||
// challenge path), otherwise fall back to a deterministic tokenize-result
|
||||
// token the backend dev mock accepts. The token is a GENUINE
|
||||
// tokenize-result shape — `cnon:sca-<prefix>_<amount>_ok` — so the
|
||||
// backend mock's saved-card SCA gate recognises it via
|
||||
// isSCATokenizeResultSource (square_dev.go checks the `cnon:sca-`
|
||||
// prefix) instead of the old `verify_mock_...` shape, which real Square
|
||||
// would never accept as a charge source.
|
||||
try {
|
||||
const mockModule = (await import('$lib/components/payments/MockCardForm.svelte')) as {
|
||||
tokenizeSavedCard?: (
|
||||
@@ -318,7 +345,7 @@ export async function tokenizeSavedCardWithVerification(
|
||||
}
|
||||
const prefix = squareCardId.replace(/^ccof:/, '').slice(0, 4) || 'test';
|
||||
return {
|
||||
verificationToken: `verify_mock_${prefix}_${String(Math.round(amount))}`,
|
||||
verificationToken: `cnon:sca-${prefix}_${String(Math.round(amount))}_ok`,
|
||||
outcome: 'verified'
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user