- TWO_FACTOR_ALLOW_LOG_DELIVERY production opt-in REMOVED: plaintext codes are written to the stdout log ([2FA]/[VERIFY]) only in dev/test builds as a local DEV ONLY feature while email/SMS delivery (P6) is implemented. Production builds have no delivery channel and code issuance fails closed (503) under any configuration — no silent log-based code leak
- verification/2FA codes hashed at rest (HMAC-SHA256 via TWO_FACTOR_PEPPER, CHAR(64)); [VERIFY] dev log relay; per-user brute-force budget; password_reset purpose clears lockout for self-service recovery; dummy-bcrypt on login no-user path kills timing oracle
- sabredav weak-password list + entropy gate; .env.example ships fail-closed DAV_ADMIN_PASSWORD
- delete-account re-auth (current_password + fresh 2FA code when enforced)
- prod-tag suite (run-prod-tag-tests.sh) compiles and runs the production 2FA issuance gate: production ALWAYS reports no delivery channel and refuses issuance after the pepper check
- startup_checks_test SNAPSHOT_ENC_KEY values built at runtime so gitleaks sees no secret-shaped literals
- env-docs parity updated (flag removed, 38 vars)
PSR 2017 reg 100 makes SCA mandatory and non-waivable for customer-initiated
stored-credential charges; a merchant-side 2FA check cannot legally substitute
for it (authorising a token-less charge via 2FA leaves the MERCHANT liable for
ECI 7 / SLI 210 chargebacks and reg 77(6) compensation regardless of consent).
- payments/twofa.go: the homegrown 2FA fallback for token-less saved-card
charges is REMOVED ENTIRELY. requireTwoFactorForCardAccess is now SCA-only:
a non-empty Square verification_token (charge surfaces, token forwarded to
Square) skips the gate; anything else is refused 402 verification_required.
enforceSCAFallbackConsent is a compile-compatible no-op (fallback never runs).
- New requireTwoFactorForCardAccessWithTokenValidation distinguishes surfaces
where the token IS forwarded to Square (charge — Square validates it) from
card-SAVE surfaces (token client-asserted, never forwarded: a non-empty token
must NOT skip the save gate, auth-F1).
- SCA tokenize-result wire contract (C1): a saved card charged with a fresh
one-time tokenize-result sends the token as the charge SOURCE (new_card_token
-> source_id) alongside saved_card_id, never a separate verification_token.
resolveChargeSource resolves the saved-card branch FIRST (customer from the
card row, token as source) so combined token+card requests are SCA-clean.
- C6 consent fields (consent_version / consent_accepted) added to the booking/
tip/till/gift-card charge requests, enforced server-side before any fallback
charge could reach Square and recorded on the 2fa_fallback_charge audit row;
logVerificationTokenProvenance traces minted tokens to their charge.
- user 2FA issuance gate refactored into pure build-agnostic functions
(twoFAPepperConfigured / twoFADeliveryChannelConfigured /
twoFAEnsureIssueAllowedStrict) shared with the payments re-issue path and
exercised directly by the test,dev suite; TWO_FACTOR_FALLBACK switch and
.env.example entry removed; startup posture notes updated.
- Test coverage: fail-closed 2FA production gates (pepper/delivery), token
validation on save vs charge surfaces, completion idempotency, idempotency
key determinism, refund-policy 72h/24h epsilon boundaries, VAT parity.