Files
ISDSS---Internal-Survailanc…/routes/logs.js
T

78 lines
3.3 KiB
JavaScript
Raw Normal View History

2026-09-13 20:12:28 +01:00
'use strict';
const express = require('express');
const { db } = require('../db');
const { log } = require('../lib/audit');
const { toDisplayDateTime } = require('../lib/dates');
const { requireAuth, requireAdmin } = require('../middleware/auth');
const { sendMail, adminEmails } = require('../lib/mailer');
const router = express.Router();
router.use(requireAuth, requireAdmin);
function query({ q, action, page, from, to }) {
const where = [];
const params = [];
if (q) { where.push('(actor LIKE ? OR detail LIKE ?)'); params.push(`%${q}%`, `%${q}%`); }
if (action) { where.push('action = ?'); params.push(action); }
if (page) { where.push('page = ?'); params.push(page); }
if (from) { where.push('ts >= ?'); params.push(from); }
if (to) { where.push('ts <= ?'); params.push(to); }
const sql =
'SELECT id, ts, actor, action, page, detail, ip FROM logs' +
(where.length ? ' WHERE ' + where.join(' AND ') : '') +
' ORDER BY ts DESC, id DESC';
return db.prepare(sql).all(...params);
}
router.get('/', (req, res) => {
const rows = query(req.query);
const actions = db.prepare('SELECT DISTINCT action FROM logs ORDER BY action').all().map((r) => r.action);
const pages = db.prepare('SELECT DISTINCT page FROM logs WHERE page IS NOT NULL ORDER BY page').all().map((r) => r.page);
res.json({ logs: rows.slice(0, 1000), total: rows.length, actions, pages });
});
function toCSV(rows) {
const head = ['id', 'timestamp', 'actor', 'action', 'page', 'detail', 'ip'];
const esc = (v) => `"${String(v == null ? '' : v).replace(/"/g, '""')}"`;
const lines = [head.join(',')];
for (const r of rows) {
lines.push([r.id, toDisplayDateTime(r.ts), r.actor, r.action, r.page, r.detail, r.ip].map(esc).join(','));
}
return lines.join('\r\n');
}
router.get('/export', (req, res) => {
const rows = query(req.query);
const csv = toCSV(rows);
log(req, 'LOGS_EXPORT', 'Logs', `Exported ${rows.length} log rows as CSV`);
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
res.setHeader('Content-Disposition', `attachment; filename="datahub-logs-${Date.now()}.csv"`);
res.send(csv);
});
router.post('/email', async (req, res) => {
const rows = query(req.body || {});
const csv = toCSV(rows);
const to = (req.body && req.body.to) || adminEmails().join(',');
if (!to) return res.status(400).json({ error: 'No recipient. Add an admin email or provide "to".' });
const html =
`<h2>Martinhal ISDSS — audit log export</h2>` +
`<p>${rows.length} log entries are attached as CSV.</p>` +
`<hr style="border:none;border-top:1px solid #d8d8d8">` +
`<p style="color:#8a8a8a;font-size:12px">© 2026 Martinhal IT - Joao Vaz - Version 1.5 Patch 0.2</p>`;
try {
const r = await sendMail({
to, subject: `ISDSS audit logs (${rows.length} entries)`, html,
context: 'Audit log export', actor: req.session.user.username,
attachments: [{ filename: `datahub-logs-${Date.now()}.csv`, content: csv }],
});
log(req, 'LOGS_EMAIL', 'Logs', `Emailed ${rows.length} log rows to ${to} ${r.delivered ? '(delivered)' : '(queued, no SMTP)'}`);
res.json({ ok: true, delivered: r.delivered, count: rows.length });
} catch (e) {
log(req, 'MAIL_ERROR', 'Logs', `Log email failed: ${e.message}`);
res.status(500).json({ error: e.message });
}
});
module.exports = router;