v0.5.172: удалён /debug-session, UNIQUE индекс, убраны test/dev IAM

This commit is contained in:
2026-06-22 19:00:10 +04:00
parent ff1f195a2d
commit e943b33a04
5 changed files with 7 additions and 52 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ipwhitelist", "name": "ipwhitelist",
"version": "0.5.171", "version": "0.5.172",
"description": "IP WhiteList microservice for cloud provider", "description": "IP WhiteList microservice for cloud provider",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
-20
View File
@@ -78,26 +78,6 @@ async function start() {
// k8s liveness probe — простая проверка что сервер жив // k8s liveness probe — простая проверка что сервер жив
app.get('/healthz', (req, res) => res.send('OK')); app.get('/healthz', (req, res) => res.send('OK'));
// 🔧 DEBUG: показать IAM-данные из сессии (убрать после теста!)
app.get('/debug-session', async (req, res) => {
if (!req.session || !req.session.user) return res.json({ error: 'no session' });
const { token, idToken, ...safe } = req.session;
// Последняя запись аудита для проверки impersonated_by
let lastAudit = null;
try {
const { getAudit } = require('./src/queries');
const audit = await getAudit(null);
lastAudit = audit.slice(0, 3);
} catch(e) { lastAudit = 'error: ' + e.message; }
res.json({
user: req.session.user,
hasToken: !!token,
tokenPreview: token ? token.slice(0, 50) + '...' : null,
tokenPayload: token ? (() => { try { const p = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString()); return { iss: p.iss, sub: p.sub, email: p.email, ClientID: p.ClientID, iat: p.iat }; } catch(e) { return 'decode error'; } })() : null,
lastAudit,
});
});
// JWKS endpoint для валидации токенов внешними сервисами (только в mock-режиме) // JWKS endpoint для валидации токенов внешними сервисами (только в mock-режиме)
if (auth.jwksHandler) app.get('/.well-known/jwks.json', auth.jwksHandler); if (auth.jwksHandler) app.get('/.well-known/jwks.json', auth.jwksHandler);
-30
View File
@@ -65,34 +65,6 @@ function createV2Router() {
} }
}); });
// ── GET /v2/iam_response_test — IAM test стенд (только админ) ─────
router.get('/iam_response_test', resolveContext, async (req, res) => {
if (!req.canAdmin) return res.status(403).send('Доступ запрещён');
const token = req.session && req.session.token;
if (!token) return res.redirect('/v2/login');
try {
const raw = await iamFetch(token, config.iamApiBase + '/auth/user');
res.set('Content-Type', 'text/html; charset=utf-8');
res.send(rawPage('IAM TEST', raw));
} catch (e) {
res.send('<h2>Ошибка IAM Test</h2><pre>' + e.message + '</pre>');
}
});
// ── GET /v2/iam_response_dev — IAM dev стенд (только админ) ───────
router.get('/iam_response_dev', resolveContext, async (req, res) => {
if (!req.canAdmin) return res.status(403).send('Доступ запрещён');
const token = req.session && req.session.token;
if (!token) return res.redirect('/v2/login');
try {
const raw = await iamFetch(token, config.iamApiBase + '/auth/user');
res.set('Content-Type', 'text/html; charset=utf-8');
res.send(rawPage('IAM DEV', raw));
} catch (e) {
res.send('<h2>Ошибка IAM Dev</h2><pre>' + e.message + '</pre>');
}
});
// ── GET /v2/iam-gateway-test — сравнение API (только админ) ──────── // ── GET /v2/iam-gateway-test — сравнение API (только админ) ────────
router.get('/iam-gateway-test', resolveContext, async (req, res) => { router.get('/iam-gateway-test', resolveContext, async (req, res) => {
if (!req.canAdmin) return res.status(403).send('Доступ запрещён'); if (!req.canAdmin) return res.status(403).send('Доступ запрещён');
@@ -279,8 +251,6 @@ function iamComparePage(results) {
html += '<a href="/v2/app">CRUD</a>'; html += '<a href="/v2/app">CRUD</a>';
html += '<a href="/v2/admin">Админка</a>'; html += '<a href="/v2/admin">Админка</a>';
html += '<a href="/v2/iam_response">IAM PROD</a>'; html += '<a href="/v2/iam_response">IAM PROD</a>';
html += '<a href="/v2/iam_response_test">IAM TEST</a>';
html += '<a href="/v2/iam_response_dev">IAM DEV</a>';
html += '</div>'; html += '</div>';
for (const [name, r] of Object.entries(results)) { for (const [name, r] of Object.entries(results)) {
+1 -1
View File
@@ -8,7 +8,7 @@
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════
module.exports = { module.exports = {
version: '0.5.171', version: '0.5.172',
// ── IAM ────────────────────────────────────────────────────────────────── // ── IAM ──────────────────────────────────────────────────────────────────
iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user', iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user',
+5
View File
@@ -41,6 +41,11 @@ async function ensureSchema(pool) {
deleted_at TIMESTAMPTZ deleted_at TIMESTAMPTZ
); );
-- Защита от дублей: уникальный CIDR в компании среди активных записей
CREATE UNIQUE INDEX IF NOT EXISTS idx_whitelist_entries_active_cidr
ON whitelist_entries(company_id, value_cidr)
WHERE deleted_at IS NULL;
-- Аудит: каждое действие с возможностью отследить имперсонацию -- Аудит: каждое действие с возможностью отследить имперсонацию
CREATE TABLE IF NOT EXISTS audit_log ( CREATE TABLE IF NOT EXISTS audit_log (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,