Error: data and hash arguments required
i am doing simple, login signup and forgot password in node js using
bcrypt hash
code : for login
app.post('/login', (req, res) => {
console.log('login');
let {email, password} = req.body;
User.updateOne({email: email}, ' email password', (err, userData) => {
if (!err) {
let passwordCheck = bcrypt.compareSync(password, userData.password);
if (passwordCheck) {
console.log('login2');
req.session.user = {
email: userData.email,
id: userData._id
};
req.session.user.expires = new Date(Date.now() + 3 * 24 * 3600 * 1000);
res.status(200).send('You are logged in, Welcome!');
} else {
res.status(401).send('incorrect password');
console.log('login3');
}
} else {
res.status(401).send('invalid login credentials');
console.log('login4');
}
});
});
code for signUp :
app.post('/signup', (req, res) => {
let {email, password} = req.body;
let userData = {password: bcrypt.hashSync(password, 5, null), email };
console.log('out save');
let newUser = new User(userData);
newUser.save().then(error => {
if (!error) {
console.log('in save');
return res.status(200).json('signup successful');
} else {
if (error.code === 11000) {
return res.status(409).send('user already exist!');
} else {
console.log(JSON.stringigy(error, null, 2));
return res.status(500).send('error signing up user');
}
}
});
});
i have tried console logging few lines and turned out that the code doesn't go into signup
newUser.save();
tell me where i'm going wrong
The issue is with this line newUser.save().then(error => {. Do you notice the .then(). That is a resolved promise so it wouldn't be returning an error. Typically you would see something like this.
Promise()
.then((result) => {
// result is a resolved promise
})
.catch((error) => {
// error is a rejected promise
})
So you should try changing your code to this:
newUser.save()
.then(result => {
console.log('in save')
return res.status(200).json('signup successful')
})
.catch(error => {
if (error.code === 11000) {
return res.status(409).send('user already exist!')
} else {
console.log(JSON.stringigy(error, null, 2))
return res.status(500).send('error signing up user')
}
})
It looks like you're using mongoose, here is the API docs for Document.prototype.save() https://mongoosejs.com/docs/api.html#document_Document-save
Their documentation uses callback functions for the most part but if you scroll to the end of the .save() documentation you will see they show one example with a promise.
bcrypt.compareSync takes 2 parameters; passwordToCheck, passwordHash
You are getting error "bcrypt Error: data and hash arguments required"
This error means one or both parameters are either null or undefined,
In your case you need to make sure that password, userData.password are correctly going in function bcrypt.compareSync
Related
I'm trying to make email verification in my vue.js/express app.
I can create the user and send emails. But showing a message like "verification mail sent" won't work.
The error occurs when executing the code in the then() callback after the execution in DataService.
When registering the following functions are executed:
vuex
const actions = {
registerUser({
commit
}, user) {
commit('registerRequest', user)
return DataService.registerUser(JSON.stringify(user))
// HERE'S THE ERROR
.then(response => {
commit('confirmation', response.message)
setTimeout(() => {
state.status = {
confirmHere: ''
}
}, 4000);
})
.catch(...)
confirmation:
confirmation: (state, msg) => {
state.status = {
confirmHere: msg
}
},
DataService
registerUser(user) {
// Send email for registration
apiClient.post('/user/register/sendMail', user)
.then(res => {
return apiClient.post(`/user/register`, user)
})
.catch(err => {
throw err;
})
},
The sendmail function is using nodemailer to send an email and returns
res.status(200).json({
message: "success"
});
The register function in express is:
router.post('/register', async (req, res) => {
try {
if (req.body.username !== undefined && req.body.password !== undefined) {
let password = await bcrypt.hashSync(req.body.password, saltRounds);
let compareUser = await db.getObject({}, User, 'SELECT * FROM app_users WHERE username=? LIMIT 1', [req.body.username]);
if (compareUser !== undefined) {
res.status(409).json('User already exists');
return;
}
const tmp = {
username: req.body.username,
password: password
};
await db.query('INSERT INTO app_users SET ?', [tmp]);
let user = await db.getObject({}, User, 'SELECT * FROM app_users WHERE username=? LIMIT 1', [req.body.username]);
if (user === undefined)
res.status(500).json('Internal server error');
res.status(201).json({
"message": "Bestätigungs-Email gesendet."
});
} else {
res.sendStatus(400);
}
} catch (error) {
res.sendStatus(500);
}
});
You forgot to return the response from DataService.registerUser
// DataService.js
registerUser(user) {
// Send email for registration
return apiClient.post('/user/register/sendMail', user)
.then(res => {
return apiClient.post(`/user/register`, user)
})
.catch(err => {
throw err;
})
The issue is that your registerUser function doesn't return anything whereas you're expecting it to return a promise.
Change your registerUser to:
registerUser(user) {
// Send email for registration
return apiClient.post('/user/register/sendMail', user)
.then(res => {
return apiClient.post(`/user/register`, user)
})
}
(FYI in the example, I left the .throw out because it already gets handled by the Promise you return ;)
i'm trying to use findOneAndUpdate for change password on mongoose, it's work, database updated
but error message show
"error": "user.findOneAndUpdate is not a function"
this my routes
router.post('/changepass', async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOneAndUpdate({phone},{password})
await user.findOneAndUpdate();
res.send({ user });
} catch (err) {
console.log(err)
res.status(422).send({ error: err.message });
}
});
and this my userSchema
userSchema.pre('findOneAndUpdate', function(next) {
const update = this.getUpdate()
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(update.password, salt, (err, hash) => {
this.getUpdate().password = hash;
return next();
})
})
});
please help me, i'm stuck for hours on this
try removing this line await user.findOneAndUpdate(); This line is causing the error and as per official docs it should be not there
router.post('/changepass', async (req, res) => {
const { phone, password } = req.body;
try {
const user = await User.findOneAndUpdate({phone},{password})
res.send({ user });
} catch (err) {
console.log(err)
res.status(422).send({ error: err.message });
}
});
here is doc reference - https://mongoosejs.com/docs/tutorials/findoneandupdate.html
I'm not able to catch the rejected promise and I don't understand where I'm going wrong. Here's what I have
exports.signIn = (username, password) => {
return new Promise((resolve, reject) => {
pool.query(
"select * from user where username=? order by id asc limit 1",
[username],
(err, result, fields) => {
if (!err) {
console.log("user result: ", result);
if (result.length === 1) {
let user = result[0];
bcrypt.compare(password, user.password, (error, res) => {
if (error) {
reject(error);
}
if (res) {
console.log("user found: ",user.username);
resolve(user);
} else {
console.log("Incorrect password");
reject("Unauthorized Access");
}
});
} else {
console.log("user not found");
reject("Invalid username");
}
}
}
);
});
};
This is how I use the promise
app.post("/signin", (req, res, next) => {
let body = req.body;
let password = body.password;
let username = body.username;
db.signIn(username, password)
.catch(err => {
res.status(200).json({ err });
})
.then(result => {
console.log("signin: ", result);
res.status(200).json({ result });
});
});
When I enter a correct password, it resolves properly but when I enter a wrong password it still resolves with the signin console message and an UnhandledPromiseRejectionWarning warning. I really don't see where I'm going wrong, perhaps an extra eye will do.
You should use promise as :
app.post("/signin", (req, res, next) => {
let body = req.body;
let password = body.password;
let username = body.username;
db.signIn(username, password)
.then(result => {
console.log("signin: ", result);
res.status(200).json({ result });
}).catch(err => {
res.status(200).json({ err });
});
});
Because, after catch if you will add any number of then handling, it will execute them all.
I have an API / express router:
router.post("/signup", async function (req, res) {
try {
var user = await controllers.user.register(req.body.username, req.body.password);
req.session.user = user;
res.json(user);
} catch (e) {
res.status(500).json("DB Error");
}
});
Currently, on error, it returns 500 DB error. This is my controller:
function register(username, password) {
return new Promise((resolve, reject) => {
User.findOne({ username: username }).lean().exec((e, doc) => {
if (e) reject(e);
if (doc) {
reject("Username already exists.");
} else {
var user = new User({ username, password: hash(password) });
user.save((e) => {
if (e) reject(e);
else {
delete user.password;
resolve(user);
}
});
}
});
});
}
What's the right way to return a 400 if username already exists, and a 500 if it was a database error?
Mongoose already uses promises, the use of new Promise is promise construction antipattern.
Express doesn't have the concept of controllers, there are only route handlers and middlewares. Since register should be very aware of the way it will be used in a response, there may be no need for another level of abstraction above route handler. There will be no problem when a function has access to handler parameters and can form a response in-place.
It can be:
router.post("/signup", async function (req, res) {
try {
const { body, password } = req.body;
const user = await User.findOne({ username: username }).lean();
if (user) {
res.status(400).json("Username already exists");
} else {
...
res.json(user);
}
} catch (e) {
res.status(500).json("DB Error");
}
});
In case route handler needs to be reused in multiple places with some variations, it could be refactored to higher-order function or some other helper that is aware of original req and res parameters.
You can change the way you are rejecting the Promise. I'd suggest something like:
function register(username, password) {
return new Promise((resolve, reject) => {
User.findOne({ username: username }).lean().exec((e, doc) => {
if (e) reject(500);
if (doc) {
reject(400);
} else {
var user = new User({ username, password: hash(password) });
user.save((e) => {
if (e) reject(500);
else {
delete user.password;
resolve(user);
}
});
}
});
});
}
And in the route:
router.post("/signup", async function (req, res) {
try {
var user = await controllers.user.register(req.body.username, req.body.password);
req.session.user = user;
res.json(user);
} catch (e) {
res.status(e).json(e == 400 ? "Username already exists." : "DB Error");
}
});
I am using Bcrypt for hashing passwords and storing it in the database,
Bcrypt is returning false, when I retrieve the hashed password from the database, and compare with the typed user password.
I am using it under Promise, but bcrypt is returning false on the correct password
Here is the code:
userSchema.statics.findByCredentials = function(email, password) {
const User = this;
return User.findOne({email}).then((user) => {
if(!user) {
return Promise.reject();
}
// console.log(user.password);
return new Promise((resolve, reject) => {
bcrypt.compare(password, user.password, (err,res) => {
if(res) {
resolve(user);
}
else {
reject("Problem here");
}
console.log(res);
});
});
});
};
I am trying promise chain to the main file i.e server.js and return the details to the user, but it's not working.
Here is the route code of express:
app.post('/users/login', (req, res) => {
const body = _.pick(req.body, ['email', 'password']);
// res.send(body);
User.findByCredentials(body.email, body.password)
.then((user) => {
res.send(user);
}).catch((e) => res.send(e));
});
Thanks
Have you tried using the promise api for bcrypt?
It might look like this:
userSchema.statics.findByCredentials = function(email, password) {
const User = this;
return User.findOne({email}).then((user) => {
if(!user) {
return Promise.reject();
}
// console.log(user.password);
return bcrypt.compare(password, user.password)
.then(res => {
if (res) {
return user;
}
throw new Error('Problem here');
});
});
}
If not, you might be getting an error, so you could check the err argument to see if something came back from there. Other than that, as long as user.password is the hashed version of the original password, then it should be working.