Files

65 lines
1.9 KiB
JavaScript

const jwt = require('jsonwebtoken');
const { one } = require('../db');
const JWT_SECRET = process.env.DEPRECORE_JWT_SECRET || 'deprecore-local-development-secret';
function publicUser(user) {
if (!user) return null;
return {
id: user.id,
name: user.name,
email: user.email,
role: user.role,
teamId: user.team_id
};
}
function tokenFor(user) {
return jwt.sign({ sub: user.id, role: user.role, teamId: user.team_id }, JWT_SECRET, { expiresIn: '12h' });
}
function requireAuth(req, res, next) {
const header = req.headers.authorization || '';
const [, token] = header.split(' ');
if (!token) return res.status(401).json({ error: 'Authentication required' });
try {
const payload = jwt.verify(token, JWT_SECRET);
const user = one('SELECT * FROM users WHERE id = ? AND status = ?', [payload.sub, 'active']);
if (!user) return res.status(401).json({ error: 'User is inactive or missing' });
req.user = user;
return next();
} catch {
return res.status(401).json({ error: 'Invalid or expired token' });
}
}
function requireRole(...roles) {
return (req, res, next) => {
if (!roles.includes(req.user.role)) return res.status(403).json({ error: 'Insufficient access' });
return next();
};
}
// Capability-based guard: the user's role must grant at least one of the listed capabilities.
// Required lazily to avoid a load-time cycle (roles -> db -> ...).
function requireCapability(...capabilities) {
return (req, res, next) => {
const { capabilitiesForRole } = require('../services/roles');
const { capabilitySetIncludes } = require('../services/accessControl');
const granted = capabilitiesForRole(req.user.role);
if (!capabilities.some((cap) => capabilitySetIncludes(granted, cap))) {
return res.status(403).json({ error: 'Insufficient access' });
}
return next();
};
}
module.exports = {
publicUser,
requireAuth,
requireCapability,
requireRole,
tokenFor
};