Admins can filter and review curator_audit_log (date/time, actor, action, resource, details) via /api/audit against the environment DB. Co-authored-by: Cursor <cursoragent@cursor.com>
124 lines
3.1 KiB
JavaScript
124 lines
3.1 KiB
JavaScript
const pool = require('../db');
|
|
const { hasPermission, effectivePermissions } = require('../permissions');
|
|
|
|
async function loadStaffUser(userId) {
|
|
const { rows } = await pool.query(
|
|
`SELECT id, username, role, permissions, is_active
|
|
FROM users WHERE id = $1`,
|
|
[userId]
|
|
);
|
|
if (rows.length === 0) return null;
|
|
const row = rows[0];
|
|
return {
|
|
id: row.id,
|
|
username: row.username,
|
|
role: row.role,
|
|
permissions: row.permissions || [],
|
|
is_active: row.is_active !== false,
|
|
};
|
|
}
|
|
|
|
function attachStaff(req, user) {
|
|
req.curatorUser = {
|
|
id: user.id,
|
|
username: user.username,
|
|
role: user.role,
|
|
permissions: user.permissions,
|
|
is_active: user.is_active,
|
|
};
|
|
}
|
|
|
|
/** Any active staff account (admin or curator). */
|
|
async function requireCurator(req, res, next) {
|
|
const userId = req.session?.userId;
|
|
if (!userId) {
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
try {
|
|
const user = await loadStaffUser(userId);
|
|
if (!user || !user.is_active) {
|
|
req.session.destroy(() => {});
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
attachStaff(req, user);
|
|
next();
|
|
} catch (err) {
|
|
console.error('Auth middleware error:', err.message);
|
|
res.status(500).json({ error: 'Authentication failed' });
|
|
}
|
|
}
|
|
|
|
/** Active staff with a specific permission (admins always pass). */
|
|
function requirePermission(permission) {
|
|
return async (req, res, next) => {
|
|
const userId = req.session?.userId;
|
|
if (!userId) {
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
try {
|
|
const user = await loadStaffUser(userId);
|
|
if (!user || !user.is_active) {
|
|
req.session.destroy(() => {});
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
attachStaff(req, user);
|
|
|
|
if (!hasPermission(user, permission)) {
|
|
return res.status(403).json({ error: 'Permission denied' });
|
|
}
|
|
|
|
next();
|
|
} catch (err) {
|
|
console.error('Auth middleware error:', err.message);
|
|
res.status(500).json({ error: 'Authentication failed' });
|
|
}
|
|
};
|
|
}
|
|
|
|
/** Active staff with role admin only. */
|
|
async function requireAdmin(req, res, next) {
|
|
const userId = req.session?.userId;
|
|
if (!userId) {
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
try {
|
|
const user = await loadStaffUser(userId);
|
|
if (!user || !user.is_active) {
|
|
req.session.destroy(() => {});
|
|
return res.status(401).json({ error: 'Curator login required' });
|
|
}
|
|
|
|
attachStaff(req, user);
|
|
|
|
if (user.role !== 'admin') {
|
|
return res.status(403).json({ error: 'Admin access required' });
|
|
}
|
|
|
|
next();
|
|
} catch (err) {
|
|
console.error('Auth middleware error:', err.message);
|
|
res.status(500).json({ error: 'Authentication failed' });
|
|
}
|
|
}
|
|
|
|
function staffAuthPayload(user) {
|
|
return {
|
|
role: user.role,
|
|
username: user.username,
|
|
permissions: effectivePermissions(user),
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
requireCurator,
|
|
requirePermission,
|
|
requireAdmin,
|
|
loadStaffUser,
|
|
staffAuthPayload,
|
|
};
|