mirror of
https://github.com/taobataoma/meanTorrent.git
synced 2026-01-17 04:42:22 +01:00
The user password salt should be encoded with Base64 before being saved to the database. The current code adds an unecessary step of converting the result of crypto.randomBytes() (which already returns a SlowBuffer) to a Base64 string and back again to a Buffer, and misses the final step of converting the Buffer's bytes back to a Base64 string. Because of this, the salt stored in the database is garbled. This is inconvenient when manipulating the data in a terminal or text editor. When generating the password hash, the crypto.pbkdf2Sync() method creates a new Buffer directly from the data supplied. Due to the incorrect encoding of the salt, entropy is lost at this step, weakening the security of stored passwords against brute force attacks.
151 lines
3.0 KiB
JavaScript
151 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
var mongoose = require('mongoose'),
|
|
Schema = mongoose.Schema,
|
|
crypto = require('crypto');
|
|
|
|
/**
|
|
* A Validation function for local strategy properties
|
|
*/
|
|
var validateLocalStrategyProperty = function(property) {
|
|
return ((this.provider !== 'local' && !this.updated) || property.length);
|
|
};
|
|
|
|
/**
|
|
* A Validation function for local strategy password
|
|
*/
|
|
var validateLocalStrategyPassword = function(password) {
|
|
return (this.provider !== 'local' || (password && password.length > 6));
|
|
};
|
|
|
|
/**
|
|
* User Schema
|
|
*/
|
|
var UserSchema = new Schema({
|
|
firstName: {
|
|
type: String,
|
|
trim: true,
|
|
default: '',
|
|
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
|
|
},
|
|
lastName: {
|
|
type: String,
|
|
trim: true,
|
|
default: '',
|
|
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
|
|
},
|
|
displayName: {
|
|
type: String,
|
|
trim: true
|
|
},
|
|
email: {
|
|
type: String,
|
|
trim: true,
|
|
default: '',
|
|
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
|
|
match: [/.+\@.+\..+/, 'Please fill a valid email address']
|
|
},
|
|
username: {
|
|
type: String,
|
|
unique: 'testing error message',
|
|
required: 'Please fill in a username',
|
|
trim: true
|
|
},
|
|
password: {
|
|
type: String,
|
|
default: '',
|
|
validate: [validateLocalStrategyPassword, 'Password should be longer']
|
|
},
|
|
salt: {
|
|
type: String
|
|
},
|
|
profileImageURL: {
|
|
type: String,
|
|
default: 'modules/users/img/profile/default.png'
|
|
},
|
|
provider: {
|
|
type: String,
|
|
required: 'Provider is required'
|
|
},
|
|
providerData: {},
|
|
additionalProvidersData: {},
|
|
roles: {
|
|
type: [{
|
|
type: String,
|
|
enum: ['user', 'admin']
|
|
}],
|
|
default: ['user']
|
|
},
|
|
updated: {
|
|
type: Date
|
|
},
|
|
created: {
|
|
type: Date,
|
|
default: Date.now
|
|
},
|
|
/* For reset password */
|
|
resetPasswordToken: {
|
|
type: String
|
|
},
|
|
resetPasswordExpires: {
|
|
type: Date
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Hook a pre save method to hash the password
|
|
*/
|
|
UserSchema.pre('save', function(next) {
|
|
if (this.password && this.password.length > 6) {
|
|
this.salt = crypto.randomBytes(16).toString('base64');
|
|
this.password = this.hashPassword(this.password);
|
|
}
|
|
|
|
next();
|
|
});
|
|
|
|
/**
|
|
* Create instance method for hashing a password
|
|
*/
|
|
UserSchema.methods.hashPassword = function(password) {
|
|
if (this.salt && password) {
|
|
return crypto.pbkdf2Sync(password, new Buffer(this.salt, 'base64'), 10000, 64).toString('base64');
|
|
} else {
|
|
return password;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create instance method for authenticating user
|
|
*/
|
|
UserSchema.methods.authenticate = function(password) {
|
|
return this.password === this.hashPassword(password);
|
|
};
|
|
|
|
/**
|
|
* Find possible not used username
|
|
*/
|
|
UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
|
|
var _this = this;
|
|
var possibleUsername = username + (suffix || '');
|
|
|
|
_this.findOne({
|
|
username: possibleUsername
|
|
}, function(err, user) {
|
|
if (!err) {
|
|
if (!user) {
|
|
callback(possibleUsername);
|
|
} else {
|
|
return _this.findUniqueUsername(username, (suffix || 0) + 1, callback);
|
|
}
|
|
} else {
|
|
callback(null);
|
|
}
|
|
});
|
|
};
|
|
|
|
mongoose.model('User', UserSchema);
|