email verification flow updated
This commit is contained in:
@@ -146,6 +146,11 @@ const User = sequelize.define(
|
||||
max: 100,
|
||||
},
|
||||
},
|
||||
verificationAttempts: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
allowNull: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
hooks: {
|
||||
@@ -208,31 +213,64 @@ User.prototype.resetLoginAttempts = async function () {
|
||||
};
|
||||
|
||||
// Email verification methods
|
||||
// Maximum verification attempts before requiring a new code
|
||||
const MAX_VERIFICATION_ATTEMPTS = 5;
|
||||
|
||||
User.prototype.generateVerificationToken = async function () {
|
||||
const crypto = require("crypto");
|
||||
const token = crypto.randomBytes(32).toString("hex");
|
||||
// Generate 6-digit numeric code (100000-999999)
|
||||
const code = crypto.randomInt(100000, 999999).toString();
|
||||
const expiry = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
||||
|
||||
return this.update({
|
||||
verificationToken: token,
|
||||
verificationToken: code,
|
||||
verificationTokenExpiry: expiry,
|
||||
verificationAttempts: 0, // Reset attempts on new code
|
||||
});
|
||||
};
|
||||
|
||||
User.prototype.isVerificationTokenValid = function (token) {
|
||||
const crypto = require("crypto");
|
||||
|
||||
if (!this.verificationToken || !this.verificationTokenExpiry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.verificationToken !== token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if token is expired
|
||||
if (new Date() > new Date(this.verificationTokenExpiry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Validate 6-digit format
|
||||
if (!/^\d{6}$/.test(token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use timing-safe comparison to prevent timing attacks
|
||||
try {
|
||||
const inputBuffer = Buffer.from(token);
|
||||
const storedBuffer = Buffer.from(this.verificationToken);
|
||||
|
||||
if (inputBuffer.length !== storedBuffer.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return crypto.timingSafeEqual(inputBuffer, storedBuffer);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Check if too many verification attempts
|
||||
User.prototype.isVerificationLocked = function () {
|
||||
return (this.verificationAttempts || 0) >= MAX_VERIFICATION_ATTEMPTS;
|
||||
};
|
||||
|
||||
// Increment verification attempts
|
||||
User.prototype.incrementVerificationAttempts = async function () {
|
||||
const newAttempts = (this.verificationAttempts || 0) + 1;
|
||||
await this.update({ verificationAttempts: newAttempts });
|
||||
return newAttempts;
|
||||
};
|
||||
|
||||
User.prototype.verifyEmail = async function () {
|
||||
@@ -241,6 +279,7 @@ User.prototype.verifyEmail = async function () {
|
||||
verifiedAt: new Date(),
|
||||
verificationToken: null,
|
||||
verificationTokenExpiry: null,
|
||||
verificationAttempts: 0,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user