Setting a function callback fram an async request - node.js

Good Morning All,
I have been looking for an answer to this on the boards, but my noob brain just can't make sense of it.
i have this function in models/user.js
module.exports.getUserByUsername = function(username, callback){
var retUser = new User;
sql.connect(dbConfig, function(err) {
if (err) {
console.log(err);
callback();
}
// create Request object
var request = new sql.Request();
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password,recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
retUser = user;
}
callback();
// send records as a response
//res.send(recordset);
});
});
function callback() {
sql.close();
return retUser;
};
}
and this code in my routes/user.js
passport.use(new LocalStrategy(
function(username, password, done) {
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
I have been modifying an example from GITHUB that uses mongoDB for the DB connection, but I would like to use MS SQL. The function is successfully calling the database and returning the correct values. However I don't know how to initiate the callback so I can pass the retUser object back to the original function for processing and logging in.
I did for a moment try to do this by not using the callback and using a standard return type of function, however I quickly realised that given the async nature this wouldn't work.
any help here would be greatly appreciated.
Thanks

OK I managed to figure it out using this post:
Node.js npm mssql function returning undefined
my new code is:
module.exports.getUserByUsername = function(username, callback){
var connection = new sql.ConnectionPool(dbConfig, function(err) {
if (err) {
console.log(err);
callback(err);
return
}
// create Request object
var request = new sql.Request(connection);
request.input('ip_username', sql.NVarChar, username)
// query to the database and get the records
request.query('select * from [portal_users] where username = #ip_username', function(err, recordset) {
if (err) {
console.log(err);
callback(err,recordset);
return;
} else {
var user = new User(recordset.recordset[0].username,recordset.recordset[0].password.replace(/ /g,''),recordset.recordset[0].email,recordset.recordset[0].name);
user.addID(recordset.recordset[0].id);
callback(err,user);
}
sql.close();
// send records as a response
//res.send(recordset);
});
});
}

Related

Node.js email-verification with mongoose

I am working on Node.js and email-verification with passport and mongoose.
Now I am testing the code and got an error, but I can't fix it.
Here is my problem and code posted below:
My app.js i have
var nev = require('email-verification')(mongoose);
require('./routes/db/email-verification')(nev);
require('./routes/db/passport')(passport,nev);
my email-verificaiton.js
var User = require('./ModelUser');
module.exports = function(nev){
nev.configure({
...
...
},function(err,options){
if(err)
return err;
console.log('test');
});
nev.generateTempUserModel(User,function(err,tempUserModel){
if(err){
return err;
}
console.log('checked');
});
};
my passport.js
module.exports = function (passport, nev) {
...
...
passport.use('local-signup', new LocalStrategy({
usernameField: 'email', //dummy string
passwordField: 'password', //dummy string
passReqToCallback: true
}, function (req, email, password, done) {
var newUser = new User();
newUser.email = email;
newUser.password = password;
nev.createTempUser(newUser, function( err, existingPersistentUser, newTempUser){
if(err) console.error(err);
if(existingPersistentUser){
console.log('E-mail already exists');
return done(null, false, req.flash('signupMessage', 'E-mail already exists'));
}
if(newTempUser){
var URL = newTempUser[nev.options.URLFieldName];
nev.sendVerificationEmail(email, URL, function(err, info){
if(err) console.error(err);
console.log('An email has been sent to you. Please check it to verify your account.');
return done(null);
})
} else{
console.log('You have already signed up. Please check your email to verify your account.');
return done(null);
}
})
I got an error TypeError: Cannot read property 'createTempUser' of undefined
I dont know why my 'nev' variable is undefined in my passport.js.
pls anyone can help me>? this is very hard.
In email-verificaiton.js, change it to look something more like this:
function verification(nev) {
nev.configure({
...
...
},function(err,options){
if(err)
return err;
console.log('test');
});
nev.generateTempUserModel(User,function(err,tempUserModel){
if(err){
return err;
}
console.log('checked');
});
};
module.exports = {verification}
And then inside app.js you can change
var nev = require('email-verification')(mongoose);
To become
var nev = require('email-verification').verification(mongoose);

Bluebird promise resolve is being caught as an error

I am using promises to return data for a user do authenticate them and my resolve is showing up in my .catch for my call.
Call to the login function;
function(req, username, password, done) {
user.login(username, password).then( function(err, results){
if (err) throw err;
done(null, results.user);
}).catch(
function(err){
console.log("Failed to log in", err);
done(null, false);
}
);
}
Here is the promise code:
exports.login = function(username, password){
return new promise(function(resolve, reject){
var sql = `CALL LOGIN(?)`;
db.conn.query(sql, username, (err, results, fields) => {
if (err) {
reject("SQL ERR:", err);
}
var user = results[0][0];
if (!user.uID) {
reject("Incorrect username");
}
if(bcrypt.compareSync(password, user.pword)){
resolve(user);
} else {
reject('Incorrect password');
}
});
});
}
When this is called, the user objet is being thrown as an error even though its being called on resolve... I am currently stuck, I tried to re-install the bluebird module as well incase something happened with it.
What's going on here is the next thing:
Here you are passing the user object as a param if everything is ok
if (bcrypt.compareSync(password, user.pword)) {
resolve(user);
} else {
reject('Incorrect password');
}
So in this part .then of your code you are receiving a user object as a unique param so there is no necessity to check if there is an error.
function (req, username, password, done) {
user.login(username, password).then(function(user) {
// a good way to see all arguments is
// console.log(arguments);
done(null, user);
}).catch(
function(err) {
console.log("Failed to log in", err);
done(null, false);
}
);
}

crypto pbkdf2 is not called

I have written an function to hashpasswords with crypto.obkdf2. This function was working fine, but for some reason he doesn't anymore.
EDIT
In a controller I want to create an user with the user.service:
account.controller:
userService.createAccount(details, true, function(err, result){
if(err){
res.status(500).json({message: err});
}else{
//account is created, details are mailed, now we can set the user on the order
user = result;
}
})
The service does a few checks and call the user.register function
user.service
function createAccount (details, generatePassword, callback){
console.log("createAccount");
//generate password, save details + password, mail details, send results back in callback
//if(generatePassword){
// details.password = random(10);
//}
details.password = '7eb4f68ea4';
var userData = _.pick(details, 'firstName', 'lastNamePrefix', 'lastName','email','gender', 'password');
userData.verificationCode = random(8);
userData.userName = userData.email;
console.log("userdate", userData);
User.register(userData, function(err, user){
console.log("register user", err);
if(err && (11000 == err.code || 11001 == err.code)) {
console.log("E-mailadres already in use");
return callback("E-mailadres already in use");
}
if (err) {
console.log("Something went terribly wrong...", err);
return callback("Something went wrong: " + err)
}
var options = {
to: user.email,
subject: 'Uw account op Prisma Note',
template: 'new-account'
}
//Mail sturen met activatielink na aanmaken
mailService.mail(options, user, null, function(err, data){
console.log("sendmail!");
if (err) {
console.log("error sending mail", err);
return callback("Error sending mail: " + err.message);
}else{
console.log("hier!", user);
return callback(null, user);
}
});
})
}
The user.modal contains the register function:
user.model
User.statics.register = function(opts, callback) {
console.log("register!");
var self = this;
var data = _.cloneDeep(opts);
passwordService.hash(opts.password, function(err, hashedPassword, salt) {
if (err) {
console.log("passwordsrv", err);
return callback(err, null);
}
data.password = hashedPassword;
data.passwordSalt = salt;
self.model('User').create(data, function(err, user) {
if (err) {
console.log("createuser", err);
return callback(err, null);
}
user.password = undefined;
user.passwordSalt = undefined;
callback(err, user);
})
})
}
And finally, the code comes to the passwordService
password.service
var LEN = 256;
var SALT_LEN = 64;
var ITERATIONS = 10000;
var DIGEST = 'sha256';
function hashPassword(password, salt, callback){
console.log("hashPassword");
var len = LEN /2;
if (3 === arguments.length) {
crypto.pbkdf2(password, salt, ITERATIONS, len, DIGEST, function(err, derivedKey) {
if (err) {
console.log("crypto err", err);
return callback(err);
}
return callback(null, derivedKey.toString('hex'));
})
} else {
console.log("pwdsrv");
callback = salt;
crypto.randomBytes(SALT_LEN / 2, function(err, salt) {
if (err) {
console.log("randombyte", err);
return callback(err);
}
salt = salt.toString('hex');
console.log("hier");
console.log(password, salt, ITERATIONS, len, DIGEST);
//password = '7eb4f68ea4'
//salt = '21aaac28b8411326b8df5b8b60476904f58d40f972a2f5d698ec4d0fb57dc315'
//ITERATIONS = 10000
//len = 128
//DIGEST = 'sha256'
crypto.pbkdf2(password, salt, ITERATIONS, len, DIGEST, function(err, derivedKey) {
console.log("hjioo");
if (err) {
console.log("pbkdf2", err);
return callback(err);
}
console.log("hier");
callback(null, derivedKey.toString('hex'), salt);
})
})
}
}
This function is called from our 'user model'. That model has an User.statics.register function what we can call. After a lot of debugging lines I have found out the code stops at (in my tested cases) crypto.pbkdf2(password, salt, ITERATIONS, len, DIGEST, function(err, derivedKey) in the else of the function. The log before this function show the content of the variables, but I can't see the logs in the function.
I have no idea, why this is stopped working. We have updated our node.JS version, but since this is an node module, that must be no problem.
Can somebody help me to solve this problem, so our users can register again?
The mailservice, which you can see in the service, sends an email via Amazon SES, I think it is not relevant to post that code.

Passport.Js doesn't let me create two different authentication routes

I am trying to use two different basic authentication conditions for two different apis. But the moment I add the second authentication condition in my project, Passport.Js doesn't let me authenticate at all. It keeps saying wrong password. Below is the code: Can anybody suggest what's wrong with it? I am sorry if this is a noob question. I have just begun working with node so the entire framework is new to me.
// Load required packages
var passport = require('passport');
var passport2= require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var BasicStrategy2 = require('passport-http').BasicStrategy;
var User = require('../models/useridentity');
var User2 = require('../models/useridentity');
passport.use(new BasicStrategy(
function(username, password, callback) {
User.findOne({ username: username }, function (err, user) {
if (err) { return callback(err); }
// No user found with that username
if (!user) { return callback(null, false); }
// Make sure the password is correct
user.verifyPassword(password, function(err, isMatch) {
if (err) { return callback(err); }
// Password did not match
if (!isMatch) { return callback(null, false); }
// Success
return callback(null, user);
});
});
}
));
passport2.use(new BasicStrategy2(
function(user, pass, callback) {
User2.findOne({ useremail: user }, function (err, user) {
if (err) { return callback(err); }
// No user found with that username
if (!user) { return callback(null, false); }
// Make sure the password is correct
user.verifyPassword(pass, function(err, isMatch) {
if (err) { return callback(err); }
// Password did not match
if (!isMatch) { return callback(null, false); }
// Success
return callback(null, user);
});
});
}
));
exports.isAuthenticated = passport.authenticate('basic', { session : false });
exports.isAuthenticated2 = passport2.authenticate('basic',{session:false});
Requiring same modules multiple times makes no sense - due to module caching you are likely receiving the same object. You can name the strategies in use which enables using same strategy with different configuration:
var passport = require('passport'),
BasicStrategy = require('passport-http').BasicStrategy;
passport.use('auth1', new BasicStrategy(...));
passport.use('auth2', new BasicStrategy(...));
app.post('/api1', passport.authenticate('auth1'), function(req, res) { ... });
app.post('/api2', passport.authenticate('auth2'), function(req, res) { ... });

Check if document already exists if not create one

Im learning expressjs + mongo. I want to check after user logs in with passport through Steam if his data is already in database if not to create a record for him.
For this I created a static method in schema. Unfortunatelly i can't save from the inside of it.
TypeError: Object # has no method 'create'
SteamAccountSchema.statics.checkAccount = function(identifier){
this.findOne({ 'identifier' : identifier }, function(err, account){
if(err) throw err;
console.log("Checking account:" + account)
if(account) {
console.log("user already in db")
return true
} else {
console.log("Creating new user account")
this.create({
name : 'username',
identifier: identifier
}, function(err){
if(err) throw err;
// if (err) return done(err);
return false
});
}
});
}
Just cache the this object. I.e. in the code below self points to what you need:
SteamAccountSchema.statics.checkAccount = function(identifier){
var self = this;
this.findOne({ 'identifier' : identifier }, function(err, account){
if(err) throw err;
console.log("Checking account:" + account)
if(account) {
console.log("user already in db")
return true
} else {
console.log("Creating new user account")
self.create({
name : 'username',
identifier: identifier
}, function(err){
if(err) throw err;
// if (err) return done(err);
return false
});
}
});
}

Resources