fix: dup/mod secondary round — till 2FA gate parity, mint-cooldown single source, notification parity, pence comments
Loop B dup/mod attack findings:
- TillPurchases admin 2FA gate now mirrors PaymentModal and the backend: gateActive = twoFactorEnforced && customerTwoFactorEnabled && paymentMethod='saved_card'; the customer's setup flag is fetched from GET /api/admin/users/{id} on selection. A 2FA-disabled customer in an enforced env no longer hits a dead-end blocked input — the charge 403 surfaces the actionable message via the existing self-heal.
- Extracted twoFAMintThrottled helper shared by SetupTwoFAHandler and ensurePendingTwoFACode — mint-cooldown rule can no longer drift between setup and disable-flow paths
- Notification-helper drift documented: sweep copy states the intentional booking+user scoping vs the canonical webhook copy (cross-referenced); auth refresh_token_reuse insert verified to carry the same NOT EXISTS acknowledged_at IS NULL guard; no import cycle (webhooks→payments one-way)
- Pence convention: 'rounded to the cent' corrected to 'pence' (handlers.go:2726)
26/26 backend packages; 72/72 frontend tests + build; env-docs 41/41.
This commit is contained in:
@@ -667,8 +667,10 @@ func disputeNotificationID(squareDisputeID string) string {
|
||||
// an.booking_id IS NOT DISTINCT FROM $1 AND an.acknowledged_at IS NULL` (a
|
||||
// notification blocks a re-notify until the admin acknowledges it, then a NEW
|
||||
// event re-arms). sweep.go's insertCriticalPaymentNotification mirrors this
|
||||
// predicate exactly (its copy is the same guard over (reason, booking_id,
|
||||
// user_id)); if the guard ever changes, sweep.go must be updated to match.
|
||||
// predicate in shape (its copy applies the same NOT EXISTS/acknowledged_at
|
||||
// IS NULL guard over (reason, booking_id, user_id) — an intentional
|
||||
// user-scoping addition for sweep-originated events, documented on the sweep
|
||||
// copy itself); if the guard ever changes, sweep.go must be updated to match.
|
||||
//
|
||||
// Untracked disputes (no local payment row, booking_id NULL) pass disputeID
|
||||
// instead: each DISTINCT square dispute gets its OWN notification under the
|
||||
|
||||
Reference in New Issue
Block a user