Reputation: 5079
I want to hash my users password on creation of an account in mongoose, is set up a hook to asynchrounously hash the password and set the _password attribute on the account.
var accountSchema = new mongoose.Schema({
name: {type : String},
_password : {type : String}
})
accountSchema.pre('save', true, function hook (next, done) {
next();
doHashPassword(done);
});
var Account = mongoose.model('Account', accountSchema);
Joe = new Account({name : "Joe", password : "secret"});
Joe.save();
How can i access the original arguments of Joe ({name : "Joe", password : "secret"}) in my hash function / hook ? Because the password is not mapped to the private attribute (this is intended in order to not accidently set the password in clear text)
thanks in advance
Upvotes: 1
Views: 826
Reputation: 5079
I found a solution to this problem by another question of me, where Noah posted a blogpost about this subject.
http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1
They use a pre save hook. I missed the point that the password is not saved in the moment i set password of Account to the cleartext password, it only exists within the memory. If i call save the password is overwritten asynchrounously and saved after the hash succeeded.
Thank you all for your help
Upvotes: 0
Reputation: 2218
You probably don't want to ever store the password anywhere in plain text, right? What you can do is create a virtual property on the schema which will hash the password immediately and add it to the model.
This is untested, but I'd do something like this:
var accountSchema = new mongoose.Schema({
name: {type : String},
_password : {type : String}
})
accountSchema.virtual('password')
// Setting the password property will put the hashed string into _password
.set(function(s) {
this._password = myHashFn(s);
})
// If you want to have a getter, implement it here
.get(function() {
return "********";
});
var Account = mongoose.model('Account', accountSchema);
Joe = new Account({name : "Joe", password : "secret"});
Joe.save();
Upvotes: 0
Reputation: 13799
I'm not 100% sure you can access a raw property that's not part of the schema.
I do know that at one point there was an option to enable / disable saving non-schema properties in the db, so be careful even sending { name: 'Joe', password: 'secret' } that such an option is disabled, or you'll accidentally create and set 'password.' It's been a few versions since I looked into that, so you may be fine.
Generally, instead of using regular 'set' for passwords, we create an instance method like:
var joe = new Account({ name: 'Joe' });
joe.setPassword('secret', function() {
joe.save();
});
This has the nice side-effect of encapsulating the password logic (instead of relying on a hook, which is less obvious) and making password management an explicit activity. Something like this might work for you:
accountSchema.methods.setPassword = function(plain, done) {
var self = this;
doHashPassword(plain, function(err, result) {
self._password = result;
if (done) done();
});
};
The mongoose docs have a guide on creating instance methods:
You can also add some sugar to this general case and make it chainable, or ignore the callback from setPassword(), or change setPassword() to savePassword() so you don't have to worry about saving after it's been done... etc. Lots of options.
Upvotes: 1