-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
84 lines (72 loc) · 2.56 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
'use strict';
var Promise = require('bluebird');
var defaults = require('defaults');
module.exports = function createdAt(schema, options) {
// http://devsmash.com/blog/implementing-max-login-attempts-with-mongoose
// Set the default options
options = options || {};
defaults(options, {
attemptsPath : 'attempts',
lockUntilPath : 'lockUntil',
isLockedPath : 'isLocked',
incMethod : 'incAttempts',
maxAttempts : 3,
lockTime : 1 * 60 * 60 * 1000 // 1 hour
});
// Set the path options
schema
.path(options.lockUntilPath, Number)
.path(options.attemptsPath, Number)
.path(options.attemptsPath)
.required(true)
.default(0);
// Set up the virtual 'isLocked' key
schema.virtual(options.isLockedPath).get(function () {
var lockUntil = this.get(options.lockUntilPath);
return Boolean(lockUntil && lockUntil > Date.now());
});
// Set up the increment method
schema.method(options.incMethod, function (returnVal, cb) {
// if returnVal is a function and cb isn't passed, make the first argument
// the callback instead
if (typeof returnVal === 'function' && !cb) {
cb = returnVal;
returnVal = undefined;
}
var now = Date.now();
var lockUntil = this.get(options.lockUntilPath);
var attempts = this.get(options.attemptsPath);
var isLocked = this.get(options.isLockedPath);
// if we have a previous lock that has expired, restart at 1 attempt
if (lockUntil && lockUntil < now) {
this.set(options.attemptsPath, 1);
this.set(options.lockUntilPath, undefined);
}
// Otherwise, we're incrementing
else {
// increment
this.set(options.attemptsPath, attempts + 1);
// Lock the account if we've reached max attempts and it's not locked
if (attempts + 1 >= options.maxAttempts && !isLocked) {
this.set(options.lockUntilPath, now + options.lockTime);
}
}
return saveAsync(this).then(function (model) {
// if there is a returnVal, then return that. Otherwise, return
// the model.
return typeof returnVal !== 'undefined' ? returnVal : model;
}).nodeify(cb);
});
};
// With the save, it doesn't return a promise, so there's that. No
// support for promises on the save until 4.0
// https://github.com/LearnBoost/mongoose/issues/1431
function saveAsync(doc) {
return new Promise(function (resolve, reject) {
doc.save(function (err, doc) {
/* istanbul ignore if: This should handle errors just fine */
if (err) { return reject(err); }
resolve(doc);
});
});
}