Files
core/src/features/auth/lib/email.js
T
2026-04-12 12:50:14 -04:00

234 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Email Verification and Password Reset
* Handles email verification tokens and password reset tokens
*/
import { create, findOne, deleteWhere } from '../../../core/database/crud.js';
import { generateToken, generateId } from './password.js';
import { sendAuthEmail } from '../../../core/email/index.js';
import { renderVerificationEmail, renderPasswordResetEmail, renderPasswordChangedEmail } from '../../../core/email/templates/index.js';
/**
* Create an email verification token
* @param {string} email - User email
* @returns {Promise<Object>} Verification object with token
*/
async function createEmailVerification(email) {
const token = generateToken(32);
const verificationId = generateId();
// Token expires in 24 hours
const expiresAt = new Date();
expiresAt.setHours(expiresAt.getHours() + 24);
// Delete any existing verification tokens for this email
await deleteWhere('zen_auth_verifications', {
identifier: 'email_verification',
value: email
});
const verification = await create('zen_auth_verifications', {
id: verificationId,
identifier: 'email_verification',
value: email,
token,
expires_at: expiresAt,
updated_at: new Date()
});
return {
...verification,
token
};
}
/**
* Verify an email token
* @param {string} email - User email
* @param {string} token - Verification token
* @returns {Promise<boolean>} True if valid, false otherwise
*/
async function verifyEmailToken(email, token) {
const verification = await findOne('zen_auth_verifications', {
identifier: 'email_verification',
value: email
});
if (!verification) return false;
// Verify token matches
if (verification.token !== token) return false;
// Check if token is expired
if (new Date(verification.expires_at) < new Date()) {
await deleteWhere('zen_auth_verifications', { id: verification.id });
return false;
}
// Delete the verification token after use
await deleteWhere('zen_auth_verifications', { id: verification.id });
return true;
}
/**
* Create a password reset token
* @param {string} email - User email
* @returns {Promise<Object>} Reset object with token
*/
async function createPasswordReset(email) {
const token = generateToken(32);
const resetId = generateId();
// Token expires in 1 hour
const expiresAt = new Date();
expiresAt.setHours(expiresAt.getHours() + 1);
// Delete any existing reset tokens for this email
await deleteWhere('zen_auth_verifications', {
identifier: 'password_reset',
value: email
});
const reset = await create('zen_auth_verifications', {
id: resetId,
identifier: 'password_reset',
value: email,
token,
expires_at: expiresAt,
updated_at: new Date()
});
return {
...reset,
token
};
}
/**
* Verify a password reset token
* @param {string} email - User email
* @param {string} token - Reset token
* @returns {Promise<boolean>} True if valid, false otherwise
*/
async function verifyResetToken(email, token) {
const reset = await findOne('zen_auth_verifications', {
identifier: 'password_reset',
value: email
});
if (!reset) return false;
// Verify token matches
if (reset.token !== token) return false;
// Check if token is expired
if (new Date(reset.expires_at) < new Date()) {
await deleteWhere('zen_auth_verifications', { id: reset.id });
return false;
}
return true;
}
/**
* Delete a password reset token
* @param {string} email - User email
* @returns {Promise<number>} Number of deleted tokens
*/
async function deleteResetToken(email) {
return await deleteWhere('zen_auth_verifications', {
identifier: 'password_reset',
value: email
});
}
/**
* Send verification email using Resend
* @param {string} email - User email
* @param {string} token - Verification token
* @param {string} baseUrl - Base URL of the application
*/
async function sendVerificationEmail(email, token, baseUrl) {
const verificationUrl = `${baseUrl}/auth/confirm?email=${encodeURIComponent(email)}&token=${token}`;
const appName = process.env.ZEN_NAME || 'ZEN';
const html = await renderVerificationEmail(verificationUrl, email, appName);
const result = await sendAuthEmail({
to: email,
subject: `Confirmez votre adresse courriel ${appName}`,
html
});
if (!result.success) {
console.error(`[ZEN AUTH] Failed to send verification email to ${email}:`, result.error);
throw new Error('Failed to send verification email');
}
console.log(`[ZEN AUTH] Verification email sent to ${email}`);
return result;
}
/**
* Send password reset email using Resend
* @param {string} email - User email
* @param {string} token - Reset token
* @param {string} baseUrl - Base URL of the application
*/
async function sendPasswordResetEmail(email, token, baseUrl) {
const resetUrl = `${baseUrl}/auth/reset?email=${encodeURIComponent(email)}&token=${token}`;
const appName = process.env.ZEN_NAME || 'ZEN';
const html = await renderPasswordResetEmail(resetUrl, email, appName);
const result = await sendAuthEmail({
to: email,
subject: `Réinitialisation du mot de passe ${appName}`,
html
});
if (!result.success) {
console.error(`[ZEN AUTH] Failed to send password reset email to ${email}:`, result.error);
throw new Error('Failed to send password reset email');
}
console.log(`[ZEN AUTH] Password reset email sent to ${email}`);
return result;
}
/**
* Send password changed confirmation email using Resend
* @param {string} email - User email
*/
async function sendPasswordChangedEmail(email) {
const appName = process.env.ZEN_NAME || 'ZEN';
const html = await renderPasswordChangedEmail(email, appName);
const result = await sendAuthEmail({
to: email,
subject: `Mot de passe modifié ${appName}`,
html
});
if (!result.success) {
console.error(`[ZEN AUTH] Failed to send password changed email to ${email}:`, result.error);
throw new Error('Failed to send password changed email');
}
console.log(`[ZEN AUTH] Password changed email sent to ${email}`);
return result;
}
export {
createEmailVerification,
verifyEmailToken,
createPasswordReset,
verifyResetToken,
deleteResetToken,
sendVerificationEmail,
sendPasswordResetEmail,
sendPasswordChangedEmail
};