feat: UI-слой через /api/v1/* (ui/, views/ui-login.ejs, views/error.ejs)
- ui/api-client.js: HTTP-клиент к /api/v1/* (token из session.token) - ui/routes/auth.js: /login (mock-пресеты), /login-token (Bearer paste), /logout - ui/routes/entries.js: /, /add, /edit/:id, /delete/:id через API - ui/routes/admin.js: /admin, /admin/limit/:id, /audit через API - ui/routes/export.js: /export → проксирует /api/v1/entries/export - ui/index.js: createUiRouter() — requireToken + resolveUser middleware - views/ui-login.ejs: страница входа (mock + token) - views/error.ejs: шаблон для 403/404/500 API расширения: - GET /api/v1/entries теперь возвращает limit и used - GET /api/v1/entries?company=<id> (admin): записи другой компании - POST/PATCH/DELETE /api/v1/entries?company=<id> (admin): мутации для другой компании - GET /api/v1/entries/export: агрегированный CIDR (перенесён из монолита) - GET /api/v1/audit?company=<id>: журнал (перенесён из монолита) server.js: заменены src/routes/* на ui/createUiRouter(), убран CSRF
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* ui/routes/auth.js — /login, /logout для UI-слоя.
|
||||
*
|
||||
* Два режима:
|
||||
* Mock (DEV_MODE=true) — страница с пресетами MOCK_USERS.
|
||||
* Выбранный пользователь → генерируем mock Bearer token → session.token.
|
||||
*
|
||||
* Token (всегда доступен) — форма вставки реального Bearer токена от auth-api/KC.
|
||||
* Вставленный токен → session.token (без проверки подписи здесь,
|
||||
* API сам проверит при первом запросе).
|
||||
*
|
||||
* /logout — уничтожает сессию.
|
||||
*/
|
||||
|
||||
const { Router } = require('express');
|
||||
|
||||
function createRouter({ auth, MOCK_USERS, authLimiter }) {
|
||||
const router = Router();
|
||||
const devMode = () => process.env.DEV_MODE === 'true';
|
||||
|
||||
// GET /login
|
||||
router.get('/login', (req, res) => {
|
||||
if (req.session && req.session.token) return res.redirect('/');
|
||||
res.render('ui-login', {
|
||||
devMode: devMode(),
|
||||
MOCK_USERS: devMode() ? MOCK_USERS : [],
|
||||
error: req.query.error || null,
|
||||
returnTo: req.query.returnTo || '/',
|
||||
});
|
||||
});
|
||||
|
||||
// POST /login — mock user
|
||||
router.post('/login', authLimiter, (req, res) => {
|
||||
const { clientId, returnTo } = req.body;
|
||||
if (!clientId) return res.redirect('/login?error=Выберите+пользователя');
|
||||
|
||||
const user = MOCK_USERS.find(u => u.clientId === clientId);
|
||||
if (!user) return res.redirect('/login?error=Пользователь+не+найден');
|
||||
|
||||
const token = auth.issueMockToken({
|
||||
clientId: user.clientId,
|
||||
companyId: user.companyId || '00000000-0000-0000-0000-000000000001',
|
||||
companyName: user.companyName || user.clientId,
|
||||
email: user.email || user.clientId + '@mock.local',
|
||||
});
|
||||
|
||||
req.session.token = token;
|
||||
req.session.user = { clientId: user.clientId, email: user.email, isAdmin: user.isAdmin };
|
||||
res.redirect(returnTo || '/');
|
||||
});
|
||||
|
||||
// POST /login-token — вставить реальный Bearer токен
|
||||
router.post('/login-token', authLimiter, (req, res) => {
|
||||
const { token, returnTo } = req.body;
|
||||
if (!token || !token.trim()) return res.redirect('/login?error=Токен+не+может+быть+пустым');
|
||||
|
||||
req.session.token = token.trim();
|
||||
req.session.user = null; // заполнится при первом запросе к API
|
||||
res.redirect(returnTo || '/');
|
||||
});
|
||||
|
||||
// GET /logout
|
||||
router.get('/logout', (req, res) => {
|
||||
req.session.destroy(() => res.redirect('/login'));
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
module.exports = { createRouter };
|
||||
Reference in New Issue
Block a user