import { v4 as uuidv4 } from 'uuid'; import { EmailVerificationToken, AuthenticatedUser } from './auth.types'; import { mailgunService } from '../mailgun.service'; import { AccountStatus } from './auth.constants'; import { databaseService } from '../database'; import { tokenService } from './token.service'; const TOKEN_EXPIRY_HOURS = 24; export class EmailVerificationService { async generateVerificationToken( user: AuthenticatedUser ): Promise { const token = uuidv4().replace(/-/g, ''); // Generate a random token using UUID const expiresAt = new Date(); expiresAt.setHours(expiresAt.getHours() + TOKEN_EXPIRY_HOURS); const verificationToken: EmailVerificationToken = { userId: user._id, email: user.email || '', token, expiresAt, }; // Persist verification token via TokenService await tokenService.saveVerificationToken(verificationToken); // Send verification email via Mailgun if (user.email) { const emailSent = await mailgunService.sendVerificationEmail( user.email, token ); if (!emailSent) { console.warn('Failed to send verification email'); } } return verificationToken; } async validateVerificationToken( token: string ): Promise { const verificationToken = await tokenService.findVerificationToken(token); if (!verificationToken) { return null; } // Check if token is expired if (new Date() > new Date(verificationToken.expiresAt)) { return null; } // Find the user (in production, this would be a proper database lookup) const user = await databaseService.findUserByEmail(verificationToken.email); return user as AuthenticatedUser; } async markEmailVerified(user: AuthenticatedUser): Promise { // Update user in database const updatedUser = { ...user, emailVerified: true, status: AccountStatus.ACTIVE, }; await databaseService.updateUser(updatedUser); // Remove used token(s) for this user await tokenService.deleteVerificationTokensForUser(user._id); } async sendPasswordResetEmail(email: string, token: string): Promise { return mailgunService.sendPasswordResetEmail(email, token); } }