I am using node.js to build a small game and to store states/token i am using online database mongolab. I generate the token with the following function:
UserSchema.methods.generateAuthToken = function() {
var user = this;
var access = "auth";
var token = jwt.sign({_id: user._id.toHexString, access}, "abc123").toString();
user.tokens = user.tokens.concat({access, token});
return user.save().then(() => {
return token;
});
};
The save function is :
UserSchema.pre("save", function(next) {
var user = this;
console.log("Being saved");
if (user.isModified("password")) {
console.log("Being modified");
bcrypt.genSalt(5, (err, saltvalue) => {
bcrypt.hash(user.password, saltvalue, (err, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
If i stay at a certain page for sometime(delay) then database resets the token to empty array.
However i have inserted everywhere console.logs to see if the server is trying to reset the value but the database does it automatic.
If someone has knowledge about this kind of error,then it will be of great help.
Related
I do not know if the exact request in title is possible, but if not; i would really appreciate an alternate solution.
I have this pre save method of mongoose
ownerSchema.pre("save", function(next) {
const owner = this;
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(owner.password, salt, function(err, hash) {
// Store hash in your password DB.
owner.password = hash;
next();
});
});
});
When i save new user(owner) a hash is created successfully and all is good>
The problem occurs when i login. when i login i generate jwt with a mongoose custom method as below
ownerSchema.methods.generateToken = function(cb) {
var owner = this;
var token = jwt.sign(
{
_id: owner._id,
username: owner.username,
email: owner.email,
category: owner.category === 0 ? false : true,
phones: owner.phones,
address: owner.address
},
config.SECRET,
{ expiresIn: "1h" }
);
owner.token= token;
owner.save(function(err,owner){
if(err) return cb(err);
cb(null,owner);
})
};
as you see i generate token to send it in "res" and at the same time i add the new token to the record in the data base. all working fine till now and the response is returned successfully>
BUT!! while i performed save() in the generate token function to save the token>> the previous pre(save) function ran again, so that a new hash is generated for the password feild.
when i try to login again, the password had already changed from calling the pre save hashing function when generating the token in the first login.
Any workaround for solving this issue?
You could use isModified method on your 'password' field.
I use it in this way, only run bcrypt if the password property was changed:
UserSchema.pre('save', function (next) {
var user = this;
if (user.isModified('password')) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
I do not know if the exact request in title is possible, but if not; i would really appreciate an alternate solution.
I have this pre save method of mongoose
ownerSchema.pre("save", function(next) {
const owner = this;
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(owner.password, salt, function(err, hash) {
// Store hash in your password DB.
owner.password = hash;
next();
});
});
});
When i save new user(owner) a hash is created successfully and all is good>
The problem occurs when i login. when i login i generate jwt with a mongoose custom method as below
ownerSchema.methods.generateToken = function(cb) {
var owner = this;
var token = jwt.sign(
{
_id: owner._id,
username: owner.username,
email: owner.email,
category: owner.category === 0 ? false : true,
phones: owner.phones,
address: owner.address
},
config.SECRET,
{ expiresIn: "1h" }
);
owner.token= token;
owner.save(function(err,owner){
if(err) return cb(err);
cb(null,owner);
})
};
as you see i generate token to send it in "res" and at the same time i add the new token to the record in the data base. all working fine till now and the response is returned successfully>
BUT!! while i performed save() in the generate token function to save the token>> the previous pre(save) function ran again, so that a new hash is generated for the password feild.
when i try to login again, the password had already changed from calling the pre save hashing function when generating the token in the first login.
Any workaround for solving this issue?
You could use isModified method on your 'password' field.
I use it in this way, only run bcrypt if the password property was changed:
UserSchema.pre('save', function (next) {
var user = this;
if (user.isModified('password')) {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
} else {
next();
}
});
I'm trying to hash the password of admin in my site. I have searched and found out that this error is because of being null or undefined the value that we want to hash it.
here is my code, whenever I console.log(admin) it returns {}, I don't know why.
adminSchema.pre('save', (next) => {
var admin = this;
console.log(admin)
bcrypt.hash(admin.password, 10, (err, hash) => {
if (err) return next(err);
admin.password = hash;
next();
});
});
var adminModel = mongoose.model('Admin', adminSchema);
module.exports = adminModel;
server side code:
var adminModel = require('./../models/admins');
router.post('/register', (req, res) => {
var newAdmin = {
adminName: req.body.adminName,
faculty: req.body.faculty,
email: req.body.email,
password: req.body.password
}
adminModel.create(newAdmin, (err, admin) => {
if (err) {
console.log('[Admin Registration]: ' + err);
}
else {
console.log('[Admin Registration]: Done');
req.session.adminId = admin._id;
res.redirect('/admin/submitScore')
}
})
});
Unfortunately, I can't find the reason of that the console.log(admin) is empty. I would be thankful if anyone could help me.
The keyword this changes scope when used in arrow functions. See more here. This is not a problem in your express route, but in your mongoose middleware it is. Change your function to not use this or make an old fashioned function(){}
I am using passportjs to handle auth of my app.
Once the user is logged in, I want to add the possibility to change the password from inside the app.
this is in my controller:
$http.post('/change-my-password',{oldPassword: $scope.user.oldpassword, newPassword: $scope.user.newpassword})
.then(function (res) {
if (res.data.success) {
// password has been changed.
} else {
// old password was wrong.
}
});
and this is my route handler in express nodejs in backend:
router.post('/change-my-password', function (req, res) {
if (!req.isAuthenticated()) {
return res.status(403).json({
success: false
});
}
UserSchema.findById(req.user._id, function(err, user){
if (err) return res.status(200).json({success: false});
user.validatePassword(req.body.oldPassword, function(err) {
if (err){
return res.status(200).json({
success: false
});
}
user.setPassword(req.body.newPassword, function() {
if (err || !user) {
return res.status(200).json(
{
success: false
}
)
}
user.save(function(err) {
if (err) return res.status(200).json({success: false});
req.login(user, function (err) {
if (err) return res.status(200).json({success: false});
return res.status(200).json({success: true});
});
});
});
});
});
});
here is my user schema model:
// user model
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var bcrypt = require('bcrypt-nodejs');
var UserSchema = new Schema({
email: String,
password: String,
confirmStatus: Boolean,
token: String,
registerAt: Number
});
UserSchema.methods.validatePassword = function (password, callback) {
this.authenticate(password, callback);
};
UserSchema.plugin(passportLocalMongoose,
{
usernameField: 'email'
});
module.exports = mongoose.model('users', UserSchema);
the problem:
I find my user by Id in my mongoose schema UserSchema then I should check if the oldPassword is valid or not, and then I set the new password.
I successfully find the user and the set the new password. But the part that should check for comparison of the old password field, doesn't work at all. Whatever I enter in the old password field gets accepts as OK and that step is skipped. Whereas, it should throws an error saying that the old password is wrong.
I am also advised to use sanitizedUser in order not to show my salt and etc.
Question is: how can I first do the comparison check of the old password and then do the set new password step? If possible, how can I use the sanitize? And how can I check if the user is not entering the same password as the new password? or if possible, saying that the new password is very similar to the old one?
You can implement the it using the new feature added 3 days ago:
just use the changePassword method, and it handles it through this:
schema.methods.changePassword = function(oldPassword, newPassword, cb) {
if (!oldPassword || !newPassword) {
return cb(new errors.MissingPasswordError(options.errorMessages.MissingPasswordError));
}
var self = this;
this.authenticate(oldPassword, function(err, authenticated) {
if (err) { return cb(err); }
if (!authenticated) {
return cb(new errors.IncorrectPasswordError(options.errorMessages.IncorrectPasswordError));
}
self.setPassword(newPassword, function(setPasswordErr, user) {
if (setPasswordErr) { return cb(setPasswordErr); }
self.save(function(saveErr) {
if (saveErr) { return cb(saveErr); }
cb(null, user);
});
});
});
};
so in your code, you need to replace the validatePassword method by this:
user.changePassword(req.body.oldPassword,req.body.newPassword, function(err) {
if (err){
return res.status(200).json({
success: false
});
}
hope this works for you.
I am building an API using Restify and Mongoose for NodeJS. In the method below after finding the user and verifying their password, I am trying to save some login information before sending the response back to the user. The problem is the response will never return. If I place the response outside and after the save call, the data never gets persisted to MongoDB. Am I doing something wrong? And help would be great as I have been working on this for the past 2 days.
login: function(req, res, next) {
// Get the needed parameters
var email = req.params.email;
var password = req.params.password;
// If the params contain an email and password
if (email && password) {
// Find the user
findUserByEmail(email, function(err, user) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// If we found a user
if (user) {
// Verify the password
user.verifyPassword(password, function(err, isMatch) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// If it is a match
if (isMatch) {
// Update the login info for the user
user.loginCount++;
user.lastLoginAt = user.currentLoginAt;
user.currentLoginAt = moment.utc();
user.lastLoginIP = user.currentLoginIP;
user.currentLoginIP = req.connection.remoteAddress;
user.save(function (err) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// NEVER RETURNS!!!!
// Send back the user
res.send(200, user);
return next();
});
}
else {
res.send(new restify.InvalidCredentialsError("Email and/or password are incorrect."));
return next();
}
});
}
else {
res.send(new restify.InvalidCredentialsError("Email and/or password are incorrect."));
return next();
}
});
}
else {
res.send(new restify.MissingParameterError());
return next();
}
},
One cause of this issue can be if you have a pre save hook which errors silently.
If you find your model as a .pre('save' () => {...}) function then double check this method is reached after you call save, and that it returns without errors.
Documentation on mongoose middleware can be found here