feat(cli): включение 2FA инстанс-админа командой totp-setup
2FA обязательна для инстанс-администраторов, но до её включения вход закрыт — получался замкнутый круг. Добавлены команды обслуживания: - `glchat totp-setup --email <admin>`: создаёт секрет, подтверждает его кодом, печатает секрет, otpauth-ссылку и 8 резервных кодов (каждый одноразовый); - `glchat totp-reset --email <admin>`: удаляет секрет при потере устройства; - код `auth.2fa_enrollment_required` с подсказкой, какую команду выполнить; - установщик: флаг `--admin-2fa` для автоматического включения (по умолчанию печатает подсказку, чтобы секреты не оседали в логах установки). Проверено сквозным прогоном локально: bootstrap → 403 на входе без 2FA → totp-setup → вход с TOTP-кодом → профиль, серверы, комнаты, роли, участники, аудит, создание сервера админом, 429 на шестой попытке входа, секретов в логах нет.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { createBrowserRouter, Navigate } from 'react-router';
|
||||
|
||||
import { AuthGuard } from '@/components/AuthGuard';
|
||||
import {
|
||||
AppearanceSettingsPage,
|
||||
AppLayout,
|
||||
IndexRedirect,
|
||||
GuildView,
|
||||
InstanceSettingsPage,
|
||||
LoginPage,
|
||||
NoGuildView,
|
||||
OnboardingPage,
|
||||
ProfileSettingsPage,
|
||||
RegisterPage,
|
||||
SecuritySettingsPage,
|
||||
SettingsLayout,
|
||||
StatusPage,
|
||||
} from '@/pages/lazyPages';
|
||||
|
||||
/** Таблица маршрутов: публичные страницы, защищённые и настройки. */
|
||||
export const routes = [
|
||||
{
|
||||
path: '/',
|
||||
children: [
|
||||
{ index: true, element: <IndexRedirect /> },
|
||||
{ path: 'login', element: <LoginPage /> },
|
||||
{ path: 'register', element: <RegisterPage /> },
|
||||
{ path: 'status', element: <StatusPage /> },
|
||||
{
|
||||
element: <AuthGuard allowIncompleteOnboarding />,
|
||||
children: [{ path: 'onboarding', element: <OnboardingPage /> }],
|
||||
},
|
||||
{
|
||||
element: <AuthGuard />,
|
||||
children: [
|
||||
{
|
||||
path: 'app',
|
||||
element: <AppLayout />,
|
||||
children: [
|
||||
{ index: true, element: <Navigate to="empty" replace /> },
|
||||
{ path: 'empty', element: <NoGuildView /> },
|
||||
{ path: ':guildId', element: <GuildView /> },
|
||||
{ path: ':guildId/:channelId', element: <GuildView /> },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
element: <AuthGuard allowIncompleteOnboarding />,
|
||||
children: [
|
||||
{
|
||||
path: 'settings',
|
||||
element: <SettingsLayout />,
|
||||
children: [
|
||||
{ index: true, element: <Navigate to="profile" replace /> },
|
||||
{ path: 'profile', element: <ProfileSettingsPage /> },
|
||||
{ path: 'security', element: <SecuritySettingsPage /> },
|
||||
{ path: 'appearance', element: <AppearanceSettingsPage /> },
|
||||
{ path: 'instance', element: <InstanceSettingsPage /> },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: '*', element: <Navigate to="/" replace /> },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const router = createBrowserRouter(routes);
|
||||
Reference in New Issue
Block a user