Node.js email-verification with mongoose - node.js

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);

Related

Synthax error in js / missing ) after argument list

Hi i'm working in node with passport and mongodb for login local session , and i got a synthax error but i can't figure out why?
it's kind of weird cause i think i got every thing in order
here here it's my code ...
var localStrategy = require('passport-local').Strategy;
var User = require('../app/models/users');
module.exports = function(passport){
//Serializing user
passport.serializeUser(function(user,done){
done(null, user.id);
});
passport.deserializeUser(function(id,done){
User.findById(id, fuction(err,user){ //here it's the error D:
done(err,user);
});
});
passport.use('local-signup', new localStrategy({
usernameField: 'username',
passField:'pass'
passReqToCallback: true
},
function(req,username, pass, done){
process.nextTick(function(){
User.findOne({'local.emial':email,},function(err,user){
if(err){
return done(err);
}
if(user){
retrun done(null,false,req.flash('signupMessage','Thath email its already taken '));
}else{
var newUser = new User();
newUser.local.username = username;
newUser.local.pass = pass;
newUser.save(function(err){
if(err){
throw err;
return done(null,newUser);
}
})
}
});
});
}
));
// end function
}
as always really thanks for your help
Correct fuction into function maybe?

Setting a function callback fram an async request

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);
});
});
}

Mongoose bcryptjs compare password doesn't refer to the document (this)

I have mongoose schema like so
var mongoose = require ('mongoose');
var bcrypt = require('bcryptjs');
var Schema = mongoose.Schema;
var SALT_WORK_FACTOR = 10;
var touristSchema = new Schema ({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String,
}
});
touristSchema.pre('save', function(next) {
var user = this;
console.log('bcrypt called by strategy', user);
// if user is facebook user skip the pasword thing.
if (user.facebook.token) {
next();
}
// only hash the password if it has been modified (or is new)
if (!user.isModified('password') && !user.isNew){
console.log('I am in here', user.isNew);
return next();
}
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
console.log('I am in genSalt');
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.local.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.local.password = hash;
next();
});
});
});
touristSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.local.password, function(err, isMatch) {
// console.log(this.local.password);
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('users', touristSchema);
and login strategy like this
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if(err)
return done(err);
if(!user)
return done(null, false, req.flash('loginMessage', 'No User Found'));
user.comparePassword(password, function(err, isMatch) {
if (err) throw err;
if (isMatch) {
done(null, user);
}
else
done(null, false, req.flash('loginMessage', 'Incorrect password'));
});
});
});
}
));
everything is working as expected but when I try to log in it gives me error:
TypeError: Cannot read property 'password' of undefined.
Turns out that this.local is undefined.
This is very strange as in touristSchema.pre hook we assigned var user = this and on logging this returned user document. When in compare method we are using touristSchema.methods.compare then this should must refer to the document as written in mongoose middleware docs too. I am beating my head over it for a couple of days now and have consumed every available help I could. Any help is greatly appreciated in advance. Thanks
and yes my
mongnodb version is v3.2.15
mongoose version is 4.9.7
which looks compatible to me according to mongoose docs

Unable to authenticate using email with passport-local nodejs..tried several examples

I have been trying to use email and password to authenticate using passport-local. I had similar code when I was using username and it worked fine. With email, I made some changes however nothing is working. Right at the endpoint '/login' of type 'post' the condition !user condition in users.js (shown below as 2nd code snippet) is somehow executing. Its not even going inside passport.use. Following is the code:-
In user.js(model file),
var mongoose=require('mongoose');
var bcrypt=require('bcryptjs');
//user schema
var UserSchema=mongoose.Schema({
phone: {
type:String,
},
email:{
type: String,
index:{unique:true}
},
password:{
type: String
},
firstname:{
type: String
},
lastname:{
type: String
}
});
var User=module.exports = mongoose.model('User',UserSchema);
module.exports.getUserByUsername=function(email,callback){
var query={email:email};
User.findOne(query, callback);
}
module.exports.comparePassword=function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
callback(null,isMatch);
});
}
}
In users.js(where i specify routes):
var express = require('express');
var router = express.Router();
var bodyParser=require('body-parser');
var User=require('../models/user');
var passport=require('passport');
var localStrategy=require('passport-local').Strategy;
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) { /*this is where the problem is this code executes everytime*/
return res.send('User not found');
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.json(user);
});
})(req, res, next);
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
//for sessions
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
//this doesnt seem to work
passport.use(new localStrategy({usernameField:'email', passwordField:'password'},function(email,password,done){
User.getUserByUsername(email, function(err,user){
if(err) throw err;
if(!user){
return done(null,false,{message: 'User not found'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) return done(err);
if(isMatch){
return done(null, user);
}
else{
return done(null,false,{message: 'Password doesnt match our records'});
}
});
});
}));
Note that there is no front end on this. I am just using postman to test my apis.
This code works fine with emails. The issue was I also have another file called admin.js and admins.js which do the same task as user and users. However, admin makes use of username. I had the same passport.use code for admin however, users was trying to access that file instead of the current one. Once I removed the admin code it all worked.

Passing inputModel instead of request to passport strategy

I'm using passport local strategy like this:
Config:
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(email, password, done) {
UserPersistenceModel.findOne({ email: email }, function (err, user) {
if (err) return done(err);
if (!user) return done(null, false);
user.comparePassword(password, function(err, isMatch) {
if(err) return done(err);
if(!isMatch) return done(null, false);
return done(null, user);
});
});
}
));
My router definition looks like this:
var TokenRouter = function(app, passport, tokenSecret) {
//Create
app.post('/', function(req, res, next) {
console.log(req.body);
passport.authenticate('local', function(err, user, info) {
if (err) return next(err);
if (!user) {
console.log('Unsuccessful login!');
return res.status(401).json({ error: 'Login failed!' });
}
req.logIn(user, function(err) {
if (err) return next(err);
console.log('Successful login!');
//user has authenticated correctly thus we create a JWT token
var token = jwt.encode(user, tokenSecret);
res.json({ output : token });
});
})(req, res, next);
});
};
For some reasons I don't fully understand the passport "mechanism". The documentation doesn't look very detailled to me. One question is where the request object (this contains the body which contains the email and the password) is passed to my strategy. How does the strategy gets the email and the password (what's the "source object")?
The reason asking this is that I'd like to use the following inputModel instead of the request being passed to the strategy:
var TokenCreateInputModel = function(req) {
this.email = req.body.email;
this.password = req.body.password;
this.validate();
};
TokenCreateInputModel.prototype = Object.create(InputModel);
TokenCreateInputModel.prototype.validate = function() {
if(!this.email) throw new Error('Email is required!');
if(this.email.indexOf('#') == -1) throw new Error('Emailsyntax is wrong!');
if(!this.password) throw new Error('Password is required!');
};
module.exports = TokenCreateInputModel;
This inputmodel is converting the request and validating the data. I want to use this input model because it fits better to my architecture (I'm using such inputModels in all other cases ... just not with passport (because of the lack of my understanding), which seems to be inconsistent to me.

Resources