Server js:
var user_controller = require('./controllers/user_controller');
passport.use(new passportLocal(function(username, password, done) {
user_controller.login(username, password).then(function(value) {
if (value) {
console.log(value + "true")
done(null, {
id: username,
name: username
});
} else {
console.log(value + "false");
done(null, null);
}
})
}));
USer contoller:
module.exports.login = function(username, password) {
var status;
var userid = username;
User.findOne({
'username': [userid],
'password': [password]
}, function(err, user) {
if (!user) {
console.log("logged err");
status = false;
} else {
console.log("login in");
status = true;
}
console.log(status);
return status;
});
};
I am doing an async task (db call) in my user_controller.login and it returns a boolean "value"
But when I execute this I am getting error:Cannot read property 'then' of undefined
I saw previous questions on this error but couldnt understand it
I think you can try with callback function. The login function takes one callback param and execute that function at end.
module.exports.login = function(username, password, callback) {
var status;
var userid = username;
User.findOne({
'username': [userid],
'password': [password]
}, function(err, user) {
if (!user) {
console.log("logged err");
status = false;
} else {
console.log("login in");
status = true;
}
console.log(status);
callback(status);
});
};
While calling the function login pass the third param as a callback function.
var user_controller = require('./controllers/user_controller');
passport.use(new passportLocal(function(username, password, done) {
user_controller.login(username, password, function(value) {
if (value) {
console.log(value + "true")
done(null, {
id: username,
name: username
});
} else {
console.log(value + "false");
done(null, null);
}
})
}));
Note: I am not tested the above code.
You can create promise based functions in Nodejs using Q library.
npm install q
Below code can help you.
module.exports.login=function(username,password){
var status;
var userid=username;
User.findOne({'username':[userid], 'password':[password]},function(err,user){
var deferred = Q.defer();
if(err){
deferred.reject(err);
} else{
deferred.resolve(data);
}
return deferred.promise;
});
and use it in Server.js
var user_controller = require('./controllers/user_controller');
passport.use(new passportLocal(function(username, password, done) {
user_controller.login(username, password).then(function(user) {
done(null, {
id: username,
name: username
});
});
Related
I was wondering if anyone could point me in the right direction and help me fix this error I'm getting when I attempt to add a user with my Ember.js model after created a user with Firebases createUser method.
To be more specific here is the error I'm getting: Uncaught TypeError: Cannot read property 'createRecord' of undefined
App.SignUpController = Ember.Controller.extend({
needs: ['sign-in'],
needs: ['application'],
userSignedIn: false,
actions: {
signMeUp: function() {
var state = false;
var controllerContext = this;
// Create firebase user
ref.createUser({
email : this.get('email'),
password : this.get('password'),
}, function(error, user) {
if (error === null) {
console.log('User created with id', user.uid);
state = true;
controllerContext.set('userSignedIn', state);
console.log("State from sign-up page: "+ state);
console.log("Testing user.uid inside: "+user.uid);
var fbid = user.id;
controllerContext.set('user id', user.uid);
var newUser = this.store.createRecord('user', {
id: fbid,
email: this.get('email'),
password: this.get('password'),
});
newUser.save();
} else {
console.log("Error creating account:", error);
}
}); // End createUser
this.transitionToRoute('letters');
}
}
});
UPDATE: Here is a (very hacky) solution I came up with after a day of JS plumbing.
App.SignUpController = Ember.Controller.extend({
needs: ['sign-in'],
needs: ['application'],
userSignedIn: false,
thisUserID: '',
actions: {
signMeUp: function() {
var state = false;
var controllerContext = this;
// Create firebase user
function authWithPassCallback(userObj, user){
console.log("authWithPassCallback user.uid is: "+user.uid);
return user.uid
}
function createUserAndLogin(userObj, callback) {
ref.createUser(userObj, function(error, user) {
if (error === null) {
console.log("User created successfully");
controllerContext.set('thisUserID', user.uid);
return callback(userObj, user);
} else {
console.log("Error creating user:", error);
}
});
}
var userAndPass = {
email: this.get('email'),
password: this.get('password')}
var fbPayload = createUserAndLogin(userAndPass, authWithPassCallback);
setTimeout(function () {
console.log("FB load: "+ controllerContext.get('thisUserID'));
var newUser = controllerContext.store.createRecord('user', {
id: controllerContext.get('thisUserID'),
email: controllerContext.get("email"),
password: controllerContext.get("password"),
});
newUser.save();
controllerContext.transitionToRoute('letters');
}, 1000);
console.log(controllerContext.get('thisUserID'));
}
}
});
I'm assuming the error is occurring at newUser = this.store.createRecord - at this point in your code this is no longer referring to the controller. You will need to use controllerContext.store.createRecord.
you probably just lost the context here. this doesn't refer to the controller, you're in the error function.
There are two ways of fixing that. First is to bind the function to the controller's this:
ref.createUser({
// ...
}, function(error, user) {
var newUser = this.store.createRecord('user', {/*...*/});
// ...
}.bind(this));
or to reuse the controllerContext variable:
ref.createUser({
// ...
}, function(error, user) {
// ...
var newUser = controllerContext.store.createRecord('user', {/*...*/});
});
I am writing a simple script to retrieve a password from the table and validate in node.js Here is the script
module.exports = {
login: function (email, pass) {
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('test.db');
db.get("SELECT password FROM users WHERE user_email = ?", email, function(err, row) {
if (err !== null) {
console.log("An error has occured");
return "error";
} else if(row.password === pass) {
console.log("success");
return "success";
} else {
console.log("Incorrect password");
return "failure";
}
});
}
};
The console log statements are correct when the if else cases are evaluated. However the return value is undefined.
I do not understand why the return value is undefined if the logging is done correctly.
You can't return values from a callback because doing so is meaningless. You have to pass in a callback to your login() function and call that with (err, result) inside your db.get() callback:
module.exports = {
login: function (email, pass, cb) {
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('test.db');
db.get("SELECT password FROM users WHERE user_email = ?",
email,
function(err, row) {
if (err)
return cb(err);
cb(null, row.password === pass);
});
}
};
I'm using NodeJS, with bcrypt-nodejs (https://github.com/shaneGirish/bcrypt-nodejs) and Bluebird for promises. Came up with this code and been wondering if there is better way to do the same thing. I have module with:
var Promise = require("bluebird"),
bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'));
// ....[some othe code here]
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result);
});
};
then from another module I call users.setPassword as below:
app.post('/api/v1/users/set-password', function(req, res, next) {
users.setPassword(req.body).then(function(result) {
// Store hash in your password DB.
console.log(result[1]);
res.json({
success: true
})
})
.catch(function(err) {
console.log(err);
});
});
It always ends up with "[Error: No callback function was given.]" message as bcrypt.hashAsync seems to require 4 parameters. Original, non-promisified hash method requires 3 only though. When I add empty callback to hashAsync, it works fine:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result,function() {});
});
};
Is there any better way to do this, without providing empty callback as above?
EDIT:
In response to Bergi's comment.. the function will set password eventually, I just didn't get that far when posted the question. Now got this far, please let me know if something is not quite right though:
Users.prototype.setPassword = function(user) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(user.password, result, null);
})
.then(function(result) {
// store in database
console.log("stored in database!");
return result;
});
};
bcrypt.hashAsync seems to require 4 parameters. Original, non-promisified hash method requires 3 only though.
It's the other way round rather. From the docs:
hash(data, salt, progress, cb)
data - [REQUIRED] - the data to be encrypted.
salt - [REQUIRED] - the salt to be used to hash the password.
progress - a callback to be called during the hash calculation to signify progress
callback - [REQUIRED] - a callback to be fired once the data has been encrypted.
The original method took 4 arguments, hashAsync will take 3 and return a promise.
However, in your code you were only passing two. You don't need to pass an empty function though, that the parameter is not [REQUIRED] means you can pass null (or any other falsy value) for it. bcrypt will create such an empty function itself. So use
function (data) {
return bcrypt.genSaltAsync(10).then(function(result) {
return bcrypt.hashAsync(data.password, result, null);
});
}
This is my promisified bcrypt from a project I did a while back. Bluebird isn't really necessary for such a small, simple library.
module.exports = {
makeUser: function(username, password){
return new Promise(function(resolve, reject) {
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(password, salt, null, function(err, hash) {
if (err) {
console.log("hashing the password failed, see user.js " + err);
reject(err);
}
else {
console.log("hash was successful.");
resolve(hash);
}
})
})
})
.then(function(hash){
return db.createUser(username, hash)
})
},
login: function(username, password){
return db.userFind(username)
.then(function(userObj){
if(!userObj){
console.log("did not find " + username + " in database.");
return new Promise(function(resolve, reject){
resolve({login:false, message:"Your username and/or password are incorrect."})
}
}
else {
console.log("found user: " + userObj._id, userObj);
return new Promise(function(resolve, reject){
bcrypt.compare(password, userObj.hashword, function(err, bool) {
resolve({bool:bool,
user:userObj._id,
mindSeal: userObj
})
})
})
}
})
}
}
Example Usage:
app.post('/signup', function(req, res) {
var username = req.body.username;
var password = req.body.password;
var user = handler.userExists(username)
.then(function(answer){
if (answer !== null){
console.log(req.body.username + " was taken")
res.send({login: false, message: req.body.username + " is taken"});
return null;
} else if (answer === null) {
console.log("username not taken")
return handler.makeUser(username, password);
}
})
.catch(function(err){
console.log("error during user lookup:", err);
res.status(404).send({message:"database error:", error:err});
})
if (user !== null){
user
.then(function(x){
console.log("this is returned from handler.makeUser: ", x)
console.log(x.ops[0]._id)
req.session.user = x.ops[0]._id;
var mindSeal = {
userSettings: {
username: x.ops[0]._id,
newCardLimit: null,
tValDefault: 128000000,
lastEdit: req.body.time,
todayCounter: 0,
allTimeCounter: 0,
cScaleDefault: {0: 0.9, 1: 1.2, 2: 1.8, 3: 2.5},
accountMade: req.body.time
},
decks: {}
};
handler.setMindSeal(req.session.user, mindSeal, req.body.time);
res.send({
login: true,
mindSeal: mindSeal
});
})
.catch(function(error){
console.log("make user error: " + error);
res.status(401).send({message:"failed.",error:error,login:false});
})
}
});
app.post('/login', function(req, res) {
var username = req.body.username;
var password = req.body.password;
handler.login(username, password)
.then(function(obj){
if (obj.bool){
console.log("username and password are valid. login granted.");
req.session.user = obj.user;
console.log("obj is:", obj)
var mindSeal = {decks:obj.mindSeal.decks, userSettings:obj.mindSeal.userSettings};
console.log("mindSeal sending:", mindSeal);
res.status(200).send({
login: true,
message:"Login Successful",
mindSeal: obj.mindSeal
});
}
else {
console.log("password invalid")
res.status(401).send({login: false, message:"Your username and/or password are incorrect."})
}
})
.catch(function(error){
console.log(error);
res.status(404).send({message:"database error:", error:err});
})
});
conceptual example only; borrowed and slightly modified some old code of mine on the fly. Working code (I see things I'd like to improve in it now, but it works) here: https://github.com/finetype/mindseal/blob/master/server.js
Maybe you could use another bcrypt library, with a better API which removes the need for promises.
Users.prototype.setPassword = function(user) {
return TwinBcrypt.hashSync(user.password, 10);
};
Or, with progress tracking :
Users.prototype.setPassword = function(user) {
function progress(p) {
console.log( Math.floor(p*100) + '%' );
}
TwinBcrypt.hash(user.password, 10, progress, function(result) {
// store in database
console.log("stored in database!");
return result;
});
};
I dont see whats the error here: it returns
Undefined
"Unknown user"
passport.use(new LocalStrategy(
function(username, password, done) {
process.nextTick(function () {
findByUsername(username, function(err, user) {
if (err) {
console.log(err);
return done(err);
}
if (!user) {
console.log("Unknown user");
return done(null, false, { message: 'Unknown user ' + username });
}
if (user.password != password) {
console.log("Invalid password");
return done(null, false, { message: 'Invalid password' });
}
return done(null, user);
})
});
}));
function findByUsername(username, fn) {
var user = [];
connection.query('SELECT * FROM Users WHERE username = ?', [username], function(err, rows) {
//console.dir(rows);
if(err != null) {
//res.end("Query error:" + err);
console.log("Query error:" + err);
} else {
for (var i = 0; i < rows.length; i++) {
var myRows = rows[i];
user.push(myRows);
};
}
});
console.log(user);
console.log(user.username);
if (user.username) {
return fn(null, user.username);
} else {
return fn(null, null);
}
}
You are passing user.username in callback. Instead you should pass user object.
Edit: You should invoke the callback only after the query is executed.
function findByUsername(username, fn) {
var user = [];
connection.query('SELECT * FROM Users WHERE username = ?', [username], function (err, rows) {
//console.dir(rows);
if (err != null) {
//res.end("Query error:" + err);
console.log("Query error:" + err);
} else {
for (var i = 0; i < rows.length; i++) {
var myRows = rows[i];
user.push(myRows);
};
}
console.log(user);
console.log(user.username);
if (user.username) {
return fn(null, user);
} else {
return fn(null, null);
}
});
}
I've got a single page which is an account settings page. In it, I allow my users to update their avatar (if they've attached an image), change their email (if it has been changed from the original), and change their name and password.
Right now, I'm using async's waterfall method, but am swapping out async for Q since I prefer the syntax (and api). I'm wondering if this is the way that I should be using Q in replacement of async's waterfall.
I'm doing something like this:
exports.settingsAccountPOST = function(req, res) {
var doesEmailExist = function() {
var deferred = Q.defer();
User.findByEmail({
email: req.body.email
}, function(err, user) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(user);
}
});
return deferred.promise;
};
var updateEmail = function(email) {
var deferred = Q.defer();
User.updateEmail({
userId : req.session.user.id,
email : req.body.email
}, function(err, updated) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(updated);
}
});
return deferred.promise;
};
var updateName = function() {
var deferred = Q.defer();
if (req.body.name) {
User.updateName({
userId: req.session.user.id,
name: req.body.name
}, function(err, updated) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(updated);
}
});
return deferred.promise;
}
};
doesEmailExist().then(function(email) {
if (!email) {
return(updateEmail(email));
}
}).then(function() {
return(updateName())
}).then(function() {
res.redirect('/account')
});
};
Say that there is an error with the email address being used. Is there a way to "pass" it to the final call? Use case: Updated password properly, but email update didn't work, so I want to show a session flash to the user telling them they updated their password properly, but there was an issue with updating their email.
I was looking in the docs and it seems I may need to use:
.fin(function () {
});
Is this correct? If so, what should I be passing into that? Just push to an object the error that occurred within the chain and then loop through all errors and display them to the user? Or just return immediately and display the error?
If you are using Q.defer you are generally doing something wrong.
var findByEmail = Q.nbind(User.findByEmail, User);
var updateEmail = Q.nbind(User.updateEmail, User);
var updateName = Q.nbind(User.updateName, User);
//later on...
exports.settingsAccountPOST = function (req, res) {
findByEmail({
email: req.body.email
})
.then(function (user) {
if (!user) {
return updateEmail({
userId: req.session.user.id,
email: req.body.email
});
}
})
.then(function () {
return updateName({
userId: req.session.user.id,
name: req.body.name
})
})
.then(function () {
res.redirect("/account");
})
.catch(function(e){
//Handle any error
});
};