// ═══════════════════════════════════════════════════════════════════════════════ // V2 — тестовый роутер (монтируется в server.js как /v2) // Только: вход через Keycloak → вывод ответа IAM на экран // ═══════════════════════════════════════════════════════════════════════════════ 'use strict'; const express = require('express'); const config = require('./src/config'); const auth = require('./src/auth'); const crud = require('./src/crud'); const oidcConfig = { baseUrl: config.kcBaseUrl, clientId: config.kcClientId, clientSecret: config.kcClientSecret, redirectUri: config.appUrl.replace(/\/$/, '') + '/v2/callback', }; /** * createV2Router — создаёт роутер для монтирования в основной server.js. * Сессия используется общая, но ключи — с префиксом v2_ чтобы не пересекаться. */ function createV2Router() { // Автосоздание таблиц при первом обращении const { pool } = require('./src/db'); const { ensureSchema } = require('./src/db/schema'); ensureSchema(pool).catch(e => console.error('[v2:db] Schema error:', e.message)); const router = express.Router(); // ── GET /v2/ — главная (вывод IAM-данных) ─────────────────────────────── router.get('/', (req, res) => { if (!req.session.v2_user) { return res.redirect('/v2/login'); } const u = req.session.v2_user; res.send(` V2 — IAM Response

✅ Вход выполнен v${config.version}

Email: ${u.email}

clientId: ${u.clientId} (активная компания)

Компания: ${u.companyName}

isAdmin: ${u.isAdmin}

ФИО: ${u.fio || '—'}

Компаний: ${u.allClientIds ? u.allClientIds.length : 0} — ${(u.allClientIds || []).join(', ')}

${u.isImpersonated ? `

⚠️ Имперсонация: ${u.originalUserEmail} → ${u.email}

` : ''}

session.v2_user (полный объект)

${JSON.stringify(u, null, 2)}

Выйти

`); }); // ── GET /v2/login — редирект на Keycloak ──────────────────────────────── router.get('/login', (req, res) => { if (req.session.v2_user) return res.redirect('/v2/'); const state = auth.generateState(); req.session.v2_oidcState = state; const url = auth.buildAuthUrl({ ...oidcConfig, state }); console.log('[v2] → Keycloak'); res.redirect(url); }); // ── GET /v2/callback — Keycloak возвращает пользователя ────────────────── router.get('/callback', async (req, res) => { const { code, state } = req.query; if (!state || state !== req.session.v2_oidcState) { return res.status(403).send('Invalid state — possible CSRF attack'); } delete req.session.v2_oidcState; if (!code) { return res.status(400).send('Missing authorization code'); } try { console.log('[v2] Exchanging code...'); const result = await auth.login(code, oidcConfig, config.iamUrl); req.session.v2_user = result.sessionUser; req.session.v2_token = result.token; req.session.v2_idToken = result.idToken; console.log('[v2] ✅ Login OK:', result.sessionUser.email, result.sessionUser.clientId); res.redirect('/v2/'); } catch (err) { console.error('[v2] ❌ Login failed:', err.message); res.status(500).send(`

Ошибка входа

${err.message}\n\n${err.stack || ''}

Попробовать снова

`); } }); // ── CRUD (/v2/app) ──────────────────────────────────────────── router.use('/app', crud.createCrudRouter()); // ── GET /v2/logout ─────────────────────────────────────────────────────── router.get('/logout', (req, res) => { delete req.session.v2_user; delete req.session.v2_token; delete req.session.v2_idToken; res.redirect('/v2/'); }); return router; } module.exports = { createV2Router };