This commit is contained in:
2026-06-03 13:58:12 -05:00
commit 2f13b8c590
54 changed files with 5136 additions and 0 deletions

49
server/middleware/auth.js Normal file
View File

@@ -0,0 +1,49 @@
const jwt = require('jsonwebtoken');
const { one } = require('../db');
const JWT_SECRET = process.env.MIXEDASSETS_JWT_SECRET || 'mixedassets-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();
};
}
module.exports = {
publicUser,
requireAuth,
requireRole,
tokenFor
};

31
server/middleware/cors.js Normal file
View File

@@ -0,0 +1,31 @@
const cors = require('cors');
const { one } = require('../db');
function isLocalDevOrigin(origin) {
try {
const url = new URL(origin);
return ['localhost', '127.0.0.1'].includes(url.hostname);
} catch {
return false;
}
}
function createCorsMiddleware() {
const persistedCors = one('SELECT value FROM app_settings WHERE key = ?', ['cors_allowed_domains'])?.value || '';
const allowedOrigins = (process.env.MIXEDASSETS_CORS_ORIGINS || persistedCors || 'http://localhost:5173,http://127.0.0.1:5173')
.split(',')
.map((origin) => origin.trim())
.filter(Boolean);
return cors({
origin(origin, callback) {
if (!origin || allowedOrigins.includes(origin) || isLocalDevOrigin(origin)) return callback(null, true);
return callback(new Error('Origin is not allowed by MixedAssets CORS settings'));
},
credentials: true
});
}
module.exports = {
createCorsMiddleware
};