diff --git a/attached_assets/image_1754927463961.png b/attached_assets/image_1754927463961.png new file mode 100644 index 0000000..f9df289 Binary files /dev/null and b/attached_assets/image_1754927463961.png differ diff --git a/reset-admin.js b/reset-admin.js new file mode 100644 index 0000000..827af71 --- /dev/null +++ b/reset-admin.js @@ -0,0 +1,37 @@ +#!/usr/bin/env node + +// Script pour réinitialiser le mot de passe admin en production +// Usage: node reset-admin.js [URL_PRODUCTION] + +const url = process.argv[2] || 'http://localhost:3000'; +const endpoint = `${url}/api/emergency-admin-reset`; + +const resetPassword = async () => { + try { + console.log(`🔄 Tentative de réinitialisation admin sur ${url}...`); + + const response = await fetch(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + secret: 'logiflow-admin-reset-2025' + }) + }); + + const result = await response.json(); + + if (response.ok) { + console.log('✅ Succès:', result.message); + console.log('📋 ID Admin:', result.adminId); + console.log('🔑 Identifiants: admin/admin'); + } else { + console.error('❌ Erreur:', result.error); + } + } catch (error) { + console.error('❌ Erreur de connexion:', error.message); + } +}; + +resetPassword(); \ No newline at end of file diff --git a/server/index.production.ts b/server/index.production.ts index e78f153..6b70bae 100644 --- a/server/index.production.ts +++ b/server/index.production.ts @@ -49,6 +49,50 @@ async function registerProductionRoutes(app: Express): Promise { }); }); + // Emergency admin reset endpoint (production only) + app.post('/api/emergency-admin-reset', async (req: Request, res: Response) => { + try { + const { secret } = req.body; + + // Require emergency secret (can be set via environment variable) + const emergencySecret = process.env.EMERGENCY_SECRET || 'logiflow-admin-reset-2025'; + if (secret !== emergencySecret) { + return res.status(403).json({ error: 'Invalid emergency secret' }); + } + + console.log('🚨 EMERGENCY: Admin password reset requested'); + + // Find existing admin + const existingAdmin = await storage.getUserByUsername('admin'); + if (existingAdmin) { + // Generate new password hash + const crypto = await import('crypto'); + const scrypt = await import('util').then(util => util.promisify(crypto.scrypt)); + const salt = crypto.randomBytes(16).toString("hex"); + const buf = (await scrypt('admin', salt, 64)) as Buffer; + const newPassword = `${buf.toString("hex")}.${salt}`; + + // Update admin password + await storage.updateUser(existingAdmin.id, { + password: newPassword, + passwordChanged: false + }); + + console.log('✅ EMERGENCY: Admin password reset to admin/admin'); + return res.json({ + success: true, + message: 'Admin password reset to admin/admin', + adminId: existingAdmin.id + }); + } else { + return res.status(404).json({ error: 'Admin user not found' }); + } + } catch (error) { + console.error('❌ EMERGENCY: Admin reset failed:', error); + return res.status(500).json({ error: 'Reset failed', details: (error as Error).message }); + } + }); + // Setup authentication setupLocalAuth(app); diff --git a/server/localAuth.production.ts b/server/localAuth.production.ts index 9b5398d..786eef6 100644 --- a/server/localAuth.production.ts +++ b/server/localAuth.production.ts @@ -78,6 +78,17 @@ async function comparePasswords(supplied: string, stored: string) { async function createDefaultAdminUser() { try { + // Check for force reset flag + const forceReset = process.env.FORCE_ADMIN_RESET === 'true'; + if (forceReset) { + console.log('🔄 FORCE_ADMIN_RESET detected, deleting existing admin user...'); + const existingAdmin = await storage.getUserByUsername('admin'); + if (existingAdmin) { + await storage.deleteUser(existingAdmin.id); + console.log('✅ Existing admin user deleted'); + } + } + const existingAdmin = await storage.getUserByUsername('admin'); if (!existingAdmin) { const hashedPassword = await hashPassword('admin'); @@ -99,15 +110,23 @@ async function createDefaultAdminUser() { passwordFormat: existingAdmin.password ? 'present' : 'missing' }); - // Check if password needs migration to new format - if (existingAdmin.password && !existingAdmin.password.includes('.')) { - console.log('🔄 Migrating admin password to new format...'); - try { - const newHashedPassword = await hashPassword('admin'); - await storage.updateUser(existingAdmin.id, { password: newHashedPassword }); - console.log('✅ Admin password migrated to new format'); - } catch (error) { - console.log('⚠️ Could not migrate password, will try multiple formats:', (error as Error).message); + // Test if current password works with 'admin' + if (existingAdmin.password) { + const testLogin = await comparePasswords('admin', existingAdmin.password); + if (!testLogin) { + console.log('🔄 Admin password incompatible with current system, forcing reset...'); + try { + const newHashedPassword = await hashPassword('admin'); + await storage.updateUser(existingAdmin.id, { + password: newHashedPassword, + passwordChanged: false + }); + console.log('✅ Admin password force-reset to: admin/admin'); + } catch (error) { + console.error('❌ Failed to reset admin password:', (error as Error).message); + } + } else { + console.log('✅ Admin password works with current system'); } } }