Files
wekan/server/lib/securityLog.js
T
Lauri Ojansivu 1d82ef8eae Security/speed/tests logging: store in the existing WeKan DB (no new files).
Per correction: use only the existing WeKan database via Meteor JavaScript
queries (works on FerretDB and MongoDB); do not create files/DBs under
WRITABLE_PATH; and have FerretDB report problems to WeKan rather than writing
itself.

- models/eventLog.js: one `eventlog` collection (stream: security|speed|tests).
- server/lib/{securityLog,speedLog,testLog}.js: thin wrappers that insert one
  document via EventLog.insertAsync (fire-and-forget, never throw).
- models/lib/securityLogFormat.js slimmed to just sanitizeDetail; remove the
  node:sqlite event store (server/lib/eventStore.js) and all file/path/schema
  helpers.
- Add a Tests stream: log anything that would fail an existing WeKan test.
- Design docs (WeKan.md, FerretDB.md) rewritten: DB-collection storage, grouped
  counts for the summary, Admin Reports read the collection, and FerretDB reports
  problems to WeKan which records them (no FerretDB DB/file writes).
- tests/securityLog.test.cjs updated (sanitizer + catalog + collection wiring +
  no-filesystem guards); verified via Python mirror.
2026-07-19 13:12:59 +03:00

53 lines
2.1 KiB
JavaScript

// ============================================================================
// WeKan security event logger (design: docs/Security/Remediation/WeKan.md)
// ----------------------------------------------------------------------------
// Single choke point every runtime security guard funnels through when it
// BLOCKS, SANITIZES or REMEDIATES a request (SSRF rejection, XSS scheme drop,
// forged-XFF ignore, export-authz denial, invite rate-limit, attachment/avatar
// upload rejection or sanitization, …).
//
// Records one document into the EXISTING WeKan database via a normal Meteor
// JavaScript query (models/eventLog.js, stream:'security'). No new files/DBs, so
// it works the same on FerretDB and MongoDB. BEST-EFFORT and NEVER throws into the
// caller: the insert is fire-and-forget and any error is swallowed. Server-only.
// ============================================================================
import EventLog from '/models/eventLog';
const { categoryFor } = require('/models/lib/securityCategories');
const { sanitizeDetail } = require('/models/lib/securityLogFormat');
function insert(doc) {
try {
const p = EventLog.insertAsync(doc);
if (p && typeof p.catch === 'function') p.catch(() => {});
} catch (e) {
if (process.env.DEBUG === 'true') console.warn('securityLog insert failed:', e && e.message);
}
}
// Record one security event. Never throws. Pass a catalog `key` (see
// models/lib/securityCategories) and/or explicit fields; explicit wins.
export function record(evt = {}) {
try {
const base = evt.key ? categoryFor(evt.key) : {};
const m = { ...base, ...evt };
const doc = {
stream: 'security',
at: new Date(),
severity: m.severity || 'info',
category: m.category || 'unknown',
bleed: m.bleed || 'Generic',
action: m.action || 'detected',
source: m.source || '',
cwe: m.cwe || '',
detail: sanitizeDetail(m.detail),
};
if (m.userId || m.userid) doc.userId = String(m.userId || m.userid);
insert(doc);
} catch (e) {
if (process.env.DEBUG === 'true') console.warn('securityLog.record failed:', e && e.message);
}
}
export default { record };