feat(mfa): Google Authenticator (TOTP) + branded 2FA login popup

- Settings → MFA Factors: wire the Authenticator tile to the real backend.
  POST /v1/mfa/totp/setup mints the QR + secret + otpauth URL; the response
  binds directly to <img [src]="totp.qrDataUri"> alongside a manual-entry
  fallback ("Can't scan? Enter this in your app:") and an issuer/account
  label. Verify hits POST /v1/mfa/totp/verify; on
  error.msg.user.mfa.totp.code.invalid the message renders inline. Disable
  uses DELETE /mfa/factors/{id}.
- Already-enrolled guard surfaces a dialog and re-hydrates from
  /mfa/factors when error.msg.user.mfa.totp.already.enrolled is returned.
- Mobile click-to-add deep-link bound to otpAuthUrl (shown on touch-only
  browsers via @media (hover:none)).
- access-control.service.ts: TotpSetupResponse + TotpVerifyResponse +
  setupTotp() / verifyTotp() endpoints.
- hydrateFromServer / resetAllFactors now treat TOTP as a persisted factor
  (verified, factorId, verifiedOn) instead of local state.
- Login 2FA picker: iconFor() returns 'qrcode' for TOTP, OTP-context copy
  switches to "Open your authenticator app", Resend button hidden,
  validity badge reads "rotates every 30 s".
- 2FA popup redesigned: CBS Nexora brand lockup at the top (logomark +
  wordmark + 'Secure Sign-in' sub-line), refined card depth with stacked
  shadow + ambient glow, segmented 6-cell OTP input, brighter primary
  button gradient, responsive collapse at <=480px.
- Register faQrcode in icons.module.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-05-15 17:45:07 +05:30
co-authored by Claude Opus 4.7
parent 595054b0b8
commit 4322f37c6d
10 changed files with 500 additions and 147 deletions
+3 -1
View File
@@ -50,7 +50,9 @@
"Bash(findstr /n \"faExchange faBolt faClock faPaperPlane faFlask faSpinner faUserFriends faCommentDots faListAlt faInfoCircle faSearch faTimes faUndo faCheckCircle faExclamationTriangle\" \"c:\\\\Users\\\\adity\\\\Music\\\\CBS\\\\UI\\\\web-app\\\\src\\\\app\\\\shared\\\\icons.module.ts\")",
"Bash(findstr /i \"error neft-rtgs digital\")",
"Bash(findstr /I /C:\"error\" /C:\"neft-rtgs\" /C:\"digital\")",
"Bash(findstr /V \"warning\")"
"Bash(findstr /V \"warning\")",
"Bash(dir \"C:\\\\Users\\\\adity\\\\Music\\\\CBS\\\\UI\\\\web-app\\\\src\\\\app\\\\settings\")",
"Bash(findstr \"merge_code_update\")"
]
}
}