'use strict'; /* Security / auth event logger → security_events (миграция 047). * * Парная утилита к utils/audit.js: * • audit() — осознанные привилегированные действия (Tier 3) в admin_audit_log * • logSecurity() — события безопасности/входа (Tier 1+2): аноним, большой объём, свой ретеншн * * Логирование НИКОГДА не должно ронять запрос — всё в try/catch. * Statement готовится лениво: server.js запускается отдельно от миграций, * поэтому таблицы может ещё не быть на момент require(). */ const db = require('../db/db'); let _stmt = null; function stmt() { if (!_stmt) { _stmt = db.prepare( `INSERT INTO security_events (category, event, user_id, email, ip, user_agent, method, route, detail) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)` ); } return _stmt; } function _ip(req) { return (req && (req.ip || req.socket?.remoteAddress)) || ''; } function _ua(req) { const ua = req?.headers?.['user-agent']; return ua ? String(ua).slice(0, 300) : ''; } function _route(req) { return String(req?.originalUrl || req?.url || '').split('?')[0]; } /** * Записать событие безопасности. * @param {object} opts * @param {object} [opts.req] Express request (для IP/UA/route/user) * @param {string} opts.category 'auth' | 'access_denied' | 'rate_limit' * @param {string} opts.event 'login.fail' | 'forbidden' | 'rate_limited' | ... * @param {number} [opts.userId] явный id (иначе берётся req.user.id) * @param {string} [opts.email] email из попытки/связанный * @param {string} [opts.detail] человекочитаемая деталь */ function logSecurity({ req, category, event, userId, email, detail } = {}) { try { const uid = userId != null ? userId : (req?.user?.id ?? null); stmt().run( category, event, uid, email || null, _ip(req), _ua(req), req?.method || null, _route(req), detail || null ); } catch (e) { console.error('[securityLog]', e.message); } } /* Эргономичные хелперы */ const logAuth = (req, event, extra = {}) => logSecurity({ req, category: 'auth', event, ...extra }); const logDenied = (req, event, detail) => logSecurity({ req, category: 'access_denied', event, detail }); const logRateLimit = (req, detail) => logSecurity({ req, category: 'rate_limit', event: 'rate_limited', detail }); module.exports = { logSecurity, logAuth, logDenied, logRateLimit };