reauth.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334
  1. /**
  2. * What the delete-account and delete-workshop dialogs ask for before the
  3. * server will go ahead, and the sentences it refuses with. Shared by the
  4. * server check (reauth.server.ts) and the dialogs, which show the refusal in
  5. * the person's own language by looking its key up here.
  6. *
  7. * - 'password': the account has a password, and must type it.
  8. * - 'totp': no password, but two-factor is on: a code from the app.
  9. * - 'none': neither (Google or passkey only), so the session itself must be
  10. * fresh, see REAUTH_FRESH_SESSION_MINUTES.
  11. */
  12. export type ReauthRequirement = 'password' | 'totp' | 'none'
  13. /** How recent a sign-in must be when there is nothing else to ask for. */
  14. export const REAUTH_FRESH_SESSION_MINUTES = 10
  15. export const REAUTH_ERRORS = {
  16. wrongPassword: 'Wrong password.',
  17. wrongCode: 'Wrong code.',
  18. tooManyAttempts: 'Too many attempts. Wait a few minutes and try again.',
  19. signInAgainAccount: 'Sign in again before deleting your account.',
  20. signInAgainWorkshop: 'Sign in again before deleting the workshop.',
  21. } as const
  22. export type ReauthError = keyof typeof REAUTH_ERRORS
  23. /** The `settings` message key for a refusal above, or null for any other error. */
  24. export function reauthErrorMessageKey(message: string | undefined): string | null {
  25. const match = (Object.keys(REAUTH_ERRORS) as ReauthError[]).find(
  26. (key) => REAUTH_ERRORS[key] === message
  27. )
  28. if (!match) return null
  29. return `account.reauth${match.charAt(0).toUpperCase()}${match.slice(1)}`
  30. }