Permalink
Browse files

done

  • Loading branch information...
0 parents commit 9618b4d9bbb461c7da7217751cceaa9aff549496 Bradley Meck committed Oct 7, 2010
Showing with 237 additions and 0 deletions.
  1. +53 −0 README.md
  2. +38 −0 example/server.js
  3. +17 −0 example/static/index.html
  4. +23 −0 example/static/sws.js
  5. +7 −0 package.json
  6. +99 −0 sws.js
@@ -0,0 +1,53 @@
+# SessionWebSocket
+
+## Resources
+
+### Server Side
+
+ require("SessionWebSocket")
+
+### Client Side
+
+The client side code is from within this repository
+
+ <script "./example/static/sws.js"></script>
+
+### Usage
+
+* On a server with
+* * Connect.session
+* * Socket.io
+
+* Get a session verifier
+
+ var sws = require("SessionWebSocket")()
+
+* Setup the server
+
+ var server = connect.createServer(
+ ...
+ connect.cookieDecoder(),
+ connect.session(...),
+ sws.http //not a function
+ ...
+ )
+
+* Setup socket.io
+
+ //put our callback inside of sws.ws(...)
+ io.listen(server,sws.ws(function(client){
+ //normal socket.io callback
+ client.on("secure",function(){
+ console.log(client.session) //client.session is now available
+ })
+ client.on("insecure",function(){
+ // fires when a message that is not the auth message arrives first
+ })
+ }))
+
+### Events
+
+#### Socket.io.Client
+
+* secure - fires when auth sucedes, __does not__ put the auth token in a "message" event
+* insecure - fires when auth fails, and then fires the "message" event
@@ -0,0 +1,38 @@
+var connect = require("connect")
+var io = require("socket.io")
+
+//Import SessionWebSockets
+//note: it is a function to allow multiple sessions able to be used
+var sws = require("../sws.js")()
+
+var server = connect.createServer(
+ //sessions in connect use both cookieDecoder and session middleware
+ connect.cookieDecoder(),
+ connect.session({store:(new require("connect/middleware/session/memory"))({ reapInterval: 60000 * 10 })}),
+ //Attach our xhr handler for token requests
+ sws.http,
+ connect.staticProvider(__dirname+"/static")
+)
+//start listening
+server.listen(8080)
+
+var socket = io.listen(server)
+socket.on('connection', sws.ws(function(client){
+ //the verification message for this will be blocked from being
+ //sent to the client
+ client.on("secure",function(){
+ console.log("SECURE")
+ //hail to the king!
+ console.log(client.session)
+ })
+
+ //This will not stop the message, but at least you know
+ client.on("insecure",function(){
+ console.log("INSECURE ACCESS")
+ })
+
+ client.on("message",function(msg){
+ console.log("MSG:"+msg)
+ })
+ })
+)
@@ -0,0 +1,17 @@
+<html><head><title>
+Web Socket Auth Tutorial
+</title></head><body>
+ <script type="text/javascript" src="http://cdn.socket.io/stable/socket.io.js"></script>
+ <script type="text/javascript" src="sws.js"></script>
+ <div id="console"></div>
+ <script>
+ SessionWebSocket(function(socket){
+ socket.on('message',function(msg){
+ console.log("SWS:",msg)
+ })
+ })
+ var socket = new io.Socket()
+ socket.connect()
+ socket.send("OH NOES")
+ </script>
+</body></html>
@@ -0,0 +1,23 @@
+function SessionWebSocket(cb) {
+ var xhr = new XMLHttpRequest()
+ //use https and go over the same port as the server
+ xhr.open("GET","/")
+
+ //set our header to get the token
+ xhr.setRequestHeader("x-access-request-token","simple")
+ xhr.onreadystatechange = function xhrverify() {
+ if(xhr.readyState === 4) {
+ var tmp
+ if(tmp = JSON.parse(xhr.responseText)["x-access-token"]) {
+ var socket = new io.Socket();
+ cb(socket)
+ socket.connect()
+ //get the first part as the secret
+ socket.send(tmp.split(";")[0])
+ }
+ }
+ }
+
+ //send out the request
+ xhr.send()
+}
@@ -0,0 +1,7 @@
+{
+ name: "SessionWebSocket",
+ description: "socket.io & connect based session notification for websockets",
+ author: "bradleymeck",
+ version: "0.1.0",
+ main: "sws.js"
+}
99 sws.js
@@ -0,0 +1,99 @@
+//exposes a verifier for sessions
+//first request an access token over xhr
+//then connect the socket with the x-access-token returned as the first message
+module.exports = function verifier(options)
+{
+ var defaults = {
+ ttl: 30*1000//30 seconds before token is invalid
+ }
+ for(var k in options) {
+ defaults[k] = options[k]
+ }
+ var session_jar = {}
+ return {
+ http:function give_token(req,res,next) {
+ //x-access-request-token: simple
+ // -- one time use token for alternative sessions
+ // -- must be secure connection
+ //
+ //returns body with json {
+ // x-access-token: key ';' time
+ //}
+ if(req.headers["x-access-request-token"]) {
+ if(req.headers["x-access-request-token"].toLowerCase()==="simple") {
+ var token = Math.random()
+ while(session_jar[token]) {
+ token = Math.random()
+ }
+ var tmp = Date.now()
+ session_jar[token] = {
+ session:req.session,
+ date:tmp,
+ id:req.sessionID
+ }
+ res.writeHead(200)
+ res.end('{"x-access-token": "'+token+';'+tmp+'"}')
+ return
+ }
+ }
+ //for connect
+ if(next) {
+ next()
+ }
+ }
+
+ , ws: function attach_client(cb) {
+ return function route_client(client) {
+ // new client is here!
+ // verify session or default to none
+ function verify(token) {
+ var tmp = session_jar[token]
+ //if we have a session and the session is not stale
+ if(tmp && tmp.date > Date.now() - defaults.ttl) {
+ var session = tmp
+ //do a little cleanup for logged in sessions
+ //TODO: figure out secure cleanup for stale sessions?
+ delete session_jar[token]
+ return session
+ }
+ }
+ //the first message will send out secret token
+ //if it does emit("secure")
+ //otherwise, emit("insecure") and fire emit("message")
+ client.on('message', function first_verify(msg){
+ var session = verify(msg) || false
+ if(session) {
+ client._session = session
+ client.session = session.session
+ client.emit("secure")
+ session = true
+ }
+ else {
+ //insecure does not stop the first message!
+ client.emit("insecure")
+ }
+ l=onmsgs.length
+ for(var i=0;i<l;i++) {
+ var fn = onmsgs[i]
+ if(!session) {
+ fn(msg)
+ }
+ client.on('message',fn)
+ }
+ client.removeListener('message',first_verify)
+ })
+
+ //our mask of functions to add at/after the first message
+ var onmsgs = []
+ var oldon = client.on
+ client.on = function(name,fn) {
+ if(name === "message") onmsgs[onmsgs.length] = fn
+ else oldon.apply(this,arguments)
+ }
+
+ //hand over the client to w/e is going on
+ cb(client)
+ }
+ }
+ }
+}

0 comments on commit 9618b4d

Please sign in to comment.