diff --git a/package.json b/package.json index a2583cb..5309b12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipwhitelist", - "version": "0.5.95", + "version": "0.5.96", "description": "IP WhiteList microservice for cloud provider", "main": "server.js", "scripts": { diff --git a/v2/history/2026-06-12.md b/v2/history/2026-06-12.md index f23987c..585f74d 100644 --- a/v2/history/2026-06-12.md +++ b/v2/history/2026-06-12.md @@ -677,3 +677,74 @@ WZ01112: entries=10 audit=10 dupes=False overLimit=False Предыдущие тесты (test.sh, router): 64 теста. Общий итог: **105 тестов, все пройдены** ✅ + + +--- + +## Полное тестирование всех комбинаций (0.5.95, 2026-06-13) + +### Новый мок-юзер: adm + +Добавлен для покрытия сценария «админ без имперсонации, много компаний»: + +| Поле | Значение | +|------|---------| +| email | admin@t.ru | +| clientId | WZ01112 | +| allClientIds | WZ01112, WZ03709, WZ09999 | +| isAdmin | true | +| isImpersonated | false | +| profiles | 3 компании (Nubes, Дочка, Третья) | + +### Матрица тестирования — все комбинации + +| # | Сценарий | Юзер | Действия | Результат | +|---|---------|------|----------|-----------| +| 1 | 1 компания, CRUD | u1 | add×2, blocked, list=2, edit, delete, after=1 | ✅ 7/7 | +| 2 | 2 компании, switch | u2 | add WZ20002, switch→WZ20001, add, list=1, switch→WZ20002, list=1 | ✅ 6/6 | +| 3 | Имперсонация, CRUD | imp | add×2, list=2, created_by=real@t.ru, edit, delete | ✅ 5/5 | +| 4 | Имперсонация, аудит | imp | audit: imp_by=admin@t.ru, user=real@t.ru, action=DELETE | ✅ 3/3 | +| 5 | Админ, 3 компании | adm | add WZ01112, switch→WZ03709, add, switch→WZ09999, add, list=1, created_by=admin@t.ru, switch→WZ01112, list=1 | ✅ 9/9 | +| 6 | Лимит 15 | u1 | 15 записей + 16-я fail | ✅ 1/1 | +| 7 | Лимит — другая компания | u2 | add после лимита u1 | ✅ 1/1 | +| 8 | Нормализация | u1 | /22 ok, /21 fail, IPv6 fail, normalize | ✅ 4/4 | +| 9 | UserFlow u1/u2/imp | u1,u2,imp | add, list, blocked, imp | ✅ 5/5 | +| 10 | Chaos (параллельно) | — | 40 ops, 4 компании | ✅ 1/1 | + +### Ключевые проверки + +| Проверка | Сценарий | Результат | +|----------|---------|-----------| +| created_by = originalUserEmail при имперсонации | imp add | ✅ real@t.ru | +| created_by = email админа БЕЗ имперсонации | adm add | ✅ admin@t.ru | +| impersonated_by в аудите | imp audit | ✅ admin@t.ru | +| user_email в аудите = originalUserEmail | imp audit | ✅ real@t.ru | +| switch компаний сохраняет изоляцию | u2 switch | ✅ | +| админ видит 3 компании и переключается | adm switch×3 | ✅ | +| лимит 15 не влияет на другие компании | u1+u2 | ✅ | + +### Итого: 42 тестовых сценария пройдены + +| Группа | Тестов | +|--------|--------| +| u1 (1 компания) | 7 | +| u2 (2 компании) | 6 | +| imp (имперсонация) | 8 | +| adm (админ, 3 компании) | 9 | +| Лимиты | 2 | +| Нормализация | 4 | +| UserFlow | 5 | +| Chaos | 1 | +| **Всего** | **42** | + +Плюс предыдущие: 105 тестов (test.sh + router + ранние). +**Общий итог: 147 тестов, все пройдены** ✅ + +### Что дальше + +| # | Задача | Статус | +|---|--------|--------| +| 1 | export/ — выгрузка CIDR | ❌ | +| 2 | EJS-шаблоны вместо inline HTML | ❌ | +| 3 | Auth end-to-end (KC callback) | ❌ | +| 4 | Интеграция в основной код (убрать v2_) | ❌ | diff --git a/v2/server.js b/v2/server.js index ffe753e..77d9e64 100644 --- a/v2/server.js +++ b/v2/server.js @@ -65,6 +65,10 @@ function createV2Router() { router.use('/test', createTestRouter()); } + // ── /v2/export — выгрузка CIDR (публичный, без авторизации) ────── + const { createExportRouter } = require('./src/export'); + router.use('/export', createExportRouter()); + // ── GET /v2/logout — редирект на основной выход ───────────────────── router.get('/logout', (req, res) => res.redirect('/logout')); diff --git a/v2/src/config/index.js b/v2/src/config/index.js index 3ebb8bf..a6b320d 100644 --- a/v2/src/config/index.js +++ b/v2/src/config/index.js @@ -9,7 +9,7 @@ // ═══════════════════════════════════════════════════════════════════════════════ module.exports = { - version: '0.5.95', + version: '0.5.96', // ── IAM ────────────────────────────────────────────────────────────────── iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user', diff --git a/v2/src/export/index.js b/v2/src/export/index.js new file mode 100644 index 0000000..28bcf55 --- /dev/null +++ b/v2/src/export/index.js @@ -0,0 +1,49 @@ +// ═══════════════════════════════════════════════════════════════════════════════ +// V2 — Экспорт CIDR (отдельный слой) +// +// ЭТО: выгрузка разрешённых CIDR в текстовом виде. +// НЕ: CRUD, валидация (использует db + validators). +// +// ЗАЧЕМ: +// 1. Отдать CIDR для firewall/nginx белого списка. +// 2. Агрегировать соседние CIDR в минимальный набор (экономия правил). +// 3. Поддержка фильтрации по компании (?companyId=X). +// +// ЦЕПОЧКА: GET /v2/export → q.getExportCIDRs → aggregateCIDRs → text/plain +// +// ПАРАМЕТРЫ: +// ?companyId=X — фильтр по компании (внутренний id) +// ?view=1 — показать в браузере (иначе — скачивание) +// ?filename=X — имя файла (по умолчанию white-list.txt) +// ═══════════════════════════════════════════════════════════════════════════════ + +const express = require('express'); +const q = require('../db/queries'); +const { aggregateCIDRs } = require('../validators'); + +function createExportRouter() { + const router = express.Router(); + + router.get('/', async (req, res) => { + try { + const companyId = req.query.companyId ? parseInt(req.query.companyId) : null; + const cidrs = await q.getExportCIDRs(companyId); + const aggregated = aggregateCIDRs(cidrs); + const text = aggregated.join('\n') + (aggregated.length ? '\n' : ''); + + res.set('Content-Type', 'text/plain; charset=utf-8'); + + const fname = (req.query.filename || 'white-list.txt').replace(/[^\w\-_. ]/g, '_'); + const disp = req.query.view === '1' ? 'inline' : 'attachment'; + res.set('Content-Disposition', disp + '; filename="' + fname + '"'); + res.send(text); + } catch (e) { + console.error('[v2:export] Error:', e); + res.status(500).send('Ошибка экспорта'); + } + }); + + return router; +} + +module.exports = { createExportRouter };