Files
hub/audit.js

27 lines
1.4 KiB
JavaScript

// Audit log: who signed in, who was added or changed, what was downloaded. One JSON line per event in /data/audit.log
// (rotated at about 1 MB, keeping one older file). Contains no passwords, codes or message text.
const fs = require('fs');
const path = require('path');
const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, 'data');
const FILE = path.join(DATA_DIR, 'audit.log'), MAX = 1024 * 1024;
const ipOf = req => String((req && (req.headers['x-forwarded-for'] || (req.socket && req.socket.remoteAddress))) || '').split(',')[0].trim();
/** log('sign-in', { who: 'Nate', ip, detail: 'iPhone' }) */
function log(event, o = {}, req) {
try {
const line = JSON.stringify({ t: Date.now(), event, who: o.who || '', detail: o.detail || '', ip: o.ip || ipOf(req) }) + '\n';
try { if (fs.statSync(FILE).size > MAX) fs.renameSync(FILE, FILE + '.1'); } catch {}
fs.appendFileSync(FILE, line, { mode: 0o600 });
} catch (e) { console.error('[audit] could not write:', e.message); }
}
/** Newest first. */
function recent(n = 200) {
const rows = [];
for (const f of [FILE, FILE + '.1']) {
let text = ''; try { text = fs.readFileSync(f, 'utf8'); } catch { continue; }
for (const l of text.split('\n').reverse()) { if (!l) continue; try { rows.push(JSON.parse(l)); } catch {} if (rows.length >= n) return rows; }
}
return rows;
}
module.exports = { log, recent };