-
Notifications
You must be signed in to change notification settings - Fork 1
/
mongoose-cryptify.js
127 lines (104 loc) · 2.78 KB
/
mongoose-cryptify.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
Mongoose Cryptify
*/
var bcp = require('bcrypt'),
Promise = require('bluebird'); // jshint ignore:line
module.exports = Cryptify;
/**
* Cryptify Plugin Signature
*
* @param {Object} schema Mongoose Schema
* @param {Object} options Options Hash
* @return {Object} Mongoose Schema
*/
function Cryptify ( schema, options ) {
if( !options.paths ) {
throw new Error('Cryptify requires "paths" to be specified in the options hash');
}
var paths = options.paths.map(function ( path ) {
return path.split('.');
});
var workFactor = options.factor || 10;
schema.pre('save', function ( next ) {
var doc = this;
var parseDocument = function ( err, previous ) {
if( err ) {
next( err );
}
Promise.reduce(paths, function ( doc, path ) {
var raw = _getPathValue( doc, path ),
previousValue = ( previous ) ? _getPathValue( previous, path ) : false;
if( !raw || ( !!previousValue && previousValue === raw ) ) {
return doc;
}
return _generateHash( raw , workFactor ).then(function ( hash ) {
_setPathValue( doc, path, hash );
return doc;
});
}, doc).then(function ( newDoc ) {
next.call( newDoc );
}).catch( next );
};
if( doc.isNew ) {
parseDocument();
} else {
doc.constructor.findById(doc._id, parseDocument);
}
});
if ( options.disableComparator !== false ) {
schema.methods.compareHash = function ( rhs, path ) {
var modelPath = path || 'password';
return new Promise((resolve, reject) => {
bcp.compare(rhs, this[modelPath], function (err, res) {
if ( err ) {
return reject(err);
}
resolve(res);
})
});
};
}
return schema;
}
/**
* Generate Hash
*
* @private
*
* @param {String} raw
* @return {Promise}
*/
function _generateHash ( raw, workFactor ) {
return new Promise(function ( resolve, reject ) {
bcp.genSalt(workFactor, function ( err, salt ) {
if( err ) {
return reject( err );
}
bcp.hash(raw, salt, function ( err, hash ) {
if( err ) {
return reject( err );
}
resolve( hash );
});
});
});
}
/**
* Get Path Value
* @param {Object} recursive Object to traverse
* @param {Array} pathArray Array of paths
* @return {Mixed} Value
*/
function _getPathValue ( recursive, pathArray ) {
pathArray.forEach(function ( subpath ) {
recursive = recursive[ subpath ];
});
return recursive;
}
function _setPathValue ( recursive, pathArray, value ) {
var len = pathArray.length - 1;
for ( var i = 0; i < len; i++ ) {
recursive = recursive[ pathArray[ i ] ];
}
recursive[ pathArray[ len ] ] = value;
}