├── package.json ├── example ├── static │ ├── index.html │ └── sws.js └── server.js ├── README.md └── sws.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | name: "SessionWebSocket", 3 | description: "socket.io & connect based session notification for websockets", 4 | author: "bradleymeck", 5 | version: "0.1.1", 6 | main: "sws.js" 7 | } -------------------------------------------------------------------------------- /example/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | Web Socket Auth Tutorial 3 | 4 | 5 | 6 |
7 | 17 | -------------------------------------------------------------------------------- /example/static/sws.js: -------------------------------------------------------------------------------- 1 | function SessionWebSocket(cb) { 2 | var xhr = new XMLHttpRequest() 3 | //use https and go over the same port as the server 4 | xhr.open("GET","/?no-cache="+(new Date()+0)) 5 | 6 | //set our header to get the token 7 | xhr.setRequestHeader("x-access-request-token","simple") 8 | xhr.onreadystatechange = function xhrverify() { 9 | if(xhr.readyState === 4) { 10 | var tmp 11 | try { 12 | if(tmp = JSON.parse(xhr.responseText)["x-access-token"]) { 13 | var socket = new io.Socket(); 14 | cb(socket) 15 | socket.connect() 16 | //get the first part as the secret 17 | socket.send(tmp.split(";")[0]) 18 | } 19 | } 20 | catch(e) { 21 | throw new Error("XMLHttpResponse had non-json response, possible cache issue?") 22 | } 23 | } 24 | } 25 | 26 | //send out the request 27 | xhr.send() 28 | } -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | var connect = require("connect") 2 | var io = require("socket.io") 3 | 4 | //Import SessionWebSockets 5 | //note: it is a function to allow multiple sessions able to be used 6 | var sws = require("../sws.js")() 7 | 8 | var server = connect.createServer( 9 | //sessions in connect use both cookieDecoder and session middleware 10 | connect.cookieDecoder(), 11 | connect.session({store:(new require("connect/middleware/session/memory"))({ reapInterval: 60000 * 10 })}), 12 | //Attach our xhr handler for token requests 13 | sws.http, 14 | connect.staticProvider(__dirname+"/static") 15 | ) 16 | //start listening 17 | server.listen(8080) 18 | 19 | var socket = io.listen(server) 20 | socket.on('connection', sws.ws(function(client){ 21 | //the verification message for this will be blocked from being 22 | //sent to the client 23 | client.on("secure",function(){ 24 | console.log("SECURE") 25 | //hail to the king! 26 | console.log(client.session) 27 | }) 28 | 29 | //This will not stop the message, but at least you know 30 | client.on("insecure",function(){ 31 | console.log("INSECURE ACCESS") 32 | }) 33 | 34 | client.on("message",function(msg){ 35 | console.log("MSG:"+msg) 36 | }) 37 | }) 38 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SessionWebSocket 2 | 3 | ## Resources 4 | 5 | ### Server Side 6 | 7 | require("SessionWebSocket") 8 | 9 | ### Client Side 10 | 11 | The client side code is from within this repository 12 | 13 | 14 | 15 | ### Usage 16 | 17 | * On a server with 18 | * * Connect.session 19 | * * Socket.io 20 | 21 | * Get a session verifier 22 | 23 | var sws = require("SessionWebSocket")() 24 | 25 | * Setup the server 26 | 27 | var server = connect.createServer( 28 | ... 29 | connect.cookieDecoder(), 30 | connect.session(...), 31 | sws.http //not a function 32 | ... 33 | ) 34 | 35 | * Setup socket.io 36 | 37 | //put our callback inside of sws.ws(...) 38 | io.listen(server,sws.ws(function(client){ 39 | //normal socket.io callback 40 | client.on("secure",function(){ 41 | console.log(client.session) //client.session is now available 42 | }) 43 | client.on("insecure",function(){ 44 | // fires when a message that is not the auth message arrives first 45 | }) 46 | })) 47 | 48 | 49 | ### Usage Client Side 50 | 51 | 52 | 57 | 58 | ### Events 59 | 60 | #### Socket.io.Client 61 | 62 | * secure - fires when auth sucedes, __does not__ put the auth token in a "message" event 63 | * insecure - fires when auth fails, and then fires the "message" event -------------------------------------------------------------------------------- /sws.js: -------------------------------------------------------------------------------- 1 | //exposes a verifier for sessions 2 | //first request an access token over xhr 3 | //then connect the socket with the x-access-token returned as the first message 4 | module.exports = function verifier(options) 5 | { 6 | var defaults = { 7 | ttl: 30*1000//30 seconds before token is invalid 8 | } 9 | for(var k in options) { 10 | defaults[k] = options[k] 11 | } 12 | var session_jar = {} 13 | return { 14 | http:function give_token(req,res,next) { 15 | //x-access-request-token: simple 16 | // -- one time use token for alternative sessions 17 | // -- must be secure connection 18 | // 19 | //returns body with json { 20 | // x-access-token: key ';' time 21 | //} 22 | if(req.headers["x-access-request-token"]) { 23 | if(req.headers["x-access-request-token"].toLowerCase()==="simple") { 24 | var token = Math.random() 25 | while(session_jar[token]) { 26 | token = Math.random() 27 | } 28 | var tmp = Date.now() 29 | session_jar[token] = { 30 | session:req.session, 31 | date:tmp, 32 | id:req.sessionID 33 | } 34 | res.writeHead(200) 35 | res.end('{"x-access-token": "'+token+';'+tmp+'"}') 36 | return 37 | } 38 | } 39 | //for connect 40 | if(next) { 41 | next() 42 | } 43 | } 44 | 45 | , ws: function attach_client(cb) { 46 | return function route_client(client) { 47 | // new client is here! 48 | // verify session or default to none 49 | function verify(token) { 50 | var tmp = session_jar[token] 51 | //if we have a session and the session is not stale 52 | if(tmp && tmp.date > Date.now() - defaults.ttl) { 53 | var session = tmp 54 | //do a little cleanup for logged in sessions 55 | //TODO: figure out secure cleanup for stale sessions? 56 | delete session_jar[token] 57 | return session 58 | } 59 | } 60 | //the first message will send out secret token 61 | //if it does emit("secure") 62 | //otherwise, emit("insecure") and fire emit("message") 63 | client.on('message', function first_verify(msg){ 64 | var session = verify(msg) || false 65 | if(session) { 66 | client._session = session 67 | client.session = session.session 68 | client.emit("secure") 69 | session = true 70 | } 71 | else { 72 | //insecure does not stop the first message! 73 | client.emit("insecure") 74 | } 75 | l=onmsgs.length 76 | for(var i=0;i