feat(require-mfa): #155 enforce MFA via admin policy toggle across app access

Add an admin-controlled `require_mfa` policy in App Settings and expose it via `/auth/app-config` so the client can enforce it globally. Users without MFA are redirected to Settings after login and blocked from protected API/WebSocket access until setup is completed, while preserving MFA setup endpoints and admin recovery paths. Also prevent enabling the policy unless the acting admin already has MFA enabled, and block MFA disable while the policy is active. Includes UI toggle in Admin > Settings, required-policy notice in Settings, client-side 403 `MFA_REQUIRED` handling, and i18n updates for all supported locales.
This commit is contained in:
fgbona
2026-03-30 17:42:40 -03:00
parent 8412f303dd
commit 66f5ea50c5
22 changed files with 260 additions and 10 deletions
+3
View File
@@ -212,6 +212,7 @@ const ru: Record<string, string> = {
'settings.saveProfile': 'Сохранить профиль',
'settings.mfa.title': 'Двухфакторная аутентификация (2FA)',
'settings.mfa.description': 'Добавляет второй шаг при входе. Используйте приложение-аутентификатор (Google Authenticator, Authy и др.).',
'settings.mfa.requiredByPolicy': 'Администратор требует двухфакторную аутентификацию. Настройте приложение-аутентификатор ниже, прежде чем продолжить.',
'settings.mfa.enabled': '2FA включена для вашего аккаунта.',
'settings.mfa.disabled': '2FA не включена.',
'settings.mfa.setup': 'Настроить аутентификатор',
@@ -365,6 +366,8 @@ const ru: Record<string, string> = {
'admin.tabs.settings': 'Настройки',
'admin.allowRegistration': 'Разрешить регистрацию',
'admin.allowRegistrationHint': 'Новые пользователи могут регистрироваться самостоятельно',
'admin.requireMfa': 'Требовать двухфакторную аутентификацию (2FA)',
'admin.requireMfaHint': 'Пользователи без 2FA должны завершить настройку в разделе «Настройки» перед использованием приложения.',
'admin.apiKeys': 'API-ключи',
'admin.apiKeysHint': 'Необязательно. Включает расширенные данные о местах, такие как фото и погода.',
'admin.mapsKey': 'API-ключ Google Maps',