Advertisement
Guest User

Untitled

a guest
Jan 20th, 2017
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.10 KB | None | 0 0
  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);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement