Getting rid of session and socket pooling sailsjs - node.js

Hi I am current working on my rest api app using sails. I was reading the following article
http://engineering.linkedin.com/nodejs/blazing-fast-nodejs-10-performance-tips-linkedin-mobile
In point 2 it was suggested to get rid of socket pooling
var http = require('http');
var options = {.....};
options.agent = false;
var req = http.request(options)
and in point 7 it suggest to get rid of session by removing.
app.use(express.session({ secret: "keyboard cat" }));
I am wondering how I can do that in sails.

For Sails v0.11x, you should use the recommended approach of editing .sailsrc file, and setting:
{
"hooks": {
"session": false,
// also useful when building an API
"grunt": false,
}
}

In Sails.js v0.10 you can disable the session by adding the following key to your config/express.js file:
middleware: {
session: null
}
As far as socket pooling goes, I think they're talking about making http requests from the server, and just suggesting that when making such requests, you set the agent option to false.

Related

How can I get (Express's) sessionID for a SockJS connection

I am using SockJS on Express server. Is there any way to get the associate HTTP session ID of the client?
I see there is a way to do it for raw web socket and Socket.io, but I am struggling to find how to do it for SockJS.
This is how my server looks like. I want a similar handler to fetch session ID:
var sockjs_echo = sockjs.createServer(sockjs_opts);
sockjs_echo.on('connection', function(conn) {
conn.on('data', function(message) {
conn.write(message);
});
});
This is a "hack", but it works for me:
sockjs_echo.on('connection', function(conn) {
var cookieHeader = conn._session.recv.ws._stream._readableState.pipes._driver._request.headers.cookie
var cookies = {}
cookieHeader.split(';').forEach(function( cookie ) {
var parts = cookie.split('=');
cookies[parts.shift().trim()] = decodeURI(parts.join('='));
});
conn.on('data', function(message) {
conn.write(message);
});
});
'cookies' variable (example):
{
"dev_cookie": "1mimec6rbcolp0ujkcbqq9pdq4uoa5v0p8a284v32tmd4q3k0qi9p4vjteoifdn9b0lsm238fghf974o9jfehfuhvm3ltrgq02ad6k0",
"session_cookie": "s%3AjkKYPKFFT8r60rXUsVYISoOF17o49GUl.pbpu6T1%2BcdrIu5uQPRxZUYOrl5GnC179GaI5pWyR7SA",
"other_cookie": "s%3AzRMiC3fjo4gxTXX1p2XSi_C_EydIa358.KAdP1gwtZBVfcbkmwi%2B3pa0L1pbOCzQ3lHnNEyFvvHc"
}
Thanks so much for asking this question, #darwinbaisa, and for the answer, c-toesca. This came after days of searching.
For XHR streaming, the cookies are at: conn._session.recv.request.headers.cookie.
The only other way I could think of doing this was to make the express session cookie httpOnly: false, thus exposing it to javascript and, of course, the possibility of hacking, then pass it back as a prefix to any message from the SockJS javascript client to the node server.
Or to assign the ID to a javascript variable as I dynamically wrote a web page response, so that javascript would have access to the variable, and again could return it to the server. But again, this would have exposed the ID, and even if the ID was hashed or encrypted, it could still be used in a malicious call to the server from javascript.
Things like this are made a lot easier in the node WS library, but I need a fallback from that for websocket-challenged browsers.

connect-redis in Nodejs

I have nodejs/express/redis/express-session in use in my nodejs application (express 4.x)
The redis initializing is done by connect-redis/session framework under hood. So far it works. Now I need to use redis to store other data in addition to session, and world like to have a new store other than the session store. Is it just one store possible?
And is it possible to use the redis client initialized by connect-redis/session if only one store is possible? how to get it?
Thanks for the help!
The code now is:
var express = require('express');
var session = require('express-session');
// pass the express to the connect redis module
// allowing it to inherit from session.Store
var RedisStore = require('connect-redis')(session);
....
// Populates req.session
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'keyboard cat',
store: new RedisStore
}));
You'll actually want to initialize a new client for anything else, as the session library is handling it's own client under the hood.
You should most likely import the redis library itself, make your own client, and use that for all future requests / etc.
When I put following code after the code above, I got error
"myRedis Error-> Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED". It seems it is not allowed to init a new Redis instance.
So is there a way to have new client from connect-redis?
var myRedis = require('redis'); // additional redis store
var myRedisCli = myRedis.createClient();
myRedisCli.on('error', function (err) {
console.log('myRedis Error-> ' + err);
});

Node.js - Trying to avoid globals...how do I keep track of a user object?

Ok, so here is the scenario. I have the user log into my app with facebook. When this happens Passport saves it to the Session (req.user). This works all well and good when I am working in a page that has access to the request object, but I find myself in the situation where I don't have access to request, but I need to check the user object.
Case in point. I am using socket.io and when I am working with the sockets and the methods surrounding them, I don't have access to the request object and therefore I can't get user info.
I keep hearing that I need to stay away from globals whenever possible, but I can't see a way around it.
Thoughts?
Below is an example of me working with sockets. This module is called from my server.js file.
function loadSockets(io)
{
var articleCommand = require('./middleware/ArticleCommand');
io.sockets.on('connection', function (socket) {
socket.on('getArticles', function(){
if (NEED USER INFO HERE !== null){
articleCommand.getArticlesByUser(NEED USER INFO HERE, function(error, articles){
io.sockets.emit('articlesRetrieved', error, articles);
});
}
});
});
}
exports.loadSockets = loadSockets;
Update
Ok, so based on the commenters advice I have installed this: https://github.com/aviddiviner/Socket.IO-sessions and applied it...but my session is always null in my sockets.
Here is what I have.
var socket = sio.enable({
socket: io.listen(server, {'log level': 1, 'heartbeat': false}),
store: mystore, // this is my Redis store
parser: express.cookieParser()
});
later on...when processing my sockets
socket.sockets.on('connection', function (socket, session) { ...
The session is always null...even though my passport has loaded up my session correctly.
Thoughts?
Ok, so for posterity's sake, here is what I did to fix this issue.
You can see from my update above that I tried to use the SocketIO-sessions module, but that didn't work.
After more research I found that I needed to make sure I got the passport session since that is what is doing my authentication.
I found this little gem: https://github.com/jfromaniello/passport.socketio
This worked like a charm. The only thing that took some figuring out is getting the key setup correctly (they assume you know how to do that in the example).
sio.set("authorization", passportSocketIo.authorize({
key: 'MYKEY',
secret: 'SECRET',
store: mySessionStore
}));
Out of the box, your key is not set. To do that simply set it up with your app like so:
app.use(express.session({
secret: "SECRET",
store: mySessionStore,
key: 'MYKEY',
cookie: { secure: false, maxAge:86400000 }
}));
Hope this helps someone.
David

Not cookie based session management in node.js

I am looking for a non-cookie based session management in node.js, something like pass a parameter in the URL like &session_id=. It will know that a session has expired when a request comes with an session_id. I've looked at connect library, but it looks that it is cookie based only.
Warning
Passing the session id as a GET parameter is considered bad practice. Why? It is dangerous because people don't usually care about session id and they will probably publish/share links with their session ids inside.
It's also a problem because when a user clicks an external link on your web, and goes to another site, that new site will be able to see the session_id in the referrer link.
So I don't think it is a good idea. Cookies are more secure.
Have a look at: Session Hijacking
For every request you receive, you will get all of the client cookies accordingly.
You can also set client cookies in the response HTTP headers using "Set-Cookie."
Using a GET parameter is unsafe. Any user could accidently share their session ID, but if you want 100% security, I'd share session IDs via cookies, and I would use HTTPS to prevent snoopers from stealing cookies.
You can use localstorage or sessionStorage..
almost same as cookie
not a cookie
better than a cookie!
More info: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage
It's very -very- easy to use... in Js for example:
<script>
// check if Storage is avaible
if(typeof(Storage)!=="undefined") {
// Save data to local storage (no exiparion date)
localStorage.setItem("name_always", "bxx");
// Save data to the current session (removes when the tab is closed)
sessionStorage.setItem("name_now", "bxx");
} else {
// No Storage support...
}
// Access to stored data
alert( "For only now, my name is: " + sessionStorage.getItem("name_now"));
alert( "Every day, my name is: " + localStorage.getItem("name_always"));
</script>
Tags: javascript html5 local-storage session-storage
You can use sessions with a store in node.js. For example, you have express application and want to use session like system in your webapp. You can use connect-mongo module for this. This will let you store your session in db. In your app.js
var express = require('express'),
, mongoStore = require('connect-mongo')(express);
var app = express();
app.configure('all', function () {
app.use(express.session({
secret: "terces",
cookie: { maxAge: 24 * 60 * 60 * 1000 },
store: new mongoStore({
url: your_db_url
})
}));
app.use(function(req, res, next) {
res.locals.session = req.session;
next();
});
});
With basic code above, you have session in express that you can use it in your controllers and views directly. In your controller;
app.post('/blog/create/?', function(req, res, next) {
if (!req.session.user) {
next("You need to login in order to create blog!");
}
});
In your view, you can use session.user in order to generate profile menu for example.

Shared Sessions between Node Apps?

I currently have two separate node apps running on two different ports but share the same backend data store. I need to share users sessions between the two apps so that when a user logs into through one app, their session is available and they appear to logged into the other app. In this case, its' a public facing website and an administrative backend.
Our setup is the following:
node with express
passport is being used to handle auth with Local Strategy
we're using connect-redis to allow us to share sessions via redis.
our domains look like this: www.mydomain.com and adm.mydomain.com
The config for for session stuff (and redis) is the same for both apps:
session: {
options: {
secret: "my secret",
cookie: {
domain: "mydomain.com",
maxAge:1000*60*60*24
}
},
redis: {
host: 'my host',
maxAge: 86400000,
secret: "my secret"
}
}
The config for session stuff in app.js looks like this:
if ( app.settings.env === "production" ) {
session.options.store = new RedisStore(session.redis);
}
app.use(express.session(session.options));
app.use(passport.initialize());
app.use(passport.session({ secret: 'a different secret' }));
What I expect it to do: Allow us to see the same session id in the cookie between the two apps.
So my question is: How do I set up express, redis and passport so that you can have sessions shared across different subdomains?
Maybe a bit outdated, but at this time, Express-session can recognise domain option for cookie. According to source:
function session(options){
var options = options || {}
// name - previously "options.key"
, name = options.name || options.key || 'connect.sid'
, store = options.store || new MemoryStore
, cookie = options.cookie || {}
...
And this is for setting cookie:
var Cookie = module.exports = function Cookie(options) {
this.path = '/';
this.maxAge = null;
this.httpOnly = true;
if (options) merge(this, options);
...
So, something like this will work for current 1.10.1 master:
secret: "my secret",
cookie: {
domain: "mydomain.com",
Express-session does not seem to recognize the "domain" option for cookies hence your problem. The cookie storing the session id is automatically tied to the domain for each app and so it cannot be shared.
One option is to write your own single-sign-on module to share sessions across webapps. It would probably live in an app.use() declaration fairly early in the execution order and would simply create a separate cookie (which would be cross-domain), create a separate SSO session id, and store the SSO id in this new cookie. Afterwards, you simply cross-populate req.session and req.sso-session as needed.

Resources