diff --git a/.env b/.env index 9c3a4710..e957e555 100755 --- a/.env +++ b/.env @@ -14,6 +14,9 @@ FACEBOOK_APP_SECRET=e6889f4339d140c218f1df177149893f JWT_SECRET=thetiptopsecret SESSION_SECRET=thetiptopsessionsecret +# Frontend URL (pour les liens dans les emails) +FRONTEND_URL=http://localhost:3000 + # Email Configuration (SMTP) SMTP_HOST=smtp.gmail.com SMTP_PORT=587 diff --git a/src/controllers/auth.controller.js b/src/controllers/auth.controller.js index 73d9aed5..bcf87ae9 100644 --- a/src/controllers/auth.controller.js +++ b/src/controllers/auth.controller.js @@ -6,6 +6,10 @@ import { pool } from '../../db.js'; import { AppError, asyncHandler } from '../middleware/errorHandler.js'; import { generateToken, generateJWT, getTokenExpiry, isExpired } from '../utils/helpers.js'; import { sendResetPasswordEmail, sendWelcomeEmail } from '../services/email.service.js'; +import dns from 'dns'; +import { promisify } from 'util'; + +const resolveMx = promisify(dns.resolveMx); /** * Inscription d'un nouvel utilisateur @@ -280,6 +284,70 @@ export const getMe = asyncHandler(async (req, res, next) => { }); }); +/** + * Vérifier si un email existe et est valide + * POST /api/auth/check-email + */ +export const checkEmail = asyncHandler(async (req, res, next) => { + const { email } = req.body; + + if (!email) { + return next(new AppError('Email requis', 400)); + } + + // Validation format email + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + return res.json({ + success: true, + isValid: false, + exists: false, + message: 'Format d\'email invalide', + details: { + formatValid: false, + domainValid: false, + mxRecords: false, + existsInDb: false + } + }); + } + + const domain = email.split('@')[1]; + let mxValid = false; + let mxRecords = []; + + // Vérification MX (enregistrements DNS du domaine) + try { + mxRecords = await resolveMx(domain); + mxValid = mxRecords && mxRecords.length > 0; + } catch (error) { + console.log(`❌ Pas d'enregistrements MX pour ${domain}:`, error.code); + mxValid = false; + } + + // Vérifier si l'email existe déjà en BDD + const existingUser = await pool.query('SELECT id FROM users WHERE email = $1', [email.toLowerCase()]); + const existsInDb = existingUser.rows.length > 0; + + // Résultat final + const isValid = mxValid && !existsInDb; + + res.json({ + success: true, + isValid, + exists: existsInDb, + message: existsInDb + ? 'Cet email est déjà utilisé' + : (mxValid ? 'Email valide et disponible' : 'Le domaine de cet email n\'existe pas'), + details: { + formatValid: true, + domainValid: mxValid, + mxRecords: mxValid, + existsInDb + } + }); +}); + export default { register, login, @@ -288,4 +356,5 @@ export default { resetPassword, logout, getMe, + checkEmail, }; diff --git a/src/routes/auth.routes.js b/src/routes/auth.routes.js index f3d89809..435cb2ee 100644 --- a/src/routes/auth.routes.js +++ b/src/routes/auth.routes.js @@ -21,6 +21,7 @@ router.post('/login', validate(loginSchema), authController.login); router.get('/verify-email/:token', authController.verifyEmail); router.post('/forgot-password', validate(forgotPasswordSchema), authController.forgotPassword); router.post('/reset-password', validate(resetPasswordSchema), authController.resetPassword); +router.post('/check-email', authController.checkEmail); // Routes OAuth router.post('/google', oauthController.googleLogin); diff --git a/src/services/email.service.js b/src/services/email.service.js index a9edf9ed..a4a4c674 100644 --- a/src/services/email.service.js +++ b/src/services/email.service.js @@ -6,44 +6,59 @@ import dotenv from 'dotenv'; dotenv.config(); -// Configuration du transporteur email -const createTransporter = () => { +// Configuration du transporteur email (créé à la demande pour éviter les problèmes de chargement) +let transporter = null; + +const getTransporter = () => { + if (transporter) return transporter; + // Pour le développement, utilisez un service de test comme Ethereal // Pour la production, utilisez un vrai service SMTP (Gmail, SendGrid, etc.) - if (process.env.NODE_ENV === 'development' && !process.env.SMTP_HOST) { - // Mode développement sans configuration SMTP console.log('⚠️ Mode développement: Les emails seront affichés dans la console'); return null; } - return nodemailer.createTransport({ + if (!process.env.SMTP_HOST || !process.env.SMTP_USER || !process.env.SMTP_PASS) { + console.error('❌ Configuration SMTP manquante:', { + host: !!process.env.SMTP_HOST, + user: !!process.env.SMTP_USER, + pass: !!process.env.SMTP_PASS + }); + return null; + } + + console.log('📧 Création du transporteur SMTP:', process.env.SMTP_HOST); + + transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: parseInt(process.env.SMTP_PORT) || 587, - secure: process.env.SMTP_PORT === '465', // true pour le port 465, false pour les autres + secure: process.env.SMTP_PORT === '465', auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS, }, tls: { - rejectUnauthorized: false // Ignore les erreurs de certificat SSL + rejectUnauthorized: false } }); -}; -const transporter = createTransporter(); + return transporter; +}; /** * Fonction générique pour envoyer un email */ const sendEmail = async ({ to, subject, html, text }) => { try { + const emailTransporter = getTransporter(); + // En mode dev sans SMTP, afficher l'email dans la console - if (!transporter) { - console.log('📧 Email qui aurait été envoyé:'); + if (!emailTransporter) { + console.log('📧 Email qui aurait été envoyé (pas de transporteur):'); console.log('To:', to); console.log('Subject:', subject); - console.log('Content:', text || html); + console.log('Content:', text ? text.substring(0, 200) : 'HTML content'); return { success: true, mode: 'dev' }; } @@ -55,12 +70,14 @@ const sendEmail = async ({ to, subject, html, text }) => { html, }; - const info = await transporter.sendMail(mailOptions); - console.log('✅ Email envoyé:', info.messageId); + console.log('📤 Envoi email à:', to, '- Sujet:', subject); + const info = await emailTransporter.sendMail(mailOptions); + console.log('✅ Email envoyé avec succès:', info.messageId); return { success: true, messageId: info.messageId }; } catch (error) { - console.error('❌ Erreur envoi email:', error); - throw new Error('Erreur lors de l\'envoi de l\'email'); + console.error('❌ Erreur envoi email:', error.message); + console.error('❌ Stack:', error.stack); + throw new Error('Erreur lors de l\'envoi de l\'email: ' + error.message); } };