Amélioration 2FA

This commit is contained in:
2026-06-14 22:13:33 +02:00
parent 13ec48a8f3
commit 402d690e96
4 changed files with 228 additions and 5 deletions
+14
View File
@@ -1775,6 +1775,20 @@ db.exec(`
db.exec('CREATE INDEX IF NOT EXISTS idx_2fa_dev_token ON two_fa_trusted_devices(token)');
db.exec('CREATE INDEX IF NOT EXISTS idx_2fa_dev_uid ON two_fa_trusted_devices(user_id)');
// ── Migration : user_agent + ip_address sur two_fa_trusted_devices ───────────
{
const devCols = db.prepare('PRAGMA table_info(two_fa_trusted_devices)').all().map(c => c.name);
if (!devCols.includes('user_agent')) {
db.exec('ALTER TABLE two_fa_trusted_devices ADD COLUMN user_agent TEXT');
console.log('[DB] two_fa_trusted_devices.user_agent ajouté');
}
if (!devCols.includes('ip_address')) {
db.exec('ALTER TABLE two_fa_trusted_devices ADD COLUMN ip_address TEXT');
console.log('[DB] two_fa_trusted_devices.ip_address ajouté');
}
}
console.log('[DB] Migrations 2FA OK');
export default db;
+48 -1
View File
@@ -501,7 +501,9 @@ router.post('/2fa/verify', async (req, res, next) => {
if (trustDevice) {
deviceToken = crypto.randomBytes(32).toString('hex');
const devExpires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
db.prepare('INSERT INTO two_fa_trusted_devices (user_id, token, expires_at) VALUES (?,?,?)').run(user.id, deviceToken, devExpires);
const ua = req.headers['user-agent'] || null;
const ip = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.socket?.remoteAddress || null;
db.prepare('INSERT INTO two_fa_trusted_devices (user_id, token, expires_at, user_agent, ip_address) VALUES (?,?,?,?,?)').run(user.id, deviceToken, devExpires, ua, ip);
}
const token = signToken({ sub: user.id, email: user.email });
@@ -513,4 +515,49 @@ router.post('/2fa/verify', async (req, res, next) => {
} catch (e) { next(e); }
});
// ════════════════════════════════════════════════════════════════════════════
// ── Appareils de confiance ───────────────────────────────────────────────
// ════════════════════════════════════════════════════════════════════════════
// GET /auth/trusted-devices — liste les appareils de confiance de l'utilisateur
router.get('/trusted-devices', requireAuth, (req, res, next) => {
try {
const currentToken = req.headers['x-device-token'] || null;
const devices = db.prepare(
"SELECT id, token, user_agent, ip_address, created_at, expires_at FROM two_fa_trusted_devices WHERE user_id=? AND expires_at > datetime('now') ORDER BY created_at DESC"
).all(req.user.id);
const result = devices.map(d => ({
id: d.id,
isCurrent: !!(currentToken && d.token === currentToken),
user_agent: d.user_agent,
ip_address: d.ip_address,
created_at: d.created_at,
expires_at: d.expires_at,
}));
res.json(result);
} catch (e) { next(e); }
});
// DELETE /auth/trusted-devices/:id — révoquer un appareil
router.delete('/trusted-devices/:id', requireAuth, (req, res, next) => {
try {
const id = parseInt(req.params.id, 10);
const dev = db.prepare('SELECT id FROM two_fa_trusted_devices WHERE id=? AND user_id=?').get(id, req.user.id);
if (!dev) throw new HttpError(404, 'Appareil introuvable.');
db.prepare('DELETE FROM two_fa_trusted_devices WHERE id=?').run(id);
res.json({ ok: true });
} catch (e) { next(e); }
});
// DELETE /auth/trusted-devices — révoquer tous les appareils
router.delete('/trusted-devices', requireAuth, (req, res, next) => {
try {
db.prepare('DELETE FROM two_fa_trusted_devices WHERE user_id=?').run(req.user.id);
res.json({ ok: true });
} catch (e) { next(e); }
});
export default router;