Created
November 14, 2012 13:22
-
-
Save shimondoodkin/4072034 to your computer and use it in GitHub Desktop.
nodejs express 3 integration of - socket.io with sessions and sessionid handshake
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Module dependencies. | |
*/ | |
var express = require('express') | |
// , routes = require('./routes') | |
// , user = require('./routes/user') | |
, http = require('http') | |
, path = require('path'); | |
var io = require('socket.io') | |
, sio, sio_client_on | |
, MemoryStore = express.session.MemoryStore | |
, sessionStore = new MemoryStore();//http://nodetoolbox.com/packages/mysql-session-store or redis or mongodb if you like i simply have mysql installed | |
// also possible to have a db store for the handshake data for socket io | |
// User validation | |
var auth = express.basicAuth(function(user, pass) { return (user=="mypass"&&pass=="mypass"); },'Secret Area'); | |
//example: app.get('/', auth , function(req,res){}) | |
var app = express(); | |
app.configure(function(){ | |
app.set('port', process.env.PORT || 5052); | |
app.set('views', __dirname + '/views'); | |
app.set('view engine', 'jade'); | |
app.use(express.favicon()); | |
//app.use(express.logger('dev')); | |
app.use(express.cookieParser()); | |
app.use(express.session({store: sessionStore , secret: 'secret' , key: 'express.sid', | |
//maxAge :24*3600000 //1 Hour * 24 | |
})); | |
/* | |
app.all('/', function (req, res, next) { | |
res.header("Access-Control-Allow-Origin", "*"); | |
res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Origin, X-File-Name, Content-Type, Cache-Control"); | |
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS'); | |
next(); | |
}); | |
*/ | |
app.use(express.bodyParser()); | |
app.use(express.methodOverride()); | |
app.use(app.router); | |
app.use(express.static(path.join(__dirname, 'public'))); | |
}); | |
app.configure('development', function(){ | |
app.use(express.errorHandler()); | |
}); | |
// Store imageData buffer 1x1 pixel transparent gif file | |
gif_1x1_buffer = new Buffer("R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", encoding='base64'); | |
app.get('/keepsession.gif', function(req,res){ | |
res.writeHead(200, | |
{ | |
'Cache-Control': 'no-cache', | |
'Pragma': 'no-cache', | |
'Expires':"Tue, 01 Jan 2000 12:12:12 GMT", | |
'Content-Type': 'image/gif' | |
}); | |
res.write(gif_1x1_buffer.toString('binary'), 'binary'); | |
res.end(); | |
}); | |
app.get('/', function(req,res){ | |
res.writeHead(200, | |
{ | |
'Cache-Control': 'no-cache', | |
'Pragma': 'no-cache', | |
'Content-Type': 'text/html', | |
'Expires':"Tue, 01 Jan 2000 12:12:12 GMT" | |
}); | |
res.end("It Works! :-)<script>location.href='chat.html'</script>"); | |
}); | |
//app.get('/', routes.index); | |
//app.get('/users', user.list); | |
// excaption handling | |
process.on('uncaughtException', function (err) { | |
console.log('Caught exception: ' + err.stack); | |
}); | |
// socket io | |
var server = http.createServer(app); | |
sio = io.listen(server); | |
sio.set('log level', 1); | |
sio.secret_keyword='server' | |
var utils = require('express/node_modules/connect/lib/utils') | |
var cookie = require('express/node_modules/cookie'); | |
function parseCookie(cookies){ | |
var secret='secret'; | |
var reqcookies = {}; | |
var reqsignedCookies = {}; | |
if (cookies) | |
{ | |
try | |
{ | |
reqcookies = cookie.parse(cookies); | |
if (secret) | |
{ | |
reqsignedCookies = utils.parseSignedCookies(reqcookies, secret); | |
var obj = utils.parseJSONCookies(reqsignedCookies); | |
reqsignedCookies = obj; | |
} | |
reqcookies = utils.parseJSONCookies(reqcookies); | |
} | |
catch (err) | |
{ | |
errstatus = 400; | |
console.log("err",err.stack) | |
} | |
} | |
return {cookies:reqcookies,signedCookies:reqsignedCookies}; | |
}; | |
//var recreate_lost_sessions=true; // unsecure then it accepts the socket with a new empty session. | |
sio.set('authorization', function (handshake_data, accept) { | |
var data = handshake_data; | |
//console.log(data.headers); | |
if (data.headers.cookie) { | |
//console.log(data); | |
//console.log(data.headers.cookie); | |
data.cookie = parseCookie(data.headers.cookie,'secret'); | |
data.sessionID = data.cookie.signedCookies['express.sid']||data.cookie.cookies['express.sid']; | |
//console.log(data.headers.cookie); | |
// (literally) get the session data from the session store | |
sessionStore.load(data.sessionID, function (err, session) { | |
if (err) { | |
// if we cannot grab a session, turn down the connection | |
accept(err.message, false); | |
} else if (session==undefined) { | |
// if we cannot grab a session, turn down the connection | |
accept('session not found', false); | |
} else { | |
data.session = session; | |
if(!data.session.userid) | |
{ | |
data.session.userid=require('express/node_modules/connect/lib/utils').uid(24);// expose user's session it is unsecure lets have another id | |
data.session.save(function(){}) | |
} | |
accept(null, true); | |
} | |
}); | |
} else { | |
// Check to see if the conection is made from the server | |
// ~ auth with token | |
if (data.query.secret_keyword && | |
(data.query.secret_keyword === sio.secret_keyword)) | |
{ | |
return accept(null, true); | |
} | |
return accept('No cookie transmitted.', false); | |
} | |
}); | |
sio.sockets.on('connection', function (socket) { | |
var hs = socket.handshake; | |
//console.log('connection',socket.handshake); | |
console.log('A socket with sessionID ' + hs.sessionID + ' connected!'); | |
// setup an inteval that will keep our session fresh | |
var intervalID = setInterval(function () { | |
// reload the session (just in case something changed, | |
// we don't want to override anything, but the age) | |
// reloading will also ensure we keep an up2date copy | |
// of the session with our connection. | |
if(hs&&hs.session)hs.session.reload( function () { | |
// "touch" it (resetting maxAge and lastAccess) | |
// and save it back again. | |
hs.session.touch().save(); | |
}); | |
}, 60 * 1000); | |
socket.on('disconnect', function () { | |
console.log('A socket with sessionID ' + hs.sessionID + ' disconnected!'); | |
// clear the socket interval to stop refreshing the session | |
clearInterval(intervalID); | |
}); | |
setup_socket_io(socket); | |
var client=socket; | |
sio_client_on.connection.apply(client,arguments); | |
}); | |
function setup_socket_io(client) | |
{ | |
Object.keys(sio_client_on) | |
.forEach(function(eventName){ | |
var f=sio_client_on[eventName]; | |
client.on(eventName,function(){f.apply(client,arguments)});}); | |
} | |
//// end socket io | |
/* | |
// some service can http get a url to notify clients | |
app.get('/refresh', function (req, res) { | |
res.end('ok'); | |
sio.sockets.emit('eval','if(refreshdata)refreshdata()'); | |
}); | |
*/ | |
/******************/ | |
var chatdata=[]; | |
var xss = require('xss'); | |
xss.whiteList.iframe=['style', 'class', 'height', 'width', 'border', 'src', 'allowfullscreen', 'frameborder'] | |
xss.whiteList.object=['width', 'height'] | |
xss.whiteList.param=['name', 'value'] | |
xss.whiteList.embed=['src', 'type','width', 'height','allowscriptaccess','allowfullscreen'] | |
xss.whiteList.font=['size','face'] | |
//// setup socket io events | |
sio_client_on= | |
{ | |
'connection': function () { | |
var client=this; | |
if(!client.handshake.session.nick) | |
{ | |
client.handshake.session.nick="John"+Math.round(Math.random()*1000); | |
client.handshake.session.save(function(){}) | |
} | |
client.emit('chat/full',chatdata); | |
client.join('chat/0'); | |
//client.join('chat/1'); | |
sio_client_on.users.call(this); | |
}, | |
'disconnect': function () { | |
var client=this; | |
sio_client_on.users.call(this,[client.id]); | |
}, | |
'users': function (skip) { | |
var client=this; | |
var myrooms=sio.sockets.manager.roomClients[client.id]; | |
var rooms=[]; | |
for(var aroom in myrooms) | |
{ | |
if(aroom.indexOf('/chat/')==0) | |
{ | |
var introom=parseInt(aroom.substr(6)); | |
rooms[introom]={}; | |
sio.sockets.clients(aroom.substr(1)).forEach(function(a){ | |
var client_handshake=sio.sockets.manager.handshaken[a.id]; | |
if(!rooms[introom][client_handshake.session.userid]) | |
{ | |
if(skip) | |
{ | |
if(skip.indexOf(a.id)==-1) | |
rooms[introom][client_handshake.session.userid]=client_handshake.session.nick; | |
} | |
else | |
rooms[introom][client_handshake.session.userid]=client_handshake.session.nick; | |
} | |
}); | |
} | |
sio.sockets.in(aroom.substr(1)).emit('chat/users',rooms); | |
} | |
}, | |
'chat/message': function (message) | |
{ | |
if(typeof message!='object') return; | |
if(typeof message.room!='number') return; | |
var client=this; | |
message.nick=client.handshake.session.nick||"nonick"; | |
message.date=(new Date()).getTime(); | |
message.id=message.room+'_'+message.date; | |
var xssoptions = { | |
//whiteList: {}, // if not specified, use the default configuration, refer xss.whiteList, | |
//onTagAttr: function () {}, //if not specified, use the default configuration, you can reference xss.onTagAttr | |
//onIgnoreTag: function () {} // If you do not specify the default configuration, refer xss.onIgnoreTag, | |
}; | |
message.text=xss(message.text,xssoptions); | |
if(!chatdata[message.room])chatdata[message.room]=[]; | |
//do not insert multiple rows of same number | |
chatdata[message.room].push(message); | |
sio.sockets.in('chat/'+message.room).emit('chat/message',message); | |
//Broadcasting means sending a message to everyone else except for the socket that starts it. | |
//client.broadcast('event',data); | |
//sio.sockets.in(req.sessionID).broadcast('Man, good to see you back!'); | |
} | |
} | |
server.listen(app.get('port')); console.log("Express server listening..."); | |
//console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var socket =io.connect("http://123.123.123.123:12345/",{ 'connect timeout': 1000 , 'try multiple transports': false}); | |
socket.on('connect_failed', function (reason) { | |
if(reason.indexOf('handshake error')!=-1) | |
{ | |
var o={} | |
o.img= new Image() | |
o.img.src="http://123.123.123.123:12345/keepsession.gif?"+((new Date).getTime()) | |
o.img.onload=function(){setTimeout(function(){delete o.img;delete o;},0);} | |
} | |
console.log('unable to connect to namespace', reason); | |
}) | |
.on('connect', function () { | |
console.log('sucessfully established a connection with the namespace'); | |
}) | |
.on('connect', function () { | |
console.log('connection lost'); | |
}); | |
// just one event on client: | |
socket.on('eval', function (d) { | |
eval(d); | |
}); | |
socket.on('message', function (d) { | |
alert(d); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment