Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef546a9dcb | ||
|
|
3d20c2a31d | ||
|
|
24f1d5af77 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ipwhitelist",
|
||||
"version": "0.5.163",
|
||||
"version": "0.5.167",
|
||||
"description": "IP WhiteList microservice for cloud provider",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -31,7 +31,6 @@ const { authLimiter } = require('./src/middleware/rateLimit');
|
||||
const { createSessionMiddleware } = require('./src/middleware/session');
|
||||
const { aggregateCIDRs } = require('./src/validators');
|
||||
const { CSP_DIRECTIVES } = require('./src/middleware/csp');
|
||||
const { createUiRouter } = require('./ui/index');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
@@ -102,46 +101,16 @@ async function start() {
|
||||
// JWKS endpoint для валидации токенов внешними сервисами (только в mock-режиме)
|
||||
if (auth.jwksHandler) app.get('/.well-known/jwks.json', auth.jwksHandler);
|
||||
|
||||
// ── /export — публичный (ВРЕМЕННО без авторизации) ───────────────────────
|
||||
// 🔮 КОГДА Keycloak SSO: заменить на app.use('/export', auth.bearerMiddleware, ...)
|
||||
app.get('/export',
|
||||
/* 🔮 auth.bearerMiddleware, */
|
||||
async (req, res) => {
|
||||
try {
|
||||
const cidrs = await q.getExportCIDRs();
|
||||
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('[export] Error:', e);
|
||||
res.status(500).send('Ошибка экспорта');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ── OIDC-роуты (Keycloak) — активны ТОЛЬКО когда KC_CLIENT_ID задан ─────
|
||||
// В mock-режиме (сейчас): заглушки, работает ui/routes/auth.js
|
||||
// 🔮 В проде: задать KC_CLIENT_ID + KC_CLIENT_SECRET в .env
|
||||
// ── OIDC-роуты (Keycloak) ───────────────────────────────────────────────
|
||||
const { createRouter: createOidcRouter } = require('./src/routes/oidc');
|
||||
app.use('/', createOidcRouter({ auth }));
|
||||
|
||||
// ── REST API v1 (Bearer JWT, без сессий/CSRF) ─────────────────────────────
|
||||
const { createApiRouter } = require('./src/api/index');
|
||||
app.use('/api/v1', createApiRouter({ auth, q }));
|
||||
|
||||
// ── UI-слой: SSR через EJS, данные из /api/v1/* ───────────────────────────
|
||||
// Монтируется ПОСЛЕ /api/v1/ — не перехватывает API-запросы.
|
||||
// ── V2 — тестовый роутер (Keycloak → IAM → вывод) ─────────────────
|
||||
// Редирект корня на V2
|
||||
// ── V2 — основной код ─────────────────────────────────────────────────
|
||||
app.get('/', (req, res) => res.redirect('/v2/app'));
|
||||
// Редирект /export → /v2/export (для обратной совместимости)
|
||||
app.get('/export', (req, res) => res.redirect('/v2/export' + (req.originalUrl.includes('?') ? req.originalUrl.substring(req.originalUrl.indexOf('?')) : '')));
|
||||
const { createV2Router } = require('./v2/server');
|
||||
app.use('/v2', createV2Router());
|
||||
// Хранит Bearer token в сессии, рендерит те же views/*.ejs.
|
||||
app.use('/', createUiRouter({ auth, MOCK_USERS, authLimiter }));
|
||||
|
||||
// ── Общий обработчик ошибок ───────────────────────────────────────────────
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
||||
+32
-8
@@ -45,14 +45,6 @@ const modules = [
|
||||
'src/validators.js',
|
||||
'src/middleware/rateLimit.js',
|
||||
'src/middleware/csrf.js',
|
||||
'src/api/index.js',
|
||||
'src/api/routes/entries.js',
|
||||
'src/api/routes/admin.js',
|
||||
'ui/index.js',
|
||||
'ui/routes/auth.js',
|
||||
'ui/routes/entries.js',
|
||||
'ui/routes/admin.js',
|
||||
'ui/routes/export.js',
|
||||
'server.js',
|
||||
];
|
||||
|
||||
@@ -222,6 +214,38 @@ const { doubleCsrfProtection: dp, generateCsrfToken: gct } = csrfMiddleware.init
|
||||
test('initCsrf returns doubleCsrfProtection fn', typeof dp, 'function');
|
||||
test('initCsrf returns generateCsrfToken fn', typeof gct, 'function');
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
// 7. v2/src/config.js — IAM параметры
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
section('v2 config');
|
||||
|
||||
const v2config = require('../v2/src/config');
|
||||
test('iamApiBase default', v2config.iamApiBase, 'https://auth-api.ngcloud.ru/api/v1');
|
||||
test('version present', typeof v2config.version, 'string');
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
// 8. v2/src/validators — aggregateCIDRs
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
section('v2 aggregateCIDRs');
|
||||
|
||||
const v2validators = require('../v2/src/validators');
|
||||
test('256 /32 → /24', v2validators.aggregateCIDRs(Array.from({length:256}, (_,i)=>'1.1.0.'+i+'/32')).join(),
|
||||
'1.1.0.0/24');
|
||||
test('two /24 → /23', v2validators.aggregateCIDRs(['10.0.0.0/24','10.0.1.0/24']).join(),
|
||||
'10.0.0.0/23');
|
||||
test('two /32 → /31', v2validators.aggregateCIDRs(['192.168.1.0/32','192.168.1.1/32']).join(),
|
||||
'192.168.1.0/31');
|
||||
test('gap → 2 CIDRs', v2validators.aggregateCIDRs(['10.0.0.0/24','10.0.2.0/24']).length, 2);
|
||||
test('single /32', v2validators.aggregateCIDRs(['5.5.5.5/32']).join(), '5.5.5.5/32');
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
// 9. v1_legacy — старый код изолирован
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
section('v1_legacy isolation');
|
||||
|
||||
test('ui/index moved', !!(() => { try { require('../ui/index'); return false; } catch { return true; }})(), true);
|
||||
test('src/api/index moved', !!(() => { try { require('../src/api/index'); return false; } catch { return true; }})(), true);
|
||||
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────
|
||||
|
||||
+5
-2
@@ -141,9 +141,12 @@ function createV2Router() {
|
||||
router.use('/test', createTestRouter());
|
||||
}
|
||||
|
||||
// ── /v2/export — выгрузка CIDR (публичный, без авторизации) ──────
|
||||
// ── /v2/export — выгрузка CIDR (только для админов) ─────────────
|
||||
const { createExportRouter } = require('./src/export');
|
||||
router.use('/export', createExportRouter());
|
||||
router.use('/export', resolveContext, (req, res, next) => {
|
||||
if (!req.canAdmin) return res.status(403).send('Доступ запрещён — только для администраторов');
|
||||
next();
|
||||
}, createExportRouter());
|
||||
|
||||
// ── GET /v2/logout — выход только из whitelist (без KC SSO) ─────────
|
||||
router.get('/logout', (req, res) => {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
module.exports = {
|
||||
version: '0.5.163',
|
||||
version: '0.5.167',
|
||||
|
||||
// ── IAM ──────────────────────────────────────────────────────────────────
|
||||
iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user',
|
||||
|
||||
Reference in New Issue
Block a user