I am using Koa module - Node js and mysql & stuck on a problem.
In signup function (inside welcomeCtrl.js) I have:
var bcrypt = require('bcrypt');
module.exports = {
signup: function* (next) {
bcrypt.genSalt(10, function(err, salt) {
console.log(salt);
bcrypt.hash(password, salt, function(err, hash) {
// Store hash in your password DB.
console.log(hash); //no error
var hashedPassword = hash;
});
});
console.log(bcrypt.hash.hash); //gives error
//or
console.log(bcrypt.hash.hahedPassword); //gives error
queryString = "insert into user(email,name, phone, password, course_id, dpt_id) values('%s','%s','%s','%s','%s','%s')";
query = util.format(queryString, email, name, phone, hash, courseId, dptId);
results = yield databaseUtils.executeQuery(query);
this.redirect('/');
}
}
I am calling signup post function in different routes.js file as:
router.post('/signup', welcomeCtrl.signup);
Here is the executeQuery function in the databaseUtils.js file
var executeQuery = function(query, callback) {
pool.getConnection(function(err, connection) {
// Use the connection
connection.query(query, function(err, rows, fields) {
connection.release();
if(err) {
err.mysqlQuery = query;
logger.logError(err);
}
if(typeof callback == "function") {
callback(err, rows);
}
// Don't use the connection here, it has been returned to the pool.
});
});
};
module.exports = {
executeQuery: thunkify(executeQuery),
executePlainQuery: executeQuery
};
Is there any way to use hash variable outside the function so that it can be inserted in query?
You should move your query function into the callback for bcrypt.hash.
bcrypt.genSalt(10, function(err, salt) {
console.log(salt);
bcrypt.hash(password, salt, function(err, hash) {
// Store hash in your password DB.
console.log(hash); //no error
queryString = "insert into user(email,name, phone, password, course_id, dpt_id) values('%s','%s','%s','%s','%s','%s')";
query = util.format(queryString, email, name, phone, hash, courseId, dptId);
databaseUtils.executeQuery(query, function() {
this.redirect('/');
});
});
});
Problem is, where does your redirect function come from? You're going to loose context on this unless you bind the functions. Do fat arrow functions work in your setup? If so you could do it that way.
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 am currently making a webapp with a database using express and postgres and am having trouble implementing registration.
This is a small snippet of what happens after the user keys in username, name and password into a form which is then posted to the '/registerUser' route. Here is the post request at the '/registerUser' route. The pool.query works for the check_username, however, is does not work for the add_user query.
Here are the 2 queries:
check_username = 'SELECT 1 FROM Users where username = $1'
add_user = 'INSERT INTO users VALUES (username, name, password) VALUES ($1, $2, $3)'
router.post('/', function(req, res, next) {
var name = req.body.name;
var username = req.body.username;
var password = req.body.password;
pool.query(sql_query.query.check_username, [username], (err, data) =>{
if(data.rows[0] != undefined) {
console.log(`re register again!`);
res.redirect('/registerUser');
} else {
console.log("adding to database")
// Generate salt
bcrypt.genSalt(10, (err, salt) =>{
if(err) {
console.log(err);
}
// hash it with salt
bcrypt.hash(password, salt, (err,hash)=>{
if(err) console.log(err)
//password = hash
console.log(`${username} + ${password}`);
// save to database
pool.query(sql_query.query.add_user, [name, username, password], (err, data) => {
console.log("pass")
res.redirect("/")
});
});
});
}
});
});
What exactly is the problem here? Could it be that i cannot nest pool.queries?
the answer is that there is a syntax error with the insert queries. There shouldnt be a VALUES in front of the table columns.
I am trying to store the hash password and checking the it is valid or not.
var bcrypt = require('bcrypt');
let data = "";
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("my password", salt, function(err, hash) {
// Store hash in your password DB.
console.log(hash);
data = hash;
});
});
bcrypt.compare("my password", data, function(err, res) {
// res === true
console.log(res)
});
return value always false.?
but if I move the compare inside genSalt function its returning true.
Thanks
You are dealing with asynchronous functions in node.js, so this result is expected. For the clearer understanding of the problem try to console.log data before bcrypt.compare. I can certainly say it would be equal to an initial value of "".
Then try to move your compare function inside the .hash callback
var bcrypt = require('bcrypt');
let data = "";
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("my password", salt, function(err, hash) {
// Store hash in your password DB.
console.log(hash);
data = hash;
console.log(data); // Here data equals to your hash
bcrypt.compare("my password", data, function(err, res) {
// res === true
console.log(res)
});
});
});
console.log('data') // Here data equals to initial value of ""
You can use async/await functions to make it look like synchronous code and get rid of callbacks. Luckily, bcrypt support promise interface that is used by async/await
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash("my password", salt);
const result = await bcrypt.compare("my password", data);
console.log(result);
1st post. I'm a student studying js and came across this problem with a callback that I'm not sure how to structure properly.
var bcrypt = require('bcrypt-nodejs');
var users = db.collection("users");
this.addUser = function(username, password, email, callback) {
"use strict";
// Generate password hash
var salt = bcrypt.genSaltSync();
var password_hash = bcrypt.hashSync(password, salt);
// Create user document
var user = {'_id': username, 'password': password_hash};
// Add email if set
if (email != "") {
user['email'] = email;
}
// NOT SURE What to write here
callback(Error("addUser Not Yet Implemented!"), null);
}
First of all: do not use sync methods if possible, use callbacks instead.
var bcrypt = require('bcrypt-nodejs');
var users = db.collection("users");
this.addUser = function(username, password, email, callback) {
"use strict";
// Generate password hash
bcrypt.genSalt(function(err, salt) {
if (err) {
callback(err);
return;
}
bcrypt.hash(password, salt, function(err, password_hash) {
if (err) {
callback(err);
return;
}
// Create user document
var user = {
'_id': username,
'password': password_hash
};
// Add email if set
if (email != "") {
user['email'] = email;
}
// NOT SURE What to write here
callback(null);
});
});
}
and please ask precise questions.
If I understand propperly, you dont know how to handle a callback?
you simply pass the function that will be called after all work in your function is done as the parameter callback. when your done, you call the callback with the wanted parameters.
here it's the err object in case of an error or null if there is no error.
If you want to pass your created user to the callback, just replace
callback(null); with callback(null, user);
I'm using the following function to hash a user's password, following Express's example for authentication:
function hash(pwd, salt, fn) {
// Bytesize
var len = 128,
// Iterations. ~300ms
iterations = 12000;
if (3 == arguments.length) {
crypto.pbkdf2(pwd, salt, iterations, len, fn);
} else {
fn = salt;
crypto.randomBytes(len, function(err, salt){
if (err) return fn(err);
salt = salt.toString('base64');
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
if (err) return fn(err);
fn(null, salt, hash);
});
});
}
}
The salt, as you can see, is returned as a string encoded in base64. The hash, however, is returned as a SlowBuffer. This same function is also used to compare hashes when trying to log a user in.
My Mongoose schema for Users specifies that the hash should be of type String. This ends up storing the hash in a strange way, resulting in contents like this which wreaked havoc on my mongo host:
My question is, is there a better/smarter way to store this hash in my database? I've tried encoding it with .toString('hex'), and I've also tried changing the hash type in the User schema to buffer, but both these approaches made all comparisons false when trying to log users in. Comparisons are made in my authenticate function, seen below:
function authenticate(name, pass, fn) {
var findUser = function(username) {
var deferred = Q.defer(),
populateObj = [
// list of paths to populate objects normally goes here
];
User.findOne({ username: name }).populate(populateObj).exec(function (err, retrievedUser) {
if (err || !retrievedUser) {
console.log(err);
deferred.reject('Cannot find user.');
}
else {
deferred.resolve(retrievedUser);
}
});
return deferred.promise;
};
findUser(name).then(function(data) {
// apply the same algorithm to the POSTed password, applying
// the hash against the pass / salt, if there is a match we
// found the user
hash(pass, data.salt, function(err, hash){
if (err) return fn(err);
if (hash == data.hash) return fn(null, data);
return fn('Invalid password.');
});
}, function() {
return fn('Failed to retrieve user.');
});
}
Storing the hash as a hex string in the database works okay for me (storing them 'raw' in either a String or a Buffer property doesn't):
var crypto = require('crypto');
var mongoose = require('mongoose');
var client = mongoose.connect('mongodb://localhost/test');
var UserSchema = new mongoose.Schema({
salt : String,
hash : String
});
var User = mongoose.model('User', UserSchema);
hash('secret', function(err, salt, key) {
new User({ salt : salt, hash : key.toString('hex') }).save(function(err, doc) {
User.findById(doc._id, function(err, doc) {
hash('secret', doc.salt, function(err, key) {
console.log('eq', doc.hash === key.toString('hex'));
});
});
});
});
(by the way, both crypto.pbkdf2 and crypto.randomBytes have synchronous counterparts)