Initial commit
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import db from '../db/index.js';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'dev-secret-change-me';
|
||||
|
||||
export function signToken(payload) {
|
||||
return jwt.sign(payload, JWT_SECRET, {
|
||||
expiresIn: process.env.JWT_EXPIRES_IN || '7d',
|
||||
});
|
||||
}
|
||||
|
||||
export function requireAuth(req, res, next) {
|
||||
const header = req.headers.authorization || '';
|
||||
const [scheme, token] = header.split(' ');
|
||||
if (scheme !== 'Bearer' || !token) {
|
||||
return res.status(401).json({ error: 'Missing or invalid Authorization header' });
|
||||
}
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
req.user = { id: decoded.sub, email: decoded.email };
|
||||
next();
|
||||
} catch {
|
||||
return res.status(401).json({ error: 'Invalid or expired token' });
|
||||
}
|
||||
}
|
||||
|
||||
/** À utiliser après requireAuth. Refuse l'accès si l'utilisateur n'est pas admin. */
|
||||
export function requireAdmin(req, res, next) {
|
||||
const row = db.prepare('SELECT role FROM users WHERE id = ?').get(req.user.id);
|
||||
if (!row || row.role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Accès réservé aux administrateurs' });
|
||||
}
|
||||
req.user.role = 'admin';
|
||||
next();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ZodError } from 'zod';
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export function errorHandler(err, req, res, next) {
|
||||
if (err instanceof ZodError) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation error',
|
||||
details: err.flatten(),
|
||||
});
|
||||
}
|
||||
if (err.status) {
|
||||
return res.status(err.status).json({ error: err.message });
|
||||
}
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
|
||||
export class HttpError extends Error {
|
||||
constructor(status, message) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import db from '../db/index.js';
|
||||
import { HttpError } from './errorHandler.js';
|
||||
|
||||
/**
|
||||
* Resolves the active investisseur from the X-Investisseur-Id header (or query),
|
||||
* verifies it belongs to the authenticated user, and exposes it as req.investisseur.
|
||||
*
|
||||
* Routes that operate on investisseur-scoped data must use this middleware.
|
||||
*/
|
||||
export function requireInvestisseur(req, res, next) {
|
||||
const raw = req.header('X-Investisseur-Id') || req.query.investisseurId;
|
||||
const id = Number(raw);
|
||||
if (!id) throw new HttpError(400, 'Missing investisseur id (header X-Investisseur-Id)');
|
||||
|
||||
const row = db
|
||||
.prepare('SELECT id, nom, type_fiscal FROM investisseurs WHERE id = ? AND user_id = ?')
|
||||
.get(id, req.user.id);
|
||||
|
||||
if (!row) throw new HttpError(403, 'Investisseur not found or not owned by user');
|
||||
req.investisseur = row;
|
||||
next();
|
||||
}
|
||||
Reference in New Issue
Block a user