daily pastebin goal
63%
SHARE
TWEET

Untitled

a guest Jan 20th, 2017 108 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var mongoose = require('mongoose'),
  2.         Schema = mongoose.Schema,
  3.         bcrypt = require('bcrypt-nodejs'),
  4.         SALT_WORK_FACTOR = 10,
  5.         // these values can be whatever you want - we're defaulting to a
  6.     // max of 5 attempts, resulting in a 2 hour lock
  7.     MAX_LOGIN_ATTEMPTS = 5,
  8.     LOCK_TIME = 2 * 60 * 60 * 1000;
  9.  
  10. var UserSchema = new Schema({
  11.     email: { type: String, required: true, index: { unique: true } },
  12.     password: { type: String, required: true },
  13.     name: { type: String },
  14.     admin: { type: Boolean },
  15.     public: { type: Boolean, default: false },
  16.     loginAttempts: { type: Number, required: true, default: 0 },
  17.     lockUntil: { type: Number }
  18. });
  19.  
  20.  
  21. UserSchema.virtual('isLocked').get(function() {
  22.     // check for a future lockUntil timestamp
  23.     return !!(this.lockUntil && this.lockUntil > Date.now());
  24. });
  25.  
  26. UserSchema.pre('save', function(next) {
  27.     var user = this;
  28.  
  29.     // only hash the password if it has been modified (or is new)
  30.     if (!user.isModified('password')) return next();
  31.  
  32.     // generate a salt
  33.     bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
  34.         if (err) return next(err);
  35.  
  36.         // hash the password using our new salt
  37.         bcrypt.hash(user.password, salt, null, function (err, hash) {
  38.             if (err) return next(err);
  39.  
  40.             // set the hashed password back on our user document
  41.             user.password = hash;
  42.             next();
  43.         });
  44.     });
  45. });
  46.  
  47. UserSchema.methods.comparePassword = function(candidatePassword, cb) {
  48.     bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
  49.         if (err) return cb(err);
  50.         cb(null, isMatch);
  51.     });
  52. };
  53.  
  54. UserSchema.methods.incLoginAttempts = function(cb) {
  55.     // if we have a previous lock that has expired, restart at 1
  56.     if (this.lockUntil && this.lockUntil < Date.now()) {
  57.         return this.update({
  58.             $set: { loginAttempts: 1 },
  59.             $unset: { lockUntil: 1 }
  60.         }, cb);
  61.     }
  62.     // otherwise we're incrementing
  63.     var updates = { $inc: { loginAttempts: 1 } };
  64.     // lock the account if we've reached max attempts and it's not locked already
  65.     if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
  66.         updates.$set = { lockUntil: Date.now() + LOCK_TIME };
  67.     }
  68.     return this.update(updates, cb);
  69. };
  70.  
  71. // expose enum on the model, and provide an internal convenience reference
  72. var reasons = UserSchema.statics.failedLogin = {
  73.     NOT_FOUND: 0,
  74.     PASSWORD_INCORRECT: 1,
  75.     MAX_ATTEMPTS: 2
  76. };
  77.  
  78. UserSchema.static('getAuthenticated', function(email, password, cb) {
  79.     this.findOne({ email: email }, function(err, user) {
  80.         if (err) return cb(err);
  81.  
  82.         // make sure the user exists
  83.         if (!user) {
  84.             return cb(null, null, reasons.NOT_FOUND);
  85.         }
  86.  
  87.         // check if the account is currently locked
  88.         if (user.isLocked) {
  89.             // just increment login attempts if account is already locked
  90.             return user.incLoginAttempts(function(err) {
  91.                 if (err) return cb(err);
  92.                 return cb(null, null, reasons.MAX_ATTEMPTS);
  93.             });
  94.         }
  95.  
  96.         // test for a matching password
  97.         user.comparePassword(password, function(err, isMatch) {
  98.             if (err) return cb(err);
  99.  
  100.             // check if the password was a match
  101.             if (isMatch) {
  102.                 // if there's no lock or failed attempts, just return the user
  103.                 if (!user.loginAttempts && !user.lockUntil) return cb(null, user);
  104.                 // reset attempts and lock info
  105.                 var updates = {
  106.                     $set: { loginAttempts: 0 },
  107.                     $unset: { lockUntil: 1 }
  108.                 };
  109.                 return user.update(updates, function(err) {
  110.                     if (err) return cb(err);
  111.                     return cb(null, user);
  112.                 });
  113.             }
  114.  
  115.             // password is incorrect, so increment login attempts before responding
  116.             user.incLoginAttempts(function(err) {
  117.                 if (err) return cb(err);
  118.                 return cb(null, null, reasons.PASSWORD_INCORRECT);
  119.             });
  120.         });
  121.     });
  122. });
  123.  
  124. module.exports = mongoose.model('User', UserSchema);
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top