So I have successfully implemented a user authentication using Passport.js.
Right now I am trying to implement a random URL generator for resetting passwords/confirming accounts/etc. But I cannot seem to reference the database table through Sequelize.
How do I reference an already-defined model in Sequelize outside the module it was defined in?
In the code below user
is passed via function(passport, user)
. Adding a third parameter to its call in server.js (e.g. require('./app/config/passport.js')(passport, data.user, data.hashedURL)
) does not fix the problem.
Below is what I think are the relevant portions. I can post more if need be. Error point is indicated by an arrow in passport.js
module below.
Thanks so much in advance for any light you can shed!
server.js
var express = require('express'),
expHandlebars = require('express-handlebars'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
app = express(),
fs = require('fs'),
path = require('path'),
passport = require('passport'),
flash = require('connect-flash');
var passport = require('passport');
var env = require('dotenv').config();
app.engine('handlebars', hbs = require('express-handlebars')
.create({
extname: '.handlebars',
defaultLayout: 'main',
layoutsDir: path.join(__dirname, '/views/layouts/'),
partialsDir: path.join(__dirname, 'views/partials/')
}).engine
);
app.set('view engine', 'handlebars');
app.set('views', path.join(__dirname, '/views'));
app.use(express.static(path.join(__dirname, '/public')));
//bodyParser
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
//passport
app.use(session(
{
secret: 'ahahawouldntyouliketoknow?',
cookie: {
maxAge: 259200, //30 days
secure: false
},
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());// session secret
app.use(flash());
//Models
var data = require('./app/data/');
//Routes
var authRoute = require('./app/routes/auth.js')(app, passport);
//load passport strategies
require('./app/config/passport.js')(passport, data.user);
app.listen(5000, function(err) {
if (!err) {
console.log("Site is live");
} else {
console.log(err);
}
});
/app/routes/auth.js
module.exports = function(app, passport) {
app.get('/', function (req, res, next) {
res.render('home', {
page_title: "Seeing is Believing",
inc_style: true,
style_sheet: "style/home.css",
});
});
//Routing for 'forgot password' functionality
app.get('/forgot', function(req, res) {
console.log("!" + req.flash('error'));
res.send();
});
app.post('/forgot', passport.authenticate('user-forgot-password', {
successRedirect: '/forgot',
failureRedirect: '/',
failureFlash: true
}));
...
};
/app/config/passport.js
var bCrypt = require('bcrypt-nodejs'),
LocalStrategy = require('passport-local').Strategy,
CustomStrategy = require('passport-custom').Strategy,
Sequelize = require('sequelize'),
verify = require('./verify');
module.exports = function(passport, user) {
var User = user;
var Hashed_URL = Sequelize.models("HashedURL");
console.log(Hashed_URL);
// Serialize User
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Deserialize User
passport.deserializeUser(function(user_id, done) {
User.findByPk(user_id).then(function(user) {
if (user) {
done(null, user.get());
} else {
done(user.errors, null);
}
});
});
//
function makeURL(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
for ( var j = 0; j < 5; j++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength)) + '-';
}
}
return result;
}
//
var generateHash = function(password) {
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
};
//Forgot password
passport.use('user-forgot-password', new CustomStrategy(function(req, done) {
console.log("0");
User.findOne({
where: {
'login_key': req.body.user_email
}
}).then(function(user) {
console.log("1");
if (!user) {
return done(null, false, {
message: "Unable to find username \'".concat(login_key).concat("\'.")
});
}
var randomURL = makeURL(39);
var data = {
hashed_url: randomURL,
uid: user.id,
email_info: "",
email_contents: "<h1>I LEIK PUGS</h1>",
attempts: 1
};
Hashed_URL.create(data).then(function(newURL, created) { <--- this is where the error occurs
if (!newURL) {
return done(null, false);
}
if (newURL) {
return done(null, newUser);
}
});
return done(null, user);
});
}));
...
};
/app/data/user.js
module.exports = function(sequelize, Sequelize) {
var User = sequelize.define('user', {
id: {
type: Sequelize.INTEGER.UNSIGNED,
allowNull: false,
unique: true,
autoIncrement: true,
primaryKey: true
},
...
});
return User;
};
/app/data/hashedURL.js
module.exports = function(sequelize, Sequelize) {
var hashed_URL = sequelize.define('HashedURL', {
expiration_time: {
type: 'TIMESTAMP',
allowNull: false,
defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
primaryKey: true
},
...
});
return hashed_URL;
};
/app/data/index.js
var fs = require("fs");
var path = require("path");
var Sequelize = require("sequelize");
var env = process.env.NODE_ENV || "development";
var config = require(path.join(__dirname, '..', '..', 'config', 'config.json'))[env];
var sequelize = new Sequelize(config.database, config.username, config.password, config);
var db = {};
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf(".") !== 0) && (file !== "index.js");
})
.forEach(function(file) {
var model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(function(modelName) {
if ("associate" in db[modelName]) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
Thanks to i.brod's comment I was able to solve the problem.
This is what I have right now:
auth.js
module.exports = function(app, passport) {
app.get('/', function (req, res, next) {
res.render('home', {
page_title: "Seeing is Believing",
inc_style: true,
style_sheet: "style/home.css",
});
});
//Routing for 'forgot password' functionality
app.get('/login', function(req, res) {
console.log(req.flash('error'));
res.send();
});
app.post('/login', passport.authenticate('user-login-email', {
successRedirect: '/dashboard',
failureRedirect: '/',
failureFlash: true
}));
app.get('/reset/?code=:hash', function(req, res, next) {
passport.authenticate('user-reset-password', {
successRedirect: res.render('inside', {
page_title: "Change Your Password",
portal: function() {
return "reset";
}
}),
failureRedirect: '/',
failureFlash: true
})(req, res, next);
});
app.post('/reset', function(req, res) {
console.log(req.flash('error'));
res.send();
});
...
};
passport.js
module.exports = function(passport, user) {
var User = user;
var Hashed_URL = db["hashed_url"];
passport.serializeUser((obj, done) => {
if (obj instanceof User) {
done(null, { id: obj.id, type: 'User' });
} else {
done(null, { id: obj.id, type: 'Hashed_URL' });
}
});
passport.deserializeUser((obj, done) => {
if (obj.type === 'User') {
User.findByPk(obj.id).then((user) => done(null, user));
} else {
Hashed_URL.findByPk(obj.id).then((hashedURL) => done(null, hashedURL));
}
});
//
function makeURL(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
for ( var j = 0; j < 8; j++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
if (i < (length - 1)) {
result += '-';
}
}
return result;
}
//
var generateHash = function(password) {
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
};
// Forgot password (send email)
passport.use('user-forgot-password', new CustomStrategy(function(req, done) {
User.findOne({
where: {
'login_key': req.body.user_email
}
}).then(function(user) {
if (!user) {
return done(null, false, {
message: "Unable to find username \'".concat(login_key).concat("\'.")
});
}
var randomURL = 'f' + makeURL(26);
var data = {
hashed_url: randomURL,
id: user.id,
email_info: "{'to':'[email protected]'}",
email_contents: "<h1>I LEIK PUGS</h1>",
attempts: 1
};
Hashed_URL.create(data).then(function(newURL, created) {
if (!newURL) {
console.log("A");
return done(null, false);
}
if (newURL) {
console.log("B");
return done(null, newURL);
}
});
});
}));
...
};
I do not think I altered anything else. Note: the random URL generator was just for testing, I think JWT or hashing would be more ideal for generating temporary secure URLs.
I'll try to post as much of the final program as I can on my git when it is complete.