Mongoose won't validate user - javascript

this is my user model and this is my js file that searches for email in database.
When passing the correct email to following code, it doesn't find the user in database although the email is correct. Should I do it somehow different?
workflow.on('patchUser', function(token, hash) {
var conditions = { email: req.body.email.toLowerCase() };
var fieldsToSet = {
resetPasswordToken: hash,
resetPasswordExpires: Date.now() + 10000000
};
req.app.db.models.User.findOneAndUpdate(conditions, fieldsToSet, function(err, user) {
if (err) {
return workflow.emit('exception', err);
}
if (!user) {
workflow.outcome.errors.push("Can't find any email match it");
return workflow.emit('response');
}
workflow.emit('sendEmail', token, user);
});
});
user is always null even thought the correct email is passed.

Related

Why find() using models won't work in signup route?

It's a simple signup route to store credentials in a mongoDB database but I miss something because the 2 else if won't work properly. I suspect it is my find().
The first else if returns me in Postman "error": "E11000 duplicate key error collection: vinted.users index: email_1 dup key: { email: \"jean#dpont.com\" }" and the second give me "email already exists".
Thanks in advance for your help
const express = require("express");
const router = express.Router();
const SHA256 = require("crypto-js/sha256");
const encBase64 = require("crypto-js/enc-base64");
const uid2 = require("uid2");
const User = require("../models/User");
router.post("/user/signup", async (req, res) => {
try {
const email = req.fields.email;
const username = req.fields.username;
const phone = req.fields.phone;
const password = req.fields.password;
const token = uid2(64);
const salt = uid2(16);
const hash = SHA256(password + salt).toString(encBase64);
const emailSearch = await User.find({ email: email });
if (!emailSearch || username !== null) {
const newUser = new User({
email: email,
account: {
username: username,
phone: phone,
},
password: password,
token: token,
hash: hash,
salt: salt,
});
await newUser.save();
res.status(200).json({
_id: newUser._id,
token: newUser.token,
account: newUser.account,
});
}
//problem under
else if (emailSearch) {
res.status(404).json({ message: "email already exists" });
} else if (username === null) {
res.status(404).json({ message: "please type a username" });
}
} catch (error) {
res.status(404).json({
error: error.message,
});
}
});
It looks like the issue is that if the username in the request body is not null, it's going to attempt to create a new User with that username regardless of whether a User exists with the same email - if (!emailSearch || username !== null).
It's generally best-practice to do as much input validation as you can before you start looking for records or creating new ones, as you will be able to avoid more Mongo errors and database actions if you can stop invalid actions before they're attempted. So in this case, check that the username is valid before looking for existing Users.
To solve this problem, I would move that last else-if to before you check whether a User exists with the same email. That way, once you determine whether the username is valid, then the only thing that you need to consider is existing Users before creating a new one. Something like this:
if (username === null) {
res.status(400).send({ message: "Error: Please provide a 'username'." });
}
const existingUserWithEmail = await User.find({ email: email });
if (!existingUserWithEmail) {
// Create the new User
} else {
res.status(400).send({ message: "Error: An account already exists with this email." });
}

why bcryptjs compare gives null value even though hash used is generated one?

FOr authentication purpose, I'm storing the hashed password in MongoDB when I try to compare this password for the same string bcryptjs throws a null value.
where it stores hashed password in Binary form for string '123'.
here is my generating code
import bcrypt
salt = bcrypt.gensalt()
password = bcrypt.hashpw(request.form['password'].encode('utf-8'), salt)
When I try to compare this with user entered password '123' I get a null value.
123 $2b$12$URN6pyD4SsOgIXALvr.jIuy2hvxlxva.ioamDNtMhAwvWb9/nLdhO null
here is my nodejs code with bcryptjs to compare user password with hashed database password
userSchema.methods.comparePassword = function (passw, cb) {
var user = this;
console.log((passw === user.password) ? 'passwords match' : 'passwords dont match' );
console.log(passw +" "+ user.password )
bcrypt.compare(passw, user.password, function (err, isMatch) {
console.log(passw +" "+ user.password +" " +isMatch )
if(err) {
return cb(err)
}
cb(null, isMatch)
})
}
I get a null value even though I enter the same string '123' also If I try checking with this online bcryptchecker website https://bcryptgenerator.com/ I get a match. What am I doing wrong exactly here?can someone point out my mistake ?
I think you are making the mistake in sending data to 'bcrypt.compare' method. You should make changes:
bcrypt.compare(user.password, 'password from database')
.then(status => console.log(status))
.catch (e) {
console.log(`Error: ${e}`);
}
For more details check this.

Authentication page

Im trying to build out my sign in page on a JavaScript, Node and Express app. Iv got the login correct, im getting a response when the users password and username match. So that part is fine. But once they match id like to take them to the home screen. However, im not sure how todo that. Iv found a res.redirect("route") but it returns: res.redirect is not a function. Ill add my code: ```app.post('/lgnfrm', function (req, res) {
var usrEmail= req.body.usrEmail;
var usrPassw = req.body.usrPass;
// INSERT WORKING
var sql = 'SELECT * FROM loginInfo WHERE email = (?)'
connection.query(sql, [usrEmail], function (err, res) {
// IF/ELSE CHECKING IF PASSWORD AND EMAIL MATCH DB VALUES
if (err) {
//
console.log(err)
} else {
// CHECKS IF THE EMAIL MATCHES DB
console.log("VALID EMAIL")
if (res.length > 0){
// IF EMAIL VALID, CHECK PASSWORD
if (res[0].passW == usrPassw) {
res.redirect("/home");
console.log("LOGIN SUCCESSFUL");
} else {
// INCORRECT PASSWORD
console.log("PASSWORD INCORRECT");
}
}
}
})
}) ```
app.post('/lgnfrm', function (request, response) {
var usrEmail= request.body.usrEmail;
var usrPassw = request.body.usrPass;
// INSERT WORKING
var sql = 'SELECT * FROM loginInfo WHERE email = (?)'
connection.query(sql, [usrEmail], function (err, res) {
// IF/ELSE CHECKING IF PASSWORD AND EMAIL MATCH DB VALUES
if (err) {
//
console.log(err)
} else {
// CHECKS IF THE EMAIL MATCHES DB
console.log("VALID EMAIL")
if (res.length > 0){
// IF EMAIL VALID, CHECK PASSWORD
if (res[0].passW == usrPassw) {
response.redirect("/home");
console.log("LOGIN SUCCESSFUL");
} else {
// INCORRECT PASSWORD
console.log("PASSWORD INCORRECT");
}
}
}
})
})

Getting [object, Object] instead of whole user data. What does that mean?

I am getting the [object,Object ] in my server terminal instead of whole user data . I do not know what does that mean... I think I did all perfectly but still unable to get the whole data. I specified of sailjs server.
How to get whole user data instead of [object,Object]?
module.exports = {
/**
* Check the provided email address and password, and if they
* match a real user in the database, sign in to Medool.
*/
login: function (req, res) {
// Try to look up user using the provided email address
User.findOne({
email: req.param('email')
}, function foundUser(err, user) {
if (err)
return res.negotiate(err);
if (!user)
return res.notFound();
// Compare password attempt from the form params to the encrypted password
// from the database (`user.password`)
require('machinepack-passwords').checkPassword({
passwordAttempt: req.param('password'),
encryptedPassword: user.encryptedPassword
}).exec({
error: function (err) {
return res.negotiate(err);
},
/*
If the password from the form params doesn't checkout w/ the encrypted
password from the database...
*/
incorrect: function () {
return res.notFound();
},
success: function () {
// Store user id in the user session
console.log("User form the login check" +user)
req.session.me = user.helpsterId;
console.log(req.session.me);
// All done- let the client know that everything worked.
return res.ok();
}
});
});
}
};
Output when lifted server is [object, Object]in console
Try it,
console.log(user);
console.log(JSON.stringify(user));
console.log("User form the login check" +user);
and write the result for us.

Meteor: check email does not exist in Meteor.users collection before creating an account

I have a form where users enter their email address and password into a join form. This creates the account but I now want to develop it further.
client.js:
Template.joinForm.events({
'submit .form-join': function(e, t) {
e.preventDefault();
var email = t.find('#email').value,
password = t.find('#password').value,
username = Random.id(),
array = [],
profile = {
nameOfArray: array
};
Accounts.createUser({
email: email,
username: username,
password: password,
profile: profile
}, function(error) {
if (error) {
alert(error);
} else {
Router.go('/');
}
});
}
});
Before creating a user account, how do you:
Check if the email variable from the joinForm does not already exist in the Meteor.users collection. Processing this on the server?
If email does exist, then reject user creation?
I have seen the new function and wondering if I can use this http://docs.meteor.com/#/full/accounts_validatenewuser
Accounts.validateNewUser(function (user) {
// pseudo if statement code
if (email not exist) {
// 1. create the user account and then
Accounts.sendVerificationEmail(userId, [email])
} else {
throw new Meteor.Error(403, "email address is already registered");
}
});
Thank you for reading this.
I'm unclear as to whether to use Accounts.createUser or Accounts.onCreateUser and which code should be on the client, and which on the server. My aim is to build the account securely, therefore, deny any other modification privileges during this process from the console.
The extra empty array nameOfArrayis now created on the server if the account is allowed to be created, ie, passing the validateNewUser function. Of course, you can add more validation checks for example, password length.
client.js:
Template.joinForm.events({
'submit .form-join': function(e, t) {
e.preventDefault();
var email = t.find('#email').value,
password = t.find('#password').value,
username = Random.id();
Accounts.createUser({
email: email,
username: username,
password: password,
profile: profile
}, function(error) {
if (error) {
alert(error.reason);
} else {
Router.go('/');
}
});
}
});
server.js:
Accounts.onCreateUser(function(options, user) {
var newEmail = user.emails[0].address;
console.log(newEmail);
var emailAlreadyExist = Meteor.users
.find({"emails.address": newEmail}, {limit: 1})
.count() > 0;
console.log(emailAlreadyExist + ' already exists');
if (emailAlreadyExist === true) {
throw new Meteor.Error(403, "email already registered");
} else {
profile = options.profile;
profile.nameOfArray = [];
user.profile = profile;
return user;
}
});
I've found that Accounts.createUser has it's own validation built in and checks for already existing email/login.
Meteor docs: Accounts.createUser:
If there are existing users with a username or email only differing in
case, createUser will fail.
Thus Accounts.onCreateUser doesn't even fire if Accounts.createUser email/login validation throws error.
The Accounts.validateNewUser function requires users to validate their email after submitting. It's basically that step where, after you sign up for something, before you can sign in you have to enter a code that's sent to you on your email or mobile device -- basically, it ensures that the user is who they say they are. It's what might prevent you from signing up with the email totallyfake#totally_not_a_real_place.com.
If I'm reading your question right, you're more interested in seeing if an email is unique than in seeing if the user actually owns that email account. You can do this with Accounts.onCreateUser, which runs on the server:
Called whenever a new user is created. Return the new user object, or throw an Error to abort the creation.
The full process will look something like this. On the client, exactly what you have:
Template.joinForm.events({
'submit .form-join': function(e, t) {
e.preventDefault();
var email = t.find('#email').value,
password = t.find('#password').value,
username = Random.id(),
array = [],
profile = {
nameOfArray: array
};
Accounts.createUser({
email: email,
username: username,
password: password,
profile: profile
}, function(error) {
if (error) {
alert(error);
} else {
Router.go('/');
}
});
}
});
Then, on the server, before the user is actually created, it will run the user through your onCreateUser function, and whatever you return will be inserted into the users collection:
Accounts.onCreateUser(function(options, user) {
var email = user.emails[0];
if (!email) { throw new Meteor.Error("You must provide a non-empty email"); // this may actually not be necessary -- createUser might do it for you
if (Meteor.users.find({emails: email}) {
throw new Meteor.Error("A user with email " + email + " already exists!");
}
... // whatever other transformation you might want
return user;
});
You might also check out the accounts-ui package, since depending on how much you want to do vary from a vanilla implementation of user accounts, a lot may already be done for you.
The Accounts.validateNewUser is used to check if the fields of the user object comply with the desired format, returning true or false accordingly.
To check if the email is already registered, I think you should include this verification in the Accounts.onCreateUser function (http://docs.meteor.com/#/full/accounts_oncreateuser).
Without having tested the code, you can try something like this:
Accounts.validateNewUser(function (user) {
// Check compliance of the user object fields, using check http://docs.meteor.com/#/full/check
});
Accounts.onCreateUser(function(options, user) {
if (options.profile){
user.profile = options.profile;
}
if (Meteor.users.find({email: user.email}).fetch == 0) {
if(Accounts.validateNewUser(user)){
Accounts.sendVerificationEmail(userId, [email]);
return user;
} else {
throw new Meteor.Error(403, "Error checking user fields");
} else {
throw new Meteor.Error(403, "email address is already registered");
}
}

Categories