For my registration page, I want to check for existing users before adding a new user to avoid duplicate usernames. For some reason, after I check if an existing username exists in the database, it does not run any of the code afterwards.
app.post("/register", (req, res) => {
const username = req.body.username;
const password = req.body.password;
var newuser = false;
db.query("SELECT * FROM users WHERE username = ?;", [username], (err, result) => {
if (err) {
res.send({err: err})
}
if (result.length == 0) {
newuser = true;
console.log(newuser + "one")
}
})
if (newuser) {
console.log(newuser + "two")
bcrypt.hash(password, saltRounds, (err, hash) => {
if (err)
console.log(err)
db.query(
"INSERT INTO users (username, password) VALUES (?,?)",
[username, hash],
(err, result) => {
if (err)
console.log(err);
}
)
})
}
})
In this example, the only output I get is "trueone" ... meaning that it evaluated result.length to 0 and set newuser = true.
It is because you are not waiting to the result of the first select. You can use async function or move the if(new user) condition into the select callback.
Related
I have a "user.json" file that looks like this. using java script I have to parse this file and then check this email and file combinations against user input
{
"something#somewhere.com": "maybe",
"john#beatles.uk": "lennonj!",
"paul#beatles.uk": "mccartney",
"mick#rollingstones.uk": "jaggerm!"
}
function lookUpCredentials(filePath, cb) {
fs.readFile(filePath, (err, fileData) => {
if (err) {
return cb && cb(err);
}
try {
const object = JSON.parse(fileData);
return cb && cb(null, object);
} catch (err) {
return cb && cb(err);
}
});
}
lookUpCredentials("./user.json", (err, data) => {
if (err) {
console.log(err);
return;
}
credentials = data;
});
app.post('/login', (req, res) => {
let username = req.body.username;
let password = req.body.password;
})
My question is How could I go about checking whether the input information is contained in the user.json file ?
You have to call lookupCredentials() in with the handler provided to app.post().
After the check you give back an answer to client via res.send() resp. res.end(). For each situation you want to stop request and give the client an answer.
The lookup and credentials check could look as follows:
app.post('/login', (req, res) => {
// If you do not change the variable later on, use const !
const username = req.body.username
const password = req.body.password
// respond if provided parameters are not given or emtpy.
if(!username || !password) {
res.status(400).end('No username or No password provided.')
return
}
// now use your created function to lookup the data:
// first read in file via
lookUpCredentials('./user.json', (err, credentials) => {
if (err) {
console.error(err)
// always send a response on error!
res.status(500).end('Error when looking up credentials file.')
return
}
// since you have an object with usernames as keys, we simply
// check if there is a value in the object
const stored_password = credentials[username]
// when no password was found, the username was not listed! => bad username
if(!stored_password) {
console.error('bad username', username)
res.status(403).end('Bad username')
return
}
// Check the password!
// when missmatched, inform client!
if(stored_password !== password) {
console.error('bad password received for user', username)
res.status(403).end('Bad password')
return
}
// No checks failed! We now can inform user he is logged in!
res.status(200).end('Login succeceded for user', username)
});
})
i am currently building a React application with Nodejs/Express Backend and try to implement a Login Authentication.
i register Users with Name, email, password and hash the password with bcrypt:
router.post('/register', async (req, res) => {
// Hashing
const salt = await bcrypt.genSalt(10)
const hashedPassword = await bcrypt.hash(req.body.regpassword, salt)
// Validate
const {error} = Joi.validate(req.body, schema)
var data = {
regname: req.body.regname,
regemail: req.body.regemail,
regpassword : hashedPassword
}
var sql ='INSERT INTO Users (regname, regemail, regpassword) VALUES (?,?,?)'
var params =[data.regname, data.regemail, data.regpassword]
db.run(sql, params, function (err, result) {
if (error){
res.status(400).send(error.details[0].message);
return;
}
res.json({
"answer": "Success",
})
res.status(200)
});
})
this works fine. But my /login route doesnt work:
router.post('/login', (req, res, next) => {
let sql = `SELECT * FROM Users WHERE regname = "${req.body.regname}" AND regpassword = "${req.body.regpassword}"`;
var x;
db.all(sql, (err, rows) => {
if (err) {
next(err);
return;
}
if (!rows) {
res.status(400);
res.send('Invalid username or password');
return
}
rows.forEach( async (row) => {
if (row.regname === req.body.regname && await bcrypt.compare(req.body.regpassword, row.regpassword) ) {
x = 1;
}
else {
x = 2;
db.close();
}
})
if (x === 1) {
res.json({
"answer":"Success",
})
}
else {
res.json(
{"answer":"Denied",
})
}
})
})
The salt needs to be stored in the database as well.
The /login route must then retrieve the regpassword and the salt from the database based on the req.body.regname. It then needs to run a await bcrypt.hash(req.body.regpassword, salt) exactly identical to the /register route and then compare the result of that hashing operation with the regpassword from the database. If the two hashes match then the user provided the correct password and you can display some confirmation / issue some session token / ...
i share my solution here, if someone needs it:
router.post('/login', (req, res) => {
const regname = req.body.regname;
const regpassword = req.body.regpassword;
const findUserByName = (regname, cb) => {
return db.get(`SELECT * FROM Users WHERE regname = ?`,[regname], (err, row) => {
cb(err, row)
});
}
findUserByName(regname, (err, user)=>{
if (err) return res.status(500).send('Server error!');
if (!user) return res.status(404).send('User not found!');
const result = bcrypt.compareSync(regpassword, user.regpassword);
if(!result) return res.status(401).send('Password not valid!');
res.status(200)
res.json({
"answer":"Success",
})
});
});
I have an application with a register and login form. I've managed to get the encrypted password into the database, but i can't seem to get it to work when I want to compare it when logging in. How would I implement bcrypt in my login post method?
Here is my register post where the password is stored successfully:
router.post('/register', (req, res) => {
bcrypt.hash(req.body.password, 10).then((hash) => {
let userData = req.body;
let user = new User(userData);
user.password = hash;
user.save((error, registeredUser) => {
if (error) {
console.log(error);
} else {
let payload = {subject: registeredUser._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
});
});
});
And here is my login post:
router.post('/login', (req, res) => {
let userData = req.body;
User.findOne({email: userData.email}, (error, user) => {
if (error) {
console.log(error);
} else {
if(!user) {
res.status(401).send('Invalid Email');
} else
if (user.password !== userData.password) {
res.status(401).send('Invalid Password');
} else {
let payload = {subject: user._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
}
});
});
Few things to note here.
Password are usually encrypted using one-way hashing function, which means you shouldn't be expecting to decrypt the saved password back to original text.
In a one way hash function, same hash (encryption output) is created for same input, every time. Eg: If you can encrypt the word "mysimplepassword", the output is going to be the same "xjjklqjlj34309dskjle4" (just a sample) every time.
The method of checking password in such scenarios is:
(a) Store the encrypted password (hash) when its first provided (usually during sign up)
(b) During login, receive the password as input and encrypt it using same encryption method, to obtain the hash
(c) Compare the hash
If you are using bcrypt, you can use bcrypt.compare() to perform these operations
I figured it out and am now comparing the hashed passwords successfully. Here is the new login post:
router.post('/login', (req, res) => {
let userData = req.body;
User.findOne({email: userData.email}, (error, user) => {
if (error) {
console.log(error);
} else {
if(!user) {
res.status(401).send('Invalid Email');
} else {
bcrypt.compare(req.body.password, user.password, function (err, result) {
if (result == false) {
res.status(401).send('Invalid Password');
} else {
let payload = {subject: user._id};
let token = jwt.sign(payload, 'secretKey');
res.status(200).send({token});
}
});
}}
});
});
Im trying to build a node api for change password,
User must type the currentPassword and the new password
when bcrypt.compare the new currentPassword with the stored on db, i got always false, whatever it's wrong or correct
const changePass = async (req, res, next) => {
//email and password
const CurrentPassword = req.body.currPassword
let password1 = ''+req.body.password1
let password2 = ''+req.body.password2
const hashedPassword = await bcrypt.hash(password1, 10);
let id = "" + req.body.id
User.findById( id )
.then(user => {
bcrypt.compare(CurrentPassword, user.password, (err, data) => {
if (err) throw err
if (data) {
User.findByIdAndUpdate(id, {password : hashedPassword }, {new: false}, (err) => {
if (err) throw err
})
} else {
return res.status(401).json({ msg: "Invalid" })
}
})
})
}
If you want to learn bcrypt I recommend you to visit bcrypt NPM because it will save you too much time later,
in your case I made some modification on your code in order to check for the current password OLD and then compare between the newPassword1 and the confirmation passwordConfirmation
feel free to use console.log('') when you have doubts about anything it will give you a good vision about your code status
const changePassword = async (req, res, next) => {
let id = req.body.nid;
if(id){
console.log('Im here')
const old = req.body.old;
const newP = req.body.newP;
const newP2 = req.body.newP2;
User.findById(id,(err,user)=>{
if(user){
console.log(user)
const hash = user.password;
bcrypt.compare(old,hash,function (err,res){
if(res){
if(newP === newP2){
bcrypt.hash(newP,10, (err,hash)=>{
user.password = hash;
user.save( (err,user) =>{
if(err) return console.error(err);
console.log(user.userName +' your password has been changed');
});
});
};
};
});
}
})
}
}
So as you can see. I am trying to take the previous password in the column and update it with the hashed version. For some reason the save on the document isn't firing right away. So I tried using async await and even creating a custom async await foreach to await the callback and the save. However, Mongoose seems to be waiting for all of the saves to come in before applying the save.
This is the error that I get.
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 505)
(node:2440)
const User = require("./models/User");
const bcrypt = require("bcryptjs");
const db = require("./config/keys").mongoURI;
async function hashIt(user) {
console.log(user);
bcrypt.genSalt(10, (err, salt) => {
if (err) console.log(err);
bcrypt.hash(user.Password, salt, async (err, hash) => {
if (err) throw err;
user.Password = hash;
const id = await user.save();
console.log(id);
})
});
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
async function mySeed() {
try {
User.find({}, async (err, users) => {
if (err) console.log(err);
asyncForEach(users, async (user) => {
await hashIt(user);
})
});
} catch (e) {
console.log(e);
}
}
async function fullThing(){
mongoose.connect(db, { useNewUrlParser: true })
.then(async () => {
await mySeed();
console.log("finished successfully");
})
}
fullThing();```
I appreciate the response. The solution turned out to be that w=majority for some reason needed to be removed from the db connection. After removing that. Everything began working fine. Wrapping the connect with the catch did help to find the error.
I have a similar routine running on my current back front end system, and below is how I have adapted your code to mine; mine is working, therefore I hope yours will work as well. I believe the problem is that is you are not catching potential errors, that happened to me a lot in the beginning, and sometimes it still happens when I am tired.
bcrypt.genSalt(10, (err, salt) => {
if (err) console.log(err);
bcrypt.hash(user.Password, salt, (err, hash) => {
if (err) throw err;
user.Password = hash;
const id = user
.save()
.then(() => {
console.log("okay");
})
.catch(err => console.log(err));
});
});
In case it does not work, please, let me know what comes out as error.
Appendix
I have tested my solution below:
const bcrypt = require("bcryptjs");
require("./connection");
//creating user schema
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
UserSchema = new Schema({ name: String, password: String });
var User = mongoose.model("User", UserSchema);
const user = new User({ name: "Jorge Pires", password: "Corona Virus" });
console.log(` Before hashing ${user.password}`);
//---------------------------------------------------------------
//Uncomment here to save the user before hashing, it will change anyway, therefore no need!
// user.save();
// User.create({ name: "Jorge Pires", password: "Corona Virus" });
//--------------------------------------------------------------
bcrypt.genSalt(10, (err, salt) => {
//generates the salta
if (err) console.log(err);
bcrypt.hash(user.password, salt, (err, hash) => {
//creates the hash
if (err) throw err;
user.password = hash; //saves the hash
const id = user
.save()
.then(() => {
console.log(` after hashing ${user.password}`);
console.log(` Here goes the user id ${user.id}`);
})
.catch(err => console.log(err));
});
});
Output sample:
Before hashing Corona Virus
we are connected mongoose-tutorial
after hashing $2a$10$84MqPsiiMGA/KTHKFbytVOD5/su6rXiE7baA2TmsLzPMe.Y45aL9i
Here goes the user id 5e710a0bd4385c05b0cd827f