protect against sql injection, xss, csrf

This commit is contained in:
jackiettran
2025-09-16 12:27:15 -04:00
parent ce0b7bd0cc
commit a9fa579b6d
10 changed files with 1311 additions and 103 deletions

View File

@@ -104,17 +104,25 @@ const User = sequelize.define(
type: DataTypes.STRING,
allowNull: true,
},
loginAttempts: {
type: DataTypes.INTEGER,
defaultValue: 0,
},
lockUntil: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
hooks: {
beforeCreate: async (user) => {
if (user.password) {
user.password = await bcrypt.hash(user.password, 10);
user.password = await bcrypt.hash(user.password, 12);
}
},
beforeUpdate: async (user) => {
if (user.changed("password") && user.password) {
user.password = await bcrypt.hash(user.password, 10);
user.password = await bcrypt.hash(user.password, 12);
}
},
},
@@ -128,4 +136,41 @@ User.prototype.comparePassword = async function (password) {
return bcrypt.compare(password, this.password);
};
// Account lockout constants
const MAX_LOGIN_ATTEMPTS = 5;
const LOCK_TIME = 2 * 60 * 60 * 1000; // 2 hours
// Check if account is locked
User.prototype.isLocked = function() {
return !!(this.lockUntil && this.lockUntil > Date.now());
};
// Increment login attempts and lock account if necessary
User.prototype.incLoginAttempts = async function() {
// If we have a previous lock that has expired, restart at 1
if (this.lockUntil && this.lockUntil < Date.now()) {
return this.update({
loginAttempts: 1,
lockUntil: null
});
}
const updates = { loginAttempts: this.loginAttempts + 1 };
// Lock account after max attempts
if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked()) {
updates.lockUntil = Date.now() + LOCK_TIME;
}
return this.update(updates);
};
// Reset login attempts after successful login
User.prototype.resetLoginAttempts = async function() {
return this.update({
loginAttempts: 0,
lockUntil: null
});
};
module.exports = User;