fix(api): fail-safe прод-старт, транзакции и санитизация install-скриптов

- прод-режим отказывается стартовать без AUTH_REQUIRED и реальных секретов
  (opt-out через EVOFW_ALLOW_UNSAFE)
- CORS: whitelist через CORS_ORIGINS вместо origin:true; CSP для раздаваемого SPA
- транзакции для setAgentPolicySets, reorderPolicyRules, replaceResolvedForRule,
  replaceIpListEntries
- install-скрипты: Zod-валидация имени ссылки, экранирование $ и контрольных
  символов в RouterOS-рендере
- constant-time сравнение enroll-seed
- опциональное шифрование токена EvoBGP в БД (EVOFW_SECRET_KEY, AES-256-GCM)
  и маскирование per-list api_token в ответах
- graceful shutdown (SIGTERM/SIGINT) + тесты
This commit is contained in:
Denozordec
2026-09-20 18:51:47 +07:00
parent 45812fef6a
commit 40030ce06c
23 changed files with 493 additions and 69 deletions
+15 -2
View File
@@ -1,8 +1,21 @@
import type { FastifyInstance } from 'fastify'
import fp from 'fastify-plugin'
import type { AppConfig } from '../config.js'
async function corsPlugin(app: FastifyInstance) {
await app.register(import('@fastify/cors'), { origin: true })
async function corsPlugin(app: FastifyInstance, opts: { config: AppConfig }) {
const allowed = opts.config.corsOrigins
await app.register(import('@fastify/cors'), {
// The SPA is served same-origin (or via the Vite dev proxy), so by
// default only non-CORS (same-origin/server-side) requests pass.
// CORS_ORIGINS opens specific origins explicitly.
origin: (origin, cb) => {
if (!origin || allowed.includes(origin.replace(/\/$/, ''))) {
cb(null, true)
} else {
cb(null, false)
}
},
})
}
export default fp(corsPlugin, { name: 'cors' })