v1.3 — 2FA (TOTP + backup codes)
v1.3 — Двухфакторная аутентификация
Полноценная 2FA по стандарту RFC 6238 (TOTP) + одноразовые backup-коды для emergency-доступа.
🛡️ TOTP setup-flow
- Страница /profile/two_factor с QR-кодом (SVG via
rqrcode) — отсканируй в Google Authenticator / 1Password / Authy / любом TOTP-клиенте - Fallback на ручной ввод секрета (для старых клиентов)
- Verify-step с 6-значным кодом перед включением — никакого "включил-и-забыл-как-настроил"
- Drift-tolerance ±30s + replay-protection через
otp_last_used_at(тот же код не пускают дважды в окне)
🔑 Backup codes
- 10 одноразовых hex-кодов (8 chars) генерятся при включении 2FA
- Plaintext показывается ОДИН раз — потом только bcrypt-хеши в БД (security best practice)
- Каждый код consumed-after-use: использовал → удалён из набора
- Регенерация по запросу (требует TOTP) — старые становятся невалидны
🚪 Sign-in challenge
- После password-auth юзер с включённой 2FA попадает на /two_factor/challenge
- Поле принимает TOTP или backup-код (single input, оба варианта работают)
- Pending session живёт 5 минут — дальше повторный логин
🎨 UI
- Карточка статуса 2FA в /profile/security (вкл/выкл + кол-во оставшихся backup-кодов)
- Apple-style верстка: status-dot, card-apple--inset для отображения backup-codes
- Confirm-required при выключении
🐛 Bonus fix
- Submodule
design-system: убранpointer-events: noneсо скрытого<select>внутри.filter-chipкалендаря — теперь chip-фильтры кликабельны безapple-selectStimulus-контроллера, используется нативный системный picker
🌍 i18n
- +35 ключей в ru/en/de → паритет 2232/2232/2232