Modification des pages d'authentification

This commit is contained in:
2026-06-14 21:58:05 +02:00
parent dc28b12c27
commit 9f6363ec20
20 changed files with 2494 additions and 172 deletions
+101 -76
View File
@@ -939,7 +939,6 @@ db.exec('CREATE INDEX IF NOT EXISTS idx_corrections_plateforme ON corrections_s
}
}
export default db;
// ── Table user_preferences ───────────────────────────────────────────────────
// Stockage générique des préférences UI par utilisateur.
@@ -1671,85 +1670,111 @@ db.exec(`
console.log('[DB] Tables catégories/secteurs plateforme+investissement OK');
}
// ── Migration ponctuelle : correction date_cible aberrantes (>2100) ──────────
// Certains prêts différés importés ont une date_cible avec un siècle erroné.
// On recalcule date_souscription + duree_mois et on régénère la simulation.
// ── Migration : table de configuration SMTP ──────────────────────────────────
db.exec(`
CREATE TABLE IF NOT EXISTS smtp_config (
id INTEGER PRIMARY KEY CHECK (id = 1),
enabled INTEGER NOT NULL DEFAULT 0,
host TEXT NOT NULL DEFAULT '',
port INTEGER NOT NULL DEFAULT 587,
secure INTEGER NOT NULL DEFAULT 0,
email TEXT NOT NULL DEFAULT '',
username TEXT NOT NULL DEFAULT '',
password TEXT NOT NULL DEFAULT '',
allow_unauth INTEGER NOT NULL DEFAULT 0,
app_name TEXT NOT NULL DEFAULT 'Crowdlending Tracker',
app_url TEXT NOT NULL DEFAULT '',
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// ── Migration : email_verified sur users ─────────────────────────────────────
{
function fixAddMonths(isoDate, months) {
const [y, m, d] = isoDate.split('-').map(Number);
let nm = m + months;
let ny = y;
while (nm > 12) { nm -= 12; ny++; }
const maxDay = new Date(Date.UTC(ny, nm, 0)).getUTCDate();
const nd = Math.min(d, maxDay);
return `${String(ny).padStart(4,'0')}-${String(nm).padStart(2,'0')}-${String(nd).padStart(2,'0')}`;
}
const toFix = db.prepare(`
SELECT i.id, i.date_souscription, i.duree_mois,
i.montant_investi, i.taux_interet, i.type_remb, i.freq_interets,
i.date_premiere_echeance, i.date_debut_simul, i.echeance_fin_de_mois
FROM investissements i
WHERE i.statut IN ('en_cours','en_retard','procedure')
AND i.type_remb = 'differe'
AND i.date_cible > '2100-01-01'
AND i.duree_mois IS NOT NULL
`).all();
if (toFix.length > 0) {
const updateDate = db.prepare(`UPDATE investissements SET date_cible=?, updated_at=datetime('now') WHERE id=?`);
const fixAll = db.transaction(() => {
for (const inv of toFix) {
const newDate = fixAddMonths(inv.date_souscription, inv.duree_mois);
updateDate.run(newDate, inv.id);
generateSimul(db, { ...inv, date_cible: newDate });
console.log(`[DB] Fix date_cible id=${inv.id}${newDate}`);
}
});
fixAll();
console.log(`[DB] ${toFix.length} date_cible aberrantes corrigées.`);
const userCols = db.prepare('PRAGMA table_info(users)').all().map(c => c.name);
if (!userCols.includes('email_verified')) {
// DEFAULT 1 pour ne pas bloquer les comptes existants
db.exec('ALTER TABLE users ADD COLUMN email_verified INTEGER NOT NULL DEFAULT 1');
console.log('[DB] users.email_verified ajouté');
}
}
// ── Migration : table smtp_config ─────────────────────────────────────────
// ── Migration : table email_verification_tokens ───────────────────────────────
db.exec(`
CREATE TABLE IF NOT EXISTS email_verification_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// ── Migration : table password_reset_tokens ───────────────────────────────────
db.exec(`
CREATE TABLE IF NOT EXISTS password_reset_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// ── Migrations 2FA ────────────────────────────────────────────────────────────
{
db.exec(`
CREATE TABLE IF NOT EXISTS smtp_config (
id INTEGER PRIMARY KEY CHECK (id = 1),
enabled INTEGER NOT NULL DEFAULT 0,
host TEXT,
port INTEGER NOT NULL DEFAULT 587,
secure INTEGER NOT NULL DEFAULT 0,
email TEXT,
username TEXT,
password TEXT,
allow_unauth INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
// Seed row unique (id=1) si elle n'existe pas encore
const existing = db.prepare('SELECT id FROM smtp_config WHERE id = 1').get();
if (!existing) {
// Pré-remplir depuis les variables d'environnement si disponibles
db.prepare(`
INSERT INTO smtp_config (id, enabled, host, port, email, username, password)
VALUES (1, 0, ?, ?, ?, ?, ?)
`).run(
process.env.SMTP_HOST || null,
parseInt(process.env.SMTP_PORT || '587', 10),
process.env.SMTP_EMAIL || null,
process.env.SMTP_USERNAME || null,
process.env.SMTP_PASSWORD || null,
);
const userCols2 = db.prepare('PRAGMA table_info(users)').all().map(c => c.name);
if (!userCols2.includes('totp_secret')) {
db.exec('ALTER TABLE users ADD COLUMN totp_secret TEXT');
console.log('[DB] users.totp_secret ajouté');
}
if (!userCols2.includes('totp_enabled')) {
db.exec('ALTER TABLE users ADD COLUMN totp_enabled INTEGER NOT NULL DEFAULT 0');
console.log('[DB] users.totp_enabled ajouté');
}
// Ajout des colonnes app_name et app_url si absentes
const smtpCols = db.prepare('PRAGMA table_info(smtp_config)').all().map(c => c.name);
if (!smtpCols.includes('app_name'))
db.exec(`ALTER TABLE smtp_config ADD COLUMN app_name TEXT DEFAULT 'Crowdlending'`);
if (!smtpCols.includes('app_url'))
db.exec(`ALTER TABLE smtp_config ADD COLUMN app_url TEXT DEFAULT ''`);
console.log('[DB] Table smtp_config OK');
}
// Sessions temporaires 2FA (entre /login et /2fa/verify)
db.exec(`
CREATE TABLE IF NOT EXISTS two_fa_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
db.exec('CREATE INDEX IF NOT EXISTS idx_2fa_sess_token ON two_fa_sessions(token)');
// Codes OTP envoyés par email
db.exec(`
CREATE TABLE IF NOT EXISTS two_fa_email_codes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
code TEXT NOT NULL,
expires_at TEXT NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
db.exec('CREATE INDEX IF NOT EXISTS idx_2fa_email_uid ON two_fa_email_codes(user_id)');
// Appareils de confiance (30 jours)
db.exec(`
CREATE TABLE IF NOT EXISTS two_fa_trusted_devices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
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)');
console.log('[DB] Migrations 2FA OK');
export default db;