Path in node with parameter passed is not found - node.js

I am trying to get a page with express-router when inside of the url :id is supplied as a parameter using passport custom callback and the url is somehow not found. Here is what I have in the main file:
var app = express();
var index = require('./routes/index');
app.post('/login', function(req, res, next) {
passport.authenticate('local-signup', function(err, user, info) {
console.log('passport callback');
console.log(err);
console.log(info);
if (err) { return next(err); }
if (!user) { return res.status(401).json(info); }
req.logIn(user, function(err) {
console.log('logIn function of /login path');
if (err) { return next(err); }
return res.redirect('/auth/' + user.local.username + '/');
});
})(req, res, next);
console.log('end of login function');
});
app.use('/auth/:id/', passport.authenticate(['facebook-token', 'local-signup']), index);
And inside the index I have:
router.get('/auth/:id/', function(req, res) {
console.log("router of index.js is sending app.html");
var appPath = path.join(__dirname, '..', 'public', 'app.html');
res.sendFile(appPath);
});
I see the redirect to /auth/nik1989/ happening, but the url is not found.

Reading from Express 4.x API - Router
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
// ..
});
// only requests to /calendar/* will be sent to our "router"
app.use('/calendar', router);
Following the example to call events end point you have to do /calendar/events.
Now in your case the way you inject the middleware clearly wrong
router.get('/auth/:id/', function(req, res) {
console.log("router of index.js is sending app.html");
var appPath = path.join(__dirname, '..', 'public', 'app.html');
res.sendFile(appPath);
});
app.use('/auth/:id/', passport.authenticate(['facebook-token', 'local-signup']), index);
cause the url that you have to call is /auth/:id/auth/:id/.
If you breakdown above code what you are doing is somethink like this
app.use('/auth/:id/',passport..., router.get('/auth/:id/'...)
There are many ways to fix it I have put some examples below.
Examples
Working example one
router.get('/:id', function(req, res) {
console.log("router of index.js is sending app.html");
var appPath = path.join(__dirname, '..', 'public', 'app.html');
res.sendFile(appPath);
});
app.use('/auth', passport.authenticate(['facebook-token', 'local-signup']), index);
Working example two
router.get('/auth/:id', function(req, res) {
console.log("router of index.js is sending app.html");
var appPath = path.join(__dirname, '..', 'public', 'app.html');
res.sendFile(appPath);
});
app.use(passport.authenticate(['facebook-token', 'local-signup']), index);

This should the cause
app.use('/auth/:id/', passport.authenticate(['facebook-token', 'local-
signup']), index);
you already have a route in your index.js file thats has the same url structure
/auth/:id/
when you use app.use('/account', accoutRouter);
it means every other route called by his app .use middleware will have
account/ prepend to it e.g account/login, account/register
i didn't see passport initialization in your code
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());
but i believe using
router.get('/auth/:id/', function(req, res) {
console.log("router of index.js is sending app.html");
var appPath = path.join(__dirname, '..', 'public', 'app.html');
res.sendFile(appPath);
});
and
app.use('/auth/:id/', passport.authenticate(['facebook-token', 'local-
signup']), index);
will definitely cause errors

Related

nodejs express.router with parameters

Problem
I am using a nodejs application with the express module. To have a structure I split the routes into a extern routes.js. I want give this route.js next to the req and res parameters some other parameters who will be needed. But I donĀ“t know how I can do it.
Index.js
const app = express();
app.use(session({
secret: uuidv4(),
resave: true,
saveUninitialized: true
}));
app.use(helmet());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use('/', express.static(path.join(__dirname, '/site/static')));
app.use('/', routes);
routes.js
module.exports = (function() {
'use strict';
let router = require('express').Router();
router.get('/', (req, res) => {
if(!req.session || req.session.key !== loginkey) {
res.redirect('/login');
} else {
res.redirect('dashboard');
};
});
router.get('/dashboard', (req, res) => {
if(req.session && req.session.key === loginkey) {
helper.render(req, res, "sites/dashboard");
} else {
res.redirect('/');
};
});
router.get('/login', (req, res) => {
log.LogLine(3, "GET /login");
helper.render(req, res, "sites/login");
});
router.get('/logout', (req, res, next) => {
log.LogLine(3, "GET /logout");
if (req.session) {
req.session.destroy(function(err) {
if(err) {
return next(err);
} else {
return res.redirect('/');
};
});
};
});
return router;
})();
If you want to pass something along from index.js to your routes in routes.js then you can do the following.
In your routes.js, you could accept some parameters:
module.exports = function(arg1, arg2) {
let router = require('express').Router();
router.get('/', (req, res) => {
// You can now use arg1 and arg2 here
});
// ...
return router;
};
Note, you'll need to remove your IIFE to stop the function from being immediately invoked.
Then in index.js, you can invoke the function and pass in whatever you want:
app.use('/', routes('something', 'something else'));
I hope this helps.

Route callbacks not executing but middleware is

So this project was working fine before today, but after a bit of a nooby mistake with git I broke my project, and was unable to recover the commit. After spending some time getting everything fixed, my routes are now broken. My issue is that when calling my API routes now the server hangs for exactly 1 minute, then times out and logs a 404 on the server.
To give some background I'm using this boilerplate. In my debugging process I basically put console.logs everywhere I possibly could, and it looks like all my initialization middleware for express and passport are working fine, and my code is getting to where the routes are defined with no errors.
Middleware with app.use works and all checks out when a request is made, and all console.logs I've put there show fine. The console.logs only stop appearing in the final route definition like in this example:
app.get('/route', function(req, res, next) {
console.log('this never shows');
next();
}, function(req, res, next) {
console.log('this never shows');
})
My actual routes do have a res.send(), this is just an example to show you. All the console.logs I put in the middleware before this route show when the request is made, so it is hanging somewhere in app here.
It's a rather large project, so if you want specific code examples just ask and I'll post it. But I was able to recover all the important files that I had saved somewhere else and I'm pretty sure all my code is back to how it was before now.
edit:
Here is my file with express middleware definitions:
config/express.js
/**
* Module dependencies.
*/
var express = require('express');
var MongoStore = require('connect-mongo')(express);
var flash = require('connect-flash');
var helpers = require('view-helpers');
var swig = require('swig');
var session = require('express-session');
module.exports = function (app, config, passport) {
app.set('showStackError', true);
// should be placed before express.static
app.use(express.compress({
filter: function (req, res) {
return /json|text|javascript|css/.test(res.getHeader('Content-Type'));
},
level: 9
}));
app.use(express.favicon());
app.use(express.static(config.root + '/public'));
app.use('/uploads', express.static(config.root + '/uploads'));
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header("Access-Control-Allow-Headers", "Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.status(204).end();
}
else {
next();
}
};
app.use(allowCrossDomain);
// don't use logger for test env
if (process.env.NODE_ENV !== 'test') {
app.use(express.logger('dev'));
}
// set views path, template engine and default layout
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
app.set('views', config.root + '/app/views');
app.set('view cache', process.env.NODE_ENV !== 'development');
app.configure(function () {
// dynamic helpers
// app.use(function(req,res,next){
// req.locals.session = "eeeeeeee";
// next();
// });
// cookieParser should be above session
app.use(express.cookieParser());
// bodyParser should be above methodOverride
app.use(express.bodyParser());
app.use(express.methodOverride());
// express/mongo session storage
app.use(function(req, res, next) {
if(!req.cookies['_ga']) {
next();
}
else {
session({
secret: 'secrettexthere',
saveUninitialized: true,
resave: true,
store: new MongoStore({
url: 'mongodb://localhost/traderdb',
db: 'traderdb',
collection: 'sessions',
auto_reconnect: true
})
})(req, res, next);
}
});
// connect flash for flash messages
app.use(flash());
app.use(function (req, res, next) {
res.locals.session = req.session;
res.locals.req = req;
next();
});
app.use(function(req, res, next) {
if(!req.cookies['_ga']) {
next();
}
else {
passport.initialize()(req, res, next);
}
});
//app.use(helpers('app name'));
//
// use passport session
app.use(function(req, res, next) {
if(!req.cookies['_ga']) {
next();
}
else {
passport.session()(req, res, next);
}
});
// routes should be at the last
app.use(app.router);
// assume "not found" in the error msgs
// is a 404. this is somewhat silly, but
// valid, you can do whatever you like, set
// properties, use instanceof etc.
app.use(function(err, req, res, next) {
// treat as 404
if (~err.message.indexOf('not found')) return next();
// log it
console.error(err.stack);
// error page
res.status(500).render('500', { error: err.stack });
});
// assume 404 since no middleware responded
app.use(function(req, res, next) {
res.status(404).render('404', { url: req.originalUrl, error: 'Not found' })
});
})
}
I also have another file with passport route definitions if you'd like to see that too, but all that is tested and works okay too.
edit 2:
This is my entry point file:
server.js
/**
* Module dependencies.
*/
var express = require('express')
, fs = require('fs')
, passport = require('passport');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Load configurations
// if test env, load example file
var env = process.env.NODE_ENV || 'development'
, config = require('./config/config')[env]
, auth = require('./config/middlewares/authorization')
, mongoose = require('mongoose');
// Bootstrap db connection
mongoose.connect(config.db);
// Bootstrap models
var models_path = __dirname + '/app/models'
fs.readdirSync(models_path).forEach(function (file) {
require(models_path+'/'+file);
});
// bootstrap passport config
require('./config/passport')(passport, config);
var app = express();
// express settings
require('./config/express')(app, config, passport);
// Bootstrap routes
require('./config/routes')(app, passport, auth);
// Start the app by listening on <port>
var port = 3002;
app.listen(port);
console.log('Express app started on port '+port);
// expose app
exports = module.exports = app;
edit 3:
Here are my route definitions:
config/routes.js
var express = require('express');
var path = require('path');
var fileManager = require('express-file-manager');
var mongoose = require('mongoose');
var Session = mongoose.model('Session');
module.exports = function (app, passport, auth) {
var users = require('../app/controllers/users');
var coupons = require('../app/controllers/coupons');
var magazines = require('../app/controllers/magazines');
var zones = require('../app/controllers/zones');
var transactions = require('../app/controllers/transactions');
var favorites = require('../app/controllers/favorites');
var banners = require('../app/controllers/banners');
var reports = require('../app/controllers/reports');
var coverContest = require('../app/controllers/coverContest');
var contactMessage = require('../app/controllers/contactMessage');
app.post('/api/users/login', users.login);
app.post('/api/users/register', users.register);
app.post('/api/users/logout', users.logout);
app.post('/api/users/sendResetEmail', users.sendResetEmail);
app.post('/api/users/changePassword', users.changePassword);
app.post('/api/users/redeemCoupon', isValidAppUser(), users.redeemCoupon);
app.get('/api/users/validate', isLoggedIn(0), function(req, res) {
res.send(req.user);
});
app.post('/api/coupons', coupons.get);
app.post('/api/coupons/import', isLoggedIn(0), coupons.import);
app.post('/api/coupons/remove', isLoggedIn(0), coupons.remove);
app.post('/api/coupons/upload', isLoggedIn(0), coupons.upload);
app.post('/api/transactions', transactions.get);
app.post('/api/allTransactions', isLoggedIn(0), transactions.getAll);
app.post('/api/magazines', magazines.get);
app.post('/api/magazines/import', isLoggedIn(0), magazines.import);
app.post('/api/magazines/remove', isLoggedIn(0), magazines.remove);
app.post('/api/banners', banners.get);
app.post('/api/banners/import', isLoggedIn(0), banners.import);
app.post('/api/banners/remove', isLoggedIn(0), banners.remove);
app.post('/api/favorites', isValidAppUser(), favorites.get);
app.post('/api/favorites/import', isValidAppUser(), favorites.import);
app.post('/api/zones', zones.get);
app.post('/api/zones/add', zones.add);
app.post('/api/zones/addCoupon', zones.addCoupon);
app.post('/api/zones/addMagazine', zones.addMagazine);
app.post('/api/mail/ccSubmit', coverContest.ccSubmit);
app.post('/api/mail/contactSubmit', contactMessage.contactSubmit);
//app.get('/api/reports/siteUsers', reports.siteUsers);
app.get('/auth/facebook', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me'], failureRedirect: '/login' }), users.signin);
app.get('/auth/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login' }), users.authCallback);
app.get('/auth/github', passport.authenticate('github', { failureRedirect: '/login' }), users.signin);
app.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: '/login' }), users.authCallback);
app.get('/auth/twitter', passport.authenticate('twitter', { failureRedirect: '/login' }), users.signin);
app.get('/auth/twitter/callback', passport.authenticate('twitter', { failureRedirect: '/login' }), users.authCallback);
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/', successRedirect: '/main.html' }));
}
function isLoggedIn(secLvl) {
return function(req, res, next) {
if(req.isAuthenticated() && req.user.secLvl <= secLvl && req.user.google.email.includes('#bizpub36.com')) {
return next();
}
res.redirect('https://accounts.google.com/logout');
}
}
function isValidAppUser() {
return function(req, res, next) {
Session.findOne({ sess_id: req.body.sess_id }).exec(function(err, session) {
if(!err && session) {
next();
}
else {
res.end({ status: 'error', message: 'invalid session' });
}
});
}
}
If app.use works, my guess would be your protocol, is the app.get correct? You issue is otherwise located somewhere else in your code base as your sample runs fine as a single route express app.
It sounds like one of three things:
Somewhere in your middleware chain, you are not calling next() to allow it to advance to the next level of handlers and thus the request just eventually times out waiting for that middleware to finish (this seems to match the symptoms you describe).
Somehow, your app.get() doesn't actually match the route you expect it to or is not specified correctly.
You're using a router, but have not configured it correctly.
But, because you don't get an immediate 404, but rather it times out, it is probably option #1 above.

req.session undefined in route

I'm building a simple site with expressjs and passportjs and I'm running into the problem that I can't access session variables in my routes.
There are a lot of threads with this topic but the solutions don't work for me. It looks like my error is somewhere else.
My app is configured like this:
app.configure(function() {
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({
path: '/',
secret: 'very secret'
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
Once passport verified the twitter account it's redirected to this site:
app.get('/auth/twitter/callback',
passport.authenticate('twitter', {
failureRedirect: '/login'
}),
function(req, res) {
res.redirect('/');
console.log("populate session")
populateSession(req, res);
});
This works, as I'm seeing the "populate session" output in the console if I'm logged in.
The populateSession() looks like this:
function populateSession(req, res) {
User.findOne({
twitterID: req.user.id
}, function(err, result) {
if (result) {
// Store data to session
req.session.twitterAccessToken = result.twitterAccessToken;
req.session.twitterAccessTokenSecret = result.twitterAccessTokenSecret;
req.session.lastfmAccountName = result.lastfmAccountName;
console.log("in session: " + req.session.lastfmAccountName)
}
})
}
"in session" is printed the right way. So the session itself works. Now my problem is that I want to have access to my session variables in routes because I want to pass them to my view templates like this:
app.get('/account', ensureAuthenticated, function(req, res) {
console.log(req.session)
console.log("lastfm nick " + req.session.lastfmAccountName)
res.render('account', {
user: req.user,
lastfmnick: req.session.lastfmAccountName
});
That's where I'm running into the problems. req.session contains all the twitter fields passport is populating it with but req.session.lastfmAccountName is undefined.
Any idea what's wrong there or is there a better way to pass variables to the view? I feel like it's not a good idea to have DB queries for the fields in all my routes if it could just be stored in the session.
Thanks!
The session will automatically be saved when the response ends, in this case by res.redirect(), which is done before the modifications are made to the session.
function(req, res) {
res.redirect('/'); // ends the response, saving the session
populateSession(req, res); // modifies the session without saving
});
Since .findOne() is asynchronous, if you revise populateSession() to take and call a callback when the find completes, you can control the order so the session is modified first:
function populateSession(req, res, next) {
User.findOne({
twitterID: req.user.id
}, function(err, result) {
if (result) {
// ...
}
if (next) next(err);
})
}
app.get('/auth/twitter/callback',
/* ... */,
function(req, res) {
populateSession(req, res, function () {
res.redirect('/');
});
});
It also allows you to use populateSession as middleware:
app.get('/auth/twitter/callback',
/* ... */,
populateSession,
function(req, res) {
res.redirect('/');
});
app.use(lib.express.cookieParser(lib.config.cookieSecret));
app.use(lib.express.session({
secret: 'very secret'
})
}));
This two line should be consecutive and in that order.

I want to redirect to a 404 page if did not find an id

I want to redirect to a 404 page if did not find an id
page routes/users.js
exports.find = function(req, res) {
var id =(req.params.id);
db.getFindById(id,function(err, results){
if (err) return res.send(500, "DB QUERY ERROR");
res.render('usr/details', { finds: results });
});
}
page index.js
app.configure(function(){
app.set('views', __dirname +'/views');
app.set('view engine','jade');
app.use(express.bodyParser({KeepExtensions: true, uploadDir: path.join(__dirname, '/public/img/user-avatar')}));
app.use(express.methodOverride());
app.use(checkDatabase, function(req, res) {res.send(404, "Could not find ")});
app.use(passport.initialize());
app.use(express.static(path.join(__dirname, 'public')));
});
app.get('/list-users/finds/:id',checkDatabase);
You'll have to add next in the parameter list, which Express will pass to your handler. It will move to the next function in the middleware stack.
Then, if no id matches, do return next() to leave the function and move on to a function that will handle your 404.
exports.find = function (req, res, next) {
var id = (req.params.id);
db.getFindById(id, function (err, results) {
// Query failed, note the return to quit the function here.
if (err) return res.send(500, "DB QUERY ERROR");
// Move to next function in middleware steck if result set is empty
if (!results || !results.length) return next();
// We will not get to this call unless the resultset is populated
res.render('usr/details', {
finds: results
});
});
}
You can then use a new function after this one, which will run in the case next is called.
app.use(user.find, function(req, res) {
res.send(404, "Could not find ")
};
EDIT: What you propably want:
index.js
app.configure(function () {
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser({
KeepExtensions: true,
uploadDir: path.join(__dirname, '/public/img/user-avatar')
}));
app.use(express.methodOverride());
app.use(passport.initialize());
app.use(express.static(path.join(__dirname, 'public')));
});
app.get('/list-users/finds/:id', user.find, function (req, res) {
res.send(404, "Could not find ID");
});
routes/users.js
exports.find = function (req, res, next) {
var id = (req.params.id);
db.getFindById(id, function (err, results) {
// Query failed, note the return to quit the function here.
if (err) return res.send(500, "DB QUERY ERROR");
// Move to next function in middleware steck if result set is empty
if (!results || !results.length) return next();
// We will not get to this call unless the resultset is populated
res.render('usr/details', {
finds: results
});
});
}

How to keep a user logged on? Is it possible with ExpressJS and Passport?

I have a server in node.js using express and passport with the passport-local strategy.
I have the users in the database and through passport I'm able to authenticate them, unfortunately when a second request comes from the same client the req.isAuthenticated() method returns false.
There is also no user in the request (req.user = undefined).
I've also checked and when doing the authentication although I get back a user from passport.authenticate('local'... I do not get req.user populated then. If I try to set it up manually it just doesn't propagate for following requests.
I don't understand what I'm doing wrong, here is my code.
server.js
var express = require('express'),
compass = require('node-compass'),
routes = require('./server/routes')
http = require('http'),
path = require('path'),
passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
Database = require('./server/repositories/database'),
Configuration = require('./server/config').Config,
crypto = require('crypto');
var app = express();
app.enable("jsonp callback");
passport.use(new LocalStrategy(
function(email, password, done) {
process.nextTick(function () {
var userService = new UserService();
userService.login(email, crypto.createHash('md5').update(password).digest("hex"), function(error, user) {
if (error) done(error, user);
else if (!user) return done(null, false, { message: 'wrong credentials'});
return done(null, user);
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
var userService = new UserService();
userService.findById(id, function(err, user) {
done(err, user);
});
});
app.configure(function(){
app.set('port', Configuration.Port);
app.set('views', __dirname + '/app/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(compass({
project: path.join(__dirname, 'app'),
sass: 'styles'
}));
app.use(express.session({ secret: 'keyboard cat' }));
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'app')));
});
routes.configure(app);
Database.open(function() {
app.listen(Configuration.Port, function() {
console.log("Express server listening on port " + Configuration.Port);
});
});
routes.js
var Configuration = require('./config').Config;
var ApiResult = require('../model/apiResult').ApiResult;
var ApiErrorResult = require('../model/apiErrorResult').ApiErrorResult;
var ApiReturnCodes = require('../model/apiReturnCodes').ApiReturnCodes;
var passport = require('passport');
var usersController = require('./controllers/usersController');
exports.configure = function(app) {
function ensureAuthenticated(req, res, next) {
console.log(req.isAuthenticated());
if (req.isAuthenticated()) { return next(); }
else {res.send(new ApiErrorResult(ApiReturnCodes.NOT_LOGGED_IN, null));}
}
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err || !user) { console.log(info); res.send(new ApiErrorResult(ApiReturnCodes.ENTITY_NOT_FOUND, null)); }
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user
else res.send(new ApiResult(user));
})(req,res,next);
});
app.get('/anotherLink', ensureAuthenticated, function(req, res, next) {
res.json({Code:0});
});
}
When I hit the link /anotherLink after being authenticated I get res.isAuthenticated() as false.
Also when I see the req.session after the ensureAuthenticated is called I get:
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: {} }
What am I missing for it to save the information that that user is authenticated?
On the client side I'm using Angular only doing a simple get with the url without parameters.
If I forgot to put something here just tell me, I'll update it.
Any help will be greatly appreciated. Thanks
So I found out what was wrong with my code.
My passport.deserializeUser method used the method userService.findById
And that called the repository... like this:
userRepository.findUnique({"_id": id}, callback);
because the id was generated by MongoDB the correct call needs to be:
userRepository.findUnique({"_id": new ObjectID(id)}, callback);
I hope this saves some time to the next person with the same problem.
With this detail, this code should work nicely for everyone wanting to use the LocalStrategy on the Passport framework.

Resources