9d3d431416
- Added account types and privileged account types constants. - Created admin user controller for updating user security fields. - Developed role assignment controller for managing user roles. - Implemented validation middleware for request schemas. - Defined user role and auth session models for database interactions. - Created services for authentication, email notifications, and OTP handling. - Developed OAuth service for Google and Apple authentication. - Added JWT utility functions for token generation and verification. - Implemented comprehensive tests for authentication, session management, and password policies. - Created migration for updating user schema and adding new tables for auth sessions and user identities.
106 lines
2.7 KiB
JavaScript
106 lines
2.7 KiB
JavaScript
// app/utils/emailVerification.util.js
|
|
|
|
const crypto = require("crypto");
|
|
const { sendMail } = require("../utils/mail.util");
|
|
const redis = require("../config/redisClient");
|
|
|
|
const EMAIL_VERIFICATION_TTL =
|
|
Number(process.env.EMAIL_VERIFICATION_TTL_SECONDS) || 1800;
|
|
|
|
const generateEmailVerificationToken = () => {
|
|
return crypto.randomBytes(32).toString("hex");
|
|
};
|
|
|
|
const hashEmailVerificationToken = (token) => {
|
|
return crypto.createHash("sha256").update(token).digest("hex");
|
|
};
|
|
|
|
const createEmailVerification = async (userId) => {
|
|
const previousKey = await redis.get(`email-verification-user:${userId}`);
|
|
if (previousKey) await redis.del(previousKey);
|
|
// 1. Generate raw token
|
|
const token = generateEmailVerificationToken();
|
|
|
|
// 2. Hash token
|
|
const tokenHash = hashEmailVerificationToken(token);
|
|
|
|
// 3. Create Redis key
|
|
const redisKey = `email-verification:${tokenHash}`;
|
|
|
|
await redis.set(redisKey, userId, "EX", EMAIL_VERIFICATION_TTL);
|
|
await redis.set(`email-verification-user:${userId}`, redisKey, "EX", EMAIL_VERIFICATION_TTL);
|
|
|
|
return token;
|
|
};
|
|
|
|
/**
|
|
* Check a verification token.
|
|
*/
|
|
const verifyEmailVerificationToken = async (token) => {
|
|
if (!token || typeof token !== "string") {
|
|
return null;
|
|
}
|
|
|
|
// 1. Hash token received from user
|
|
const tokenHash = hashEmailVerificationToken(token);
|
|
|
|
// 2. Build same Redis key
|
|
const redisKey = `email-verification:${tokenHash}`;
|
|
|
|
// 3. Search Redis
|
|
const userId = await redis.getdel(redisKey);
|
|
|
|
if (!userId) {
|
|
return null;
|
|
}
|
|
|
|
await redis.del(`email-verification-user:${userId}`);
|
|
|
|
return {
|
|
userId,
|
|
redisKey,
|
|
};
|
|
};
|
|
|
|
//send verification email to user
|
|
const sendVerificationEmail = async (email, firstName, verificationToken) => {
|
|
const confirmationLink = `${process.env.FRONTEND_URL}/verify-email?token=${verificationToken}`;
|
|
|
|
// Send email
|
|
await sendMail({
|
|
to: email,
|
|
|
|
subject: "Confirm Your ZUMRI Account",
|
|
|
|
templateName: "emailVerification",
|
|
|
|
templateVars: {
|
|
customer_name: firstName,
|
|
confirmation_link: confirmationLink,
|
|
},
|
|
|
|
text: `Hello ${firstName}, please verify your ZUMRI account using this link: ${confirmationLink}`,
|
|
});
|
|
};
|
|
|
|
const deleteEmailVerification = async (redisKey) => {
|
|
await redis.del(redisKey);
|
|
};
|
|
|
|
const consumeEmailVerificationToken = async (token) => {
|
|
if (!token || typeof token !== "string") return null;
|
|
const redisKey = `email-verification:${hashEmailVerificationToken(token)}`;
|
|
const userId = await redis.getdel(redisKey);
|
|
if (userId) await redis.del(`email-verification-user:${userId}`);
|
|
return userId;
|
|
};
|
|
|
|
module.exports = {
|
|
createEmailVerification,
|
|
verifyEmailVerificationToken,
|
|
sendVerificationEmail,
|
|
deleteEmailVerification,
|
|
consumeEmailVerificationToken,
|
|
hashEmailVerificationToken,
|
|
};
|