Amélioration 2FA
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user