refactor: шаг 4 — GET /export вынесен в src/routes/export.js
This commit is contained in:
@@ -40,30 +40,19 @@ async function start() {
|
|||||||
|
|
||||||
// ── Публичные маршруты (до auth.middleware) ──────────────────────────────────
|
// ── Публичные маршруты (до auth.middleware) ──────────────────────────────────
|
||||||
|
|
||||||
// k8s liveness probe
|
// k8s liveness probe — простая проверка что сервер жив
|
||||||
app.get('/healthz', (req, res) => res.send('OK'));
|
app.get('/healthz', (req, res) => res.send('OK'));
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
// /export — агрегированный список всех активных CIDR по всем компаниям.
|
// GET /export: агрегированный список CIDR, без авторизации.
|
||||||
// ТЗ: «авторизация не требуется, доступ ограничивается на сетевом уровне».
|
// src/routes/export.js содержит логику и комментарии.
|
||||||
// Маршрут регистрируется ДО auth.middleware чтобы не требовать jwt-cookie.
|
app.use(require('./src/routes/export').createRouter({
|
||||||
// exportLimiter: не более 20 запросов/мин с одного IP (защита от scraping).
|
q,
|
||||||
app.get('/export', exportLimiter, async (req, res) => {
|
exportLimiter,
|
||||||
try {
|
aggregateCIDRs,
|
||||||
// Получаем все активные CIDR без фильтра по компании
|
}));
|
||||||
const cidrs = await q.getExportCIDRs();
|
|
||||||
// Суммаризация: объединяем пересекающиеся диапазоны → минимальный набор
|
|
||||||
const aggregated = aggregateCIDRs(cidrs);
|
|
||||||
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
||||||
res.setHeader('Content-Disposition', 'inline; filename="whitelist.txt"');
|
|
||||||
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Export error:', e);
|
|
||||||
res.status(500).send('Export error');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Страница входа — отдаём форму выбора мок-пользователя.
|
// Страница входа — отдаём форму выбора мок-пользователя.
|
||||||
// Генерируем CSRF-токен и передаём в шаблон для скрытого поля формы.
|
// Генерируем CSRF-токен и передаём в шаблон для скрытого поля формы.
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* src/routes/export.js — публичный маршрут GET /export.
|
||||||
|
*
|
||||||
|
* Назначение: отдаёт агрегированный список всех активных CIDR (все компании)
|
||||||
|
* в виде текстового файла (один адрес/подсеть на строку).
|
||||||
|
*
|
||||||
|
* Особенности:
|
||||||
|
* - НЕ требует авторизации (ТЗ: «доступ ограничивается на сетевом уровне»).
|
||||||
|
* - Регистрируется ДО auth.middleware в server.js.
|
||||||
|
* - Ограничен exportLimiter: не более 20 запросов/мин с одного IP.
|
||||||
|
* - aggregateCIDRs объединяет перекрывающиеся диапазоны → минимальный набор.
|
||||||
|
*
|
||||||
|
* Паттерн «фабрика»:
|
||||||
|
* Вместо прямых require(зависимостей) получаем их через параметр deps.
|
||||||
|
* Это позволяет легко подменять зависимости в тестах (mock q, mock aggregateCIDRs).
|
||||||
|
*
|
||||||
|
* @param {{ q: object, exportLimiter: Function, aggregateCIDRs: Function }} deps
|
||||||
|
* @returns {import('express').Router}
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Router } = require('express');
|
||||||
|
|
||||||
|
function createRouter({ q, exportLimiter, aggregateCIDRs }) {
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// GET /export — агрегированный whitelist всех компаний в текстовом виде.
|
||||||
|
// exportLimiter ограничивает частоту запросов (20/мин) до проверки авторизации —
|
||||||
|
// это важно, так как маршрут публичный.
|
||||||
|
router.get('/export', exportLimiter, async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Получаем все активные CIDR без фильтра по компании
|
||||||
|
const cidrs = await q.getExportCIDRs();
|
||||||
|
|
||||||
|
// Суммаризация: объединяем пересекающиеся и смежные диапазоны
|
||||||
|
// Например: 192.168.0.0/25 + 192.168.0.128/25 → 192.168.0.0/24
|
||||||
|
const aggregated = aggregateCIDRs(cidrs);
|
||||||
|
|
||||||
|
// Content-Type: text/plain — чтобы браузер не пытался разбирать как HTML.
|
||||||
|
// Content-Disposition: inline — открывается в браузере, а не скачивается.
|
||||||
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||||
|
res.setHeader('Content-Disposition', 'inline; filename="whitelist.txt"');
|
||||||
|
|
||||||
|
// Один CIDR на строку. Если список пустой — возвращаем пустую строку (не ошибку).
|
||||||
|
res.send(aggregated.join('\n') + (aggregated.length ? '\n' : ''));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Export error:', e);
|
||||||
|
res.status(500).send('Export error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { createRouter };
|
||||||
Reference in New Issue
Block a user