Deserialise session store using ruby child process

This commit is contained in:
Chris Blanchard 2015-09-15 14:25:00 +01:00
parent 6e00b38707
commit 9583ca688b
3 changed files with 59 additions and 34 deletions

View File

@ -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();
});
});
});

View File

@ -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;

13
scripts/unmarshal.rb Normal file
View File

@ -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