From 9583ca688bb1af8bd32b4491aa4a2998b61eca7b Mon Sep 17 00:00:00 2001 From: Chris Blanchard Date: Tue, 15 Sep 2015 14:25:00 +0100 Subject: [PATCH] Deserialise session store using ruby child process --- config/socketio.js | 44 ++++++++++++++++++++++++++------------------ lib/ensl/client.js | 36 ++++++++++++++++++++---------------- scripts/unmarshal.rb | 13 +++++++++++++ 3 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 scripts/unmarshal.rb diff --git a/config/socketio.js b/config/socketio.js index 2ce5d25..a498e5d 100644 --- a/config/socketio.js +++ b/config/socketio.js @@ -22,6 +22,14 @@ var assignRandomUser = (socket, next) => { }); }; +var handleFailedAuth = (socket, next) => { + if (process.env.RANDOM_USER) { + return assignRandomUser(socket, next); + } else { + return next(new Error("Authentication Failed")); + } +}; + module.exports = io => { var rootNamespace = io.of('/') @@ -29,28 +37,28 @@ module.exports = io => { io.use((socket, next) => { let cookies = parseCookies(socket); - let session; - if (cookies) { - session = EnslClient.decodeSession(cookies[config.session_store_name]); + if (!cookies) { + return handleFailedAuth(socket, next); } - if (!session || typeof session.user !== 'number') { - if (process.env.RANDOM_USER) { - return assignRandomUser(socket, next); - } else { - return next(new Error("Authentication Failed")); - } + let session = cookies[config.session_store_name]; + + if (!session) { + return handleFailedAuth(socket, next); } - User.find(session.user, (error, user) => { - if (error) { - winston.error(error); - return next(new Error("Authentication failed")); - } - socket._user = user; - if (socket._user.bans.gather) return next(new Error("Gather Banned")); - winston.info("Logged in:", user.username, user.id); - return next(); + EnslClient.decodeSession(session, function (error, userId) { + if (error) return handleFailedAuth(socket, next); + User.find(userId, (error, user) => { + if (error) { + winston.error(error); + return next(new Error("Authentication failed")); + } + socket._user = user; + if (socket._user.bans.gather) return next(new Error("Gather Banned")); + winston.info("Logged in:", user.username, user.id); + return next(); + }); }); }); diff --git a/lib/ensl/client.js b/lib/ensl/client.js index c7e34c6..62bffbe 100644 --- a/lib/ensl/client.js +++ b/lib/ensl/client.js @@ -4,7 +4,6 @@ var path = require("path"); var crypto = require("crypto"); var request = require("request"); var logger = require("winston"); -var Marshal = require("marsha"); var querystring = require('querystring'); var config = require(path.join(__dirname, "../../config/config")); const SECRET_TOKEN = config.secret_token; @@ -79,31 +78,36 @@ EnslClient.parseCookies = (socket) => { return cookies; }; -EnslClient.decodeSession = sessionCookie => { - if (typeof sessionCookie !== 'string') return null; +EnslClient.decodeSession = (sessionCookie, callback) => { + if (typeof sessionCookie !== 'string') { + return callback(new Error("Invalid cookie"), null); + } var session = sessionCookie.split("--"); - if (session.length !== 2) return null; + if (session.length !== 2) { + return callback(new Error("Invalid cookie: No signature provided"), null); + } // Separate text and signature var text = querystring.unescape(session[0]); var signature = session[1]; // Verify signature - if (crypto.createHmac("sha1", SECRET_TOKEN).update(text).digest('hex') !== signature) return null; - - childProcess('ruby -e "puts \'Hello World!\'"', function (err, stdout, stderr) { - console.log(stdout); - }); - - var parsedSession; - try { - parsedSession = Marshal.load(text, 'base64'); - } catch (e) { - logger.error(e); + if (crypto.createHmac("sha1", SECRET_TOKEN).update(text).digest('hex') !== signature) { + return callback(new Error("Invalid cookie signature"), null); } - return parsedSession || null; + var cb = callback; + childProcess("ruby unmarshal.rb " + text, { + cwd: path.join(__dirname, "../../scripts") + }, function (err, stdout, stderr) { + var userId = parseInt(stdout, 10); + if (isNaN(userId)) { + return callback(new Error("Invalid cookie: User ID not found"), null); + } else { + return callback(null, userId); + } + }); }; module.exports = EnslClient; diff --git a/scripts/unmarshal.rb b/scripts/unmarshal.rb new file mode 100644 index 0000000..da20f4f --- /dev/null +++ b/scripts/unmarshal.rb @@ -0,0 +1,13 @@ +# Reads in raw Rails 3 session store, returns user id + +require 'base64' + +session_store = ARGV[0] + +deserialised_store = Marshal.load(Base64.decode64(session_store)) + +user_id = deserialised_store['user'] + +STDOUT.write user_id + +exit 0 \ No newline at end of file