hashing password on update with mongoose
express, mongoose, node.js
Solution
I would use a pre `'save'` middleware:
AccountSchema.pre('save', function(next) {
this._doc.password = encrypt(this._doc.password);
next();
});
But doing this requires to use `save` also for updating a document:
Account.findById(id, function(err, doc) {
if (err) return false;
doc.password = "baloony2";
doc.save();
});
As stated in the documentation for update:
[...]
Although values are casted to their appropriate types when using update, the following are not applied:
- defaults
- setters
- validators
- middleware
If you need those features, use the traditional approach of first retrieving the document.
A verifiable example:
const crypto = require('crypto');
const algorithm = 'aes-256-ctr';
const password = 'aSjlkvS89';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
mongoose.connect("mongodb://localhost:33023/test_1");
mongoose.Promise = require('bluebird');
function encrypt(text) {
var cipher = crypto.createCipher(algorithm, password);
var crypted = cipher.update(text, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
}
// SCHEMA -------------------------------------------------
var AccountSchema = new Schema({
name: {
type: String,
unique: true
},
password: String
});
var id;
AccountSchema.pre('save', function(next) {
id = this._doc._id;
var pwd = this._doc.password;
console.log("hashing password: " + pwd);
this._doc.password = encrypt(pwd);
next();
});
// MODEL --------------------------------------------------
var Account = mongoose.model('Account', AccountSchema);
// DATA ---------------------------------------------------
new Account({
name: "john",
password: "baloony1"
})
.save()
.then(function(res) {
Account.findById(id, function(err, doc) {
if (err) return false;
doc.password = "baloony2";
doc.save();
});
});
Extra info on the example:
- http://mongoosejs.com/docs/promises.html
- http://lollyrock.com/articles/nodejs-encryption/
Problem
For hashing a password before the object is saved to mongodb, i use the built-in pre-save hook comming with mongoose. But what is the correct way to handle hashing during updates? I tried to solve this with the pre-update hook, but this has some significant disadvantages, as it bypasses the model validation (e.g password length). That was my approach (shortened): ``` userSchema.pre('findOneAndUpdate', function (next) { let query = this; let update = query.getUpdate(); if (!update.password) { return next(); } hashPassword(update.password, function (err, hash) { //handle error or go on... //e.g update.password = hash; }); }); ``` So, what is the preferred way to solve this problem?