80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
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<EmailVerificationToken> {
|
|
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<AuthenticatedUser | null> {
|
|
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<void> {
|
|
// 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<boolean> {
|
|
return mailgunService.sendPasswordResetEmail(email, token);
|
|
}
|
|
}
|