Nodejs: Express + RedisStore, req.session undefined - node.js

I have done this before... I don't follow what I'm doing wrong this time, but I've been struggling for a couple of hours and now consider myself mentally blocked. The corresponding code:
app.use(express.bodyParser());
app.use(i18next.handle);
app.use(express.methodOverride());
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/views');
app.set('view engine', 'swig');
app.set('view cache', false);
var session_store = new RedisStore({ client : redis_client});
app.use(express.errorHandler({ dumpExceptions : true, showStack : true}));
app.use(express.cookieParser());
app.use(express.session({ store : session_store, secret : SESSION_SECRET, key : "sid" }));
app.use(app.router);
Then when handling requests, here's just an example:
app.get('/session_test', function (req, res, next) {
console.log(req.session); //undefined
});
Connection to redis is working just fine. No errors are shown. Then, when trying to access it from the request, the req.session is undefined. The browser is sending the correct sid.
I'm no expert on the exact flow that occurs during the request, but after debugging, it seems as if the router was being called before the session middleware.
Thanks in advance for any and all the likely help. I will provide any code I can, I'm unsure what might be of your help.
Here's more code.
server.js
//Dependency modules
var express = require('express'),
app = express.createServer(),
//Application dependency modules
settings = require('./settings'), //app settings
routes = require('./routes'), //http routes
rtroutes = require('./rtroutes'); //real time communication routes (io)
var io = require('socket.io').listen(app);
var appWithSettings = settings.setup(io, app);
routes.settings.setup(appWithSettings);
rtroutes.settings.setup(io, appWithSettings);
No routes are added until routes.settings.setup is called. settings (which is the global settings) is a pretty big file. That's where all configuration is done. Settings are not added until settings.setup method is called too. Here's a cut of the file:
//Dependency modules
var express = require('express'),
redis = require('redis'),
//Important configuration values
var SESSION_SECRET = 'some secret thing which doesnt belong to stackoverflow!',
insert_other_variables_here = "lalala";
//Computed general objects
var RedisStore = require('connect-redis')(express),
redis_client = redis.createClient(REDIS_PORT, REDIS_HOST);
exports.setup = function (io, app) {
app.configure(function () {
app.use(express.bodyParser());
app.use(i18next.handle);
app.use(express.methodOverride());
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/views');
app.set('view engine', 'swig');
app.set('view cache', false);
var session_store = new RedisStore({ client : redis_client});
app.use(express.errorHandler({ dumpExceptions : true, showStack : true}));
app.use(express.cookieParser());
console.log("ABOUT TO ADD SESSION STORE MIDDLEWARE");
app.use(express.session({ store : session_store, secret : SESSION_SECRET, key : "sid" }));
console.log("AND NOW ADDED THE SESSION STORE MIDDLEWARE");
app.use(app.router);
});
app.configure('development', function () {
//some things in here, but nothing that affects app. I have commented this
//for debugging and it changed nothing
});
app.configure('production', function () {
//mostly configuration for io and some caching layers, as well as servers info
app.use(express.errorHandler());
app.use(express.logger({ stream : logFile }));
});
app.listen(WEB_PORT);
return {
app : app,
//some other stuff that isn't relevant
}
}
I have 25 routes split in 4 different files (somehow I didn't have a need for session until now, since I was delaying some parts and everything needed was done with Mongoose). Here's an example of how it is being done (with fake names):
routes/index.js
export.settings = require("./settings");
routes/settings.js
exports.setup = function (app_settings) {
require("./route1")(app_settings);
require("./route2")(app_settings);
require("./route3")(app_settings);
};
Here's a stripped out "route1" file ("routes/route1.js"):
module.exports = function (app_settings) {
var app = app_settings.app;
console.log("ABOUT TO ADD ROUTES")
app.get("/signin", function (req, res, next) {
console.log(req.session); //this will be undefined
});
app.get("/register", function (req, res, next) {
});
app.get('/language', function (req, res, next) {
});
app.post('/settings', function (req, res, next) {
});
console.log("ADDED ROUTES NOW!")
}

Whenever you define a route, the router gets automatically inserted into whatever the middleware stack is at the time (subsequent attempts to insert it deliberately will be ignored). Are you sure you aren't defining any routes before you set the session handler?

Forgot to update this: Ebohlman set me in the right track.
It was i18next. When calling one of the init method it sets up routes and it was forcing app.router to be forced into the handle stack sooner. My bad, I didn't realize that part of the code was interacting with the app object and it did.
There was no way the question could have been answered better than how he did with the information I gave, so I am marking his answer as right.
I should try sleeping more v.v

Related

Code breaks once I start adding files to my controllers folder - why?

I am using node, express, fs and a few other things to create my first MVC framework app. I am currently googling around to find out more about an error I was getting, but am not finding the clarity I am looking for. Right now, I am not getting errors when I keep all my code in my server.js file. But that is not what MVC is all about, so at some point I created a users_controller.js file began to move the following routes into it (all except the ('/') route). As soon as I did that, everything broke!
The error I get is => TypeError: undefined is not a function
The line being referenced is => route.controller(app);
here is the code:
var express = require('express');
var logger = require('morgan');
var path = require('path');
var exphbs = require('express-handlebars');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var pg = require('pg');
var bcrypt = require ('bcrypt');
var fs = require('fs');
var app = express();
var db = require('./db.js');
app.listen(3000);
app.engine('handlebars', exphbs({defaultLayout: 'main', extname: 'handlebars'}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'handlebars');
//app.use(session({ secret: 'app', cookie: { maxAge: 60000 }}));
app.use(session({
secret: 'app',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static('public'));
app.use(logger('dev'));
// look in url encoded POST bodies and delete it
app.use(methodOverride(function(req, res) {
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
var method = req.body._method;
delete req.body._method;
return method;
}
}));
//says look in the controllers folder for these routes
// dynamically include routes (Controller)
fs.readdirSync('./controllers').forEach(function (file) {
if(file.substr(-3) == '.js') {
route = require('./controllers/' + file);
route.controller(app); ///// <================= error =======
}
});
////check if session does not exist
app.get('/', function (req, res) {
if(!req.session.name) {
res.redirect('/loginform');
} else {
res.send("WELCOME BACK" + req.session.name);
}
});
///////renders login form if not logged in
app.get('/loginform', function (req, res) {
res.render('login');
});
///authenticates a login
app.post('/login', function (req, res){
db.findByColumn('users', 'username', req.body.name, function (data){
console.log(data);
bcrypt.compare(req.body.password, data[0].password_digest, function (err, result){
res.session.currentUser = req.body.name;
res.send('You\'re logged in '+ req.body.name + ' Be kind.');
});
res.redirect('/home');
});
});
///render home page once logged in
app.get('/home', function (req, res){
res.render('home');
});
//////register form
app.get('/register', function (req, res){
res.render('register');
});
After spending a bunch of time trying to figure out why I was getting the error, I moved it back into the server file. But I still got the error. So I deleted the users_controller.js file (making the controllers folder empty again), and everything worked again! So it seems the minute I put a file in the controllers folder, even an empty file, my code breaks. Hmmm.
My guess it that since fs is telling my server to look in the controllers folder for it's routes, as long as there are no files in there, it will look back to server.js for routes. But if there are, it looks there first (is this correct logic?). With that said, I have a couple questions:
1) Why is it breaking when I throw these routes in what 'seems' like the appropriate place, a controller file inside the controllers folder? After all, the controllers folder is where the routes SHOULD be coming from, right?
Once this all sorted out...
2) Best Practice: I figured the forms are dealing with users so I would put them in the user controller - but would it be better practice to make a forms_controller.js?
All input is appreciated ;)
There was an underscore in my filename (forms_controller.js) that was throwing the error.

How do I write my Express session inside custom middleware?

This is my current code:
var express = require('express');
app.configure(function(){
app.use(express.static(_settings.c.WEB_PATH + '/public'));
app.use(_mods.web.mware.rawBody);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.methodOverride());
app.use(express.session({
cookie:{ domain:"."+_settings.c.SITE_DOMAIN, maxAge:1440009999},
secret:'password',
store: r_store,
}));
//other middleware here
});
I want to replace the session part with a custom middleware (in another file).
I will take out that session part and put this in:
var helper = require('helper.js');
app.use(helper.setSession);
In that file, I have this:
var express = require('express');
function setSession(req,res,next){
express.session({
cookie:{ domain:"."+_settings.c.SITE_DOMAIN, maxAge:1440009999},
secret:'password',
store: r_store,
})
next();
};
exports.setSession = setSession;
However, when I run it, the session isn't connecting.I don't know how to debug it.
app.use takes a function (or array of functions) with signature (err, )req, res(, next)
express.session() returns a function like any other middleware. You're never calling the function.
var express = require('express');
function setSession(req, res, next){
express.session({
cookie:{ domain:"."+_settings.c.SITE_DOMAIN, maxAge:1440009999},
secret:'password',
store: r_store,
})(req, res, next);
};
exports.setSession = setSession;

express 3.0 bodyParser not working properly

I am using latest version of express no.3 . I have read the docs and did exactly as was written but it is still not working as it suppose to .I get file in my upload dir after submit but then everything stops and callback function from app.post doesn't fire . The code:
HTML-JADE
form(action="/upload", method="post", enctype="multipart/form-data")
input(type="file", name="image")
input(type='submit', value='submit')
App.js
var express = require('express')
, user = require('./routes/user')
, http = require('http')
, path = require('path')
, mongo = require('mongodb')
, Server = mongo.Server
, Db = mongo.Db
, routes = require('./routes')
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser({uploadDir:'./upload'}));
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
});
app.post('/upload', function(req, res) {
console.log(req.files.image) // this doesn't fire at all - no matter what i write here
res.send(200) //doesn't run also
});
You need to return a response after reading the data. Without returning a response, express has no idea of when your response is finished and node will not close the connection to the client.
try this:
app.post('/upload', function(req, res) {
console.log(req.files.image);
req.on('data', function(raw) {
console.log('received data');
});
req.on('end', function() {
console.log('end');
res.send(200);
});
}
Try sending a simple response to the user.
app.post('/upload', function(req, res) {
console.log(req.files.image);
res.write('File Uploaded !!');
res.end();
}
Update
You should try changing the format to
app.post('/upload', function(err,req,res,next){
//Check for errors then handle it
}
Can't tell much until I know what errors you are getting, since file is being uploaded to upload dir bodyParser is working fine. Maybe your route is being handled by another function, or not handled at all. app.router is code that calls the callback .
When you do app.get('/upload', function(req, res) { ... }); it is the router that actually invokes the callback function to process the request. Can you confirm if you can do app.get('/upload',...); the html-jade file succesfully. If not then there is a problem in your routes.
Finally I found solution - that was because i used node 0.9.6 -pre. After change to 0.8.21 everything works fine.
Thanks all for your help.

node.js app.get not being called

total node.js noobie, started playing with demo codes from various tutorials and websites and I noticed something that I do not understand...
namely, if I have index.html in my /public folder, then
app.get("/", function (req, res) {
console.log("get /");
res.redirect("/test.html");
});
is simply never called. As soon as I rename index.html to index2.html then the method is called and I am redirected to /public/test.html
this is what I have:
var io = require('socket.io'),
express = require('express'),
MemoryStore = express.session.MemoryStore,
app = express.createServer(),
sessionStore = new MemoryStore();
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'
}));
app.use(express.static(__dirname + '/public'));
});
and the rest is pretty much taken from this tutorial: http://www.danielbaulig.de/socket-ioexpress/
The same issue appears with any other file. If i have /public/test.html, then when I call
http://localhost:8201/test.html
this app.get is not called:
app.get("/test.html", app.authenticateUser, function (req, res) {
console.log("get /test.html");
res.redirect("/test2.html");
});
When I remove the test.html then I get forwarded to test2.html...
The reason I am trying to redirect is if the user is not logged in I do not want him to open index.html but rather want to forward him to login.html, which is not possible if index.html exists. The only "solution" is to do it client side which sucks, I don't want index.html to load in the clients browser just to forward him to login.html, the server should, in my oppinion, handle that.
Problem is your static file middleware app.use(express.static(__dirname + '/public')) is "in front" of your router. When you write
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'
}));
app.use(express.static(__dirname + '/public'));
});
this is equivalent to
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'
}));
app.use(express.static(__dirname + '/public'));
app.use(app.router); //Express implicitly appends router middleware!
});
because Express implicitly appends router middleware at the end of stack if you don't add it somewhere explicitly. Now you clearly see that static file middleware is in front of router. If static file is found it is served by app.use(express.static(__dirname + '/public')) and router app.use(app.router) is never called. If you want your request to always pass through router you should put it in front, for example
app.configure(function () {
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'
}));
app.use(app.router); //Now router comes first and will be executed before static middleware
app.use(express.static(__dirname + '/public'));
});
It's because express filters the request before it gets to your code. It finds the file and returns it to the browser.
Solution is either to send an event via socket.io telling the code in user's browser to redirect or move file into private space (outside public directory) and serve it via "fs" as CydGy suggested.
this very good tutorial (http://www.danielbaulig.de/socket-ioexpress/) deals on sockets.
And i thinks isn't useful for this case.
So, look this:
app.get("/test.html", app.authenticateUser, function (req, res) {
but where is the app.authenticateUser ?
it is surely he who blocks
So, replaces it by:
app.get("/test.html", function (req, res) {
or modify your app.authenticateUser.
(And use the module fs to read your file, and then, you can res.send(file);)
Don't forget to write .html in your url, else, you have to replace "/test.html" by "/test")
I hope it will help you.
It is because the below code is never called!
app.get("/", function (req, res) {
console.log("get /");
res.redirect("/test.html");
});
As app.use(app.router); is depreciated.All you got to do is write your code above this line
app.use(express.static(__dirname + '/public'));
Should be something like this
app.get("/", function (req, res) {
console.log("get /");
res.redirect("/test.html");
app.use(express.static(__dirname + '/public'));
app.get("/", function (req, res)...
Try this
app.get('/', function (req, res)...
Uri path must be ' single quoted.

How do I generate CSRF tokens in Express?

newbie.
I'm using ExpressJS/Node. Here's my config stuff:
var express = require('express'),
app = express.createServer(),
jade=require('jade');
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.use(express.logger());
app.use(express.cookieParser());
app.use(express.session({ secret: "secretive secret" }));
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(require('stylus').middleware({ src: __dirname + '/public' }));
app.use(app.router);
app.use(express.static(__dirname + '/public'));
app.use(express.csrf());
I found csrf.js in Express directories, and see that it should be generated and assigned to req.body._csrf, but I'm not sure how to access it.
Here's the csrf.js code
module.exports = function csrf(options) {
var options = options || {}
, value = options.value || defaultValue;
return function(req, res, next){
// generate CSRF token
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
// ignore GET (for now)
if ('GET' == req.method) return next();
// determine value
var val = value(req);
// check
if (val != token) return utils.forbidden(res);
next();
}
};
Help? Thanks!
Dynamic helpers has been removed from Express since 3.x.
The new usage would be app.use(express.csrf());, which comes from Connect.
Add the token to dynamic helpers.
app.dynamicHelpers({
token: function(req, res) {
return req.session._csrf;
}
});
Reference it in your jade template.
input(type='hidden', value=token)
Source: http://senchalabs.github.com/connect/middleware-csrf.html
In Express 4.x this middleware is removed. For Express 4.x you can do it as follows
var csrf = require('csurf');
app.use(csrf());
Ah!! you need to register the csrf middleware after your session and cookieParser middleware.
Inside Route Or Ctrl
res.render('someform', { csrf: req.csrfToken() });
or You can set a local variable also like so
app.use(function(req, res, next){
res.locals.csrf = req.csrfToken();
});
Then in view
input(type="hidden", name="_csrf", value="#{csrf}")
You are done!! :)
If you also want to set a secure cookie for your CSRF token that can be read by your frontend (angular for example), you can do this:
app.use csrf()
app.use (req, res, next) ->
res.cookie('XSRF-TOKEN', req.csrfToken(), {secure: true})
next()

Resources