├── 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