From 5c9d081391183deee1eccccea88d194ae5952341 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 13 Feb 2013 01:33:22 +0000 Subject: [PATCH 01/10] Begin supporting the database but still have a problem where it generates new key on restart... --- src/node/db/SessionManager.js | 2 +- src/node/db/SessionStore.js | 82 +++++++++++++++++++++++++++++ src/node/hooks/express/webaccess.js | 13 +++-- 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/node/db/SessionStore.js diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js index 5ce4f748..60e0a7ac 100644 --- a/src/node/db/SessionManager.js +++ b/src/node/db/SessionManager.js @@ -1,5 +1,5 @@ /** - * The Session Manager provides functions to manage session in the database + * The Session Manager provides functions to manage session in the database, it only provides session management for sessions created by the API */ /* diff --git a/src/node/db/SessionStore.js b/src/node/db/SessionStore.js new file mode 100644 index 00000000..09ea7333 --- /dev/null +++ b/src/node/db/SessionStore.js @@ -0,0 +1,82 @@ + /* + * Stores session data in the database + * Source; https://github.com/edy-b/SciFlowWriter/blob/develop/available_plugins/ep_sciflowwriter/db/DirtyStore.js + * This is not used for authors that are created via the API at current + */ + +var Store = require('ep_etherpad-lite/node_modules/connect/lib/middleware/session/store'), + utils = require('ep_etherpad-lite/node_modules/connect/lib/utils'), + Session = require('ep_etherpad-lite/node_modules/connect/lib/middleware/session/session'), + db = require('ep_etherpad-lite/node/db/DB').db, + log4js = require('ep_etherpad-lite/node_modules/log4js'), + messageLogger = log4js.getLogger("SessionStore"); + +var SessionStore = module.exports = function SessionStore() {}; + +SessionStore.prototype.__proto__ = Store.prototype; + +SessionStore.prototype.get = function(sid, fn){ + messageLogger.debug('GET ' + sid); + var self = this; + db.get("sessionstorage:" + sid, function (err, sess) + { + if (sess) { + sess.cookie.expires = 'string' == typeof sess.cookie.expires ? new Date(sess.cookie.expires) : sess.cookie.expires; + if (!sess.cookie.expires || new Date() < expires) { + fn(null, sess); + } else { + self.destroy(sid, fn); + } + } else { + fn(); + } + }); +}; + +SessionStore.prototype.set = function(sid, sess, fn){ + messageLogger.debug('SET ' + sid); + db.set("sessionstorage:" + sid, sess); + process.nextTick(function(){ + if(fn) fn(); + }); +}; + +SessionStore.prototype.destroy = function(sid, fn){ + messageLogger.debug('DESTROY ' + sid); + db.remove("sessionstorage:" + sid); + process.nextTick(function(){ + if(fn) fn(); + }); +}; + +SessionStore.prototype.all = function(fn){ + messageLogger.debug('ALL'); + var sessions = []; + db.forEach(function(key, value){ + if (key.substr(0,15) === "sessionstorage:") { + sessions.push(value); + } + }); + fn(null, sessions); +}; + +SessionStore.prototype.clear = function(fn){ + messageLogger.debug('CLEAR'); + db.forEach(function(key, value){ + if (key.substr(0,15) === "sessionstorage:") { + db.db.remove("session:" + key); + } + }); + if(fn) fn(); +}; + +SessionStore.prototype.length = function(fn){ + messageLogger.debug('LENGTH'); + var i = 0; + db.forEach(function(key, value){ + if (key.substr(0,15) === "sessionstorage:") { + i++; + } + }); + fn(null, i); +}; diff --git a/src/node/hooks/express/webaccess.js b/src/node/hooks/express/webaccess.js index 50323ef6..4a2f4664 100644 --- a/src/node/hooks/express/webaccess.js +++ b/src/node/hooks/express/webaccess.js @@ -4,7 +4,7 @@ var httpLogger = log4js.getLogger("http"); var settings = require('../../utils/Settings'); var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); - +var ueberStore = require('../../db/SessionStore'); //checks for basic http auth exports.basicAuth = function (req, res, next) { @@ -102,15 +102,14 @@ exports.expressConfigure = function (hook_name, args, cb) { * handling it cleaner :) */ if (!exports.sessionStore) { - exports.sessionStore = new express.session.MemoryStore(); - exports.secret = randomString(32); + exports.sessionStore = new ueberStore(); + exports.secret = randomString(32); // Isn't this being reset each time the server spawns? } - - args.app.use(express.cookieParser(exports.secret)); + args.app.use(express.cookieParser(exports.secret)); args.app.sessionStore = exports.sessionStore; - args.app.use(express.session({store: args.app.sessionStore, - key: 'express_sid' })); + args.app.use(express.session({secret: exports.secret, store: args.app.sessionStore, key: 'express_sid' })); args.app.use(exports.basicAuth); } + From efce99c3a13c6a406c83d537d2c18b0db7d1ec2c Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 13 Feb 2013 21:51:09 +0000 Subject: [PATCH 02/10] session key in settings file OR generate temp key for instance --- settings.json.template | 4 ++++ src/node/hooks/express/webaccess.js | 2 +- src/node/utils/Settings.js | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/settings.json.template b/settings.json.template index 4b18d780..28f0192e 100644 --- a/settings.json.template +++ b/settings.json.template @@ -15,6 +15,10 @@ "ip": "0.0.0.0", "port" : 9001, + // Session Key, used for reconnecting user sessions + // Set this to a secure string at least 10 characters long. Do not share this value. + "sessionKey" : "", + /* // Node native SSL support // this is disabled by default diff --git a/src/node/hooks/express/webaccess.js b/src/node/hooks/express/webaccess.js index 4a2f4664..c39f91da 100644 --- a/src/node/hooks/express/webaccess.js +++ b/src/node/hooks/express/webaccess.js @@ -103,7 +103,7 @@ exports.expressConfigure = function (hook_name, args, cb) { if (!exports.sessionStore) { exports.sessionStore = new ueberStore(); - exports.secret = randomString(32); // Isn't this being reset each time the server spawns? + exports.secret = settings.sessionKey; // Isn't this being reset each time the server spawns? } args.app.use(express.cookieParser(exports.secret)); diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 8435ab2c..67e748bb 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -26,6 +26,8 @@ var argv = require('./Cli').argv; var npm = require("npm/lib/npm.js"); var vm = require('vm'); var log4js = require("log4js"); +var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; + /* Root path of the installation */ exports.root = path.normalize(path.join(npm.dir, "..")); @@ -112,6 +114,11 @@ exports.loglevel = "INFO"; */ exports.logconfig = { appenders: [{ type: "console" }]}; +/* +* Session Key, do not sure this. +*/ +exports.sessionKey = false; + /* This setting is used if you need authentication and/or * authorization. Note: /admin always requires authentication, and * either authorization by a module, or a user with is_admin set */ @@ -132,8 +139,6 @@ exports.abiwordAvailable = function() } } - - exports.reloadSettings = function reloadSettings() { // Discover where the settings file lives var settingsFilename = argv.settings || "settings.json"; @@ -184,6 +189,11 @@ exports.reloadSettings = function reloadSettings() { log4js.setGlobalLogLevel(exports.loglevel);//set loglevel log4js.replaceConsole(); + if(!exports.sessionKey){ // If the secretKey isn't set we also create yet another unique value here + exports.sessionKey = "__bad__"+randomString(32);; + console.warn("You need to set a sessionKey value in settings.json, this will allow your users to reconnect to your Etherpad Instance if your instance restarts"); + } + if(exports.dbType === "dirty"){ console.warn("DirtyDB is used. This is fine for testing but not recommended for production.") } From 7f09ec25a27e18c45d60a3410ed568a32c15e41d Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 13 Feb 2013 21:53:15 +0000 Subject: [PATCH 03/10] no need for prefix and tidy double semi --- src/node/utils/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 67e748bb..04404a1a 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -190,7 +190,7 @@ exports.reloadSettings = function reloadSettings() { log4js.replaceConsole(); if(!exports.sessionKey){ // If the secretKey isn't set we also create yet another unique value here - exports.sessionKey = "__bad__"+randomString(32);; + exports.sessionKey = randomString(32); console.warn("You need to set a sessionKey value in settings.json, this will allow your users to reconnect to your Etherpad Instance if your instance restarts"); } From 36814ed42b019c851356ae59065bdb7ae7975702 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 13 Feb 2013 23:44:20 +0000 Subject: [PATCH 04/10] apply overlay and remove overlay instantly --- src/static/js/pad_connectionstatus.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/static/js/pad_connectionstatus.js b/src/static/js/pad_connectionstatus.js index c592afbd..2d9354ab 100644 --- a/src/static/js/pad_connectionstatus.js +++ b/src/static/js/pad_connectionstatus.js @@ -43,9 +43,8 @@ var padconnectionstatus = (function() status = { what: 'connected' }; - padmodals.showModal('connected'); - padmodals.hideOverlay(500); + padmodals.hideOverlay(); }, reconnecting: function() { @@ -54,7 +53,7 @@ var padconnectionstatus = (function() }; padmodals.showModal('reconnecting'); - padmodals.showOverlay(500); + padmodals.showOverlay(); }, disconnected: function(msg) { @@ -73,10 +72,11 @@ var padconnectionstatus = (function() } padmodals.showModal(k); - padmodals.showOverlay(500); + padmodals.showOverlay(); }, isFullyConnected: function() { + padmodals.hideOverlay(); return status.what == 'connected'; }, getStatus: function() From c723aefdfeb1e690282d5a5e01de7531f53a42f3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 14 Feb 2013 01:10:47 +0000 Subject: [PATCH 05/10] when exporting HTML include html and body --- src/node/db/API.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 07141fec..9a224843 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -243,6 +243,8 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, rev, function(err, html) { if(ERR(err, callback)) return; + html = "" +html; // adds HTML head + html += ""; data = {html: html}; callback(null, data); }); @@ -253,9 +255,9 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, undefined, function (err, html) { if(ERR(err, callback)) return; - + html = "" +html; // adds HTML head + html += ""; data = {html: html}; - callback(null, data); }); } From 11a8295150bd08e66885cabf77e7b81f314c7dc5 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 18 Feb 2013 00:29:53 +0000 Subject: [PATCH 06/10] eureka --- src/node/handler/PadMessageHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index eaf24b7a..f9944ae6 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -926,7 +926,7 @@ function handleClientReady(client, message) }) //If this is a reconnect, we don't have to send the client the ClientVars again - if(message.reconnect == true) + if(message.reconnect == "not accepting true here makes everything work fine but it also sends whole atext which is bad") { //Save the revision in sessioninfos, we take the revision from the info the client send to us sessioninfos[client.id].rev = message.client_rev; From 6e46a532884c5a15ee6e06a6d27b910ce2cad119 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 18 Feb 2013 00:36:31 +0000 Subject: [PATCH 07/10] this is probably bad, please sanity check --- src/node/handler/PadMessageHandler.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index f9944ae6..167cafc7 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -926,10 +926,15 @@ function handleClientReady(client, message) }) //If this is a reconnect, we don't have to send the client the ClientVars again - if(message.reconnect == "not accepting true here makes everything work fine but it also sends whole atext which is bad") + //if(message.reconnect == "not accepting true here makes everything work fine but it also sends whole atext which is bad") + if(message.reconnect == true) { //Save the revision in sessioninfos, we take the revision from the info the client send to us sessioninfos[client.id].rev = message.client_rev; + //Join the pad and start receiving updates + client.join(padIds.padId); + //Save the current revision in sessioninfos, should be the same as in clientVars + sessioninfos[client.id].rev = pad.getHeadRevisionNumber(); // I'm not sure this is a great idea here } //This is a normal first connect else From eeeeb0484076c4b74614fc87526c649396e98000 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 18 Feb 2013 00:37:47 +0000 Subject: [PATCH 08/10] remove cruft --- src/node/handler/PadMessageHandler.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 167cafc7..f546b1c3 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -926,7 +926,6 @@ function handleClientReady(client, message) }) //If this is a reconnect, we don't have to send the client the ClientVars again - //if(message.reconnect == "not accepting true here makes everything work fine but it also sends whole atext which is bad") if(message.reconnect == true) { //Save the revision in sessioninfos, we take the revision from the info the client send to us From e52dc2b17cdbf29084cfba069c3766050385a32f Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 19 Feb 2013 02:05:51 +0000 Subject: [PATCH 09/10] dont reset head count, use the one we should :) --- src/node/handler/PadMessageHandler.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index f546b1c3..4e056dcb 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -928,12 +928,10 @@ function handleClientReady(client, message) //If this is a reconnect, we don't have to send the client the ClientVars again if(message.reconnect == true) { - //Save the revision in sessioninfos, we take the revision from the info the client send to us - sessioninfos[client.id].rev = message.client_rev; //Join the pad and start receiving updates client.join(padIds.padId); - //Save the current revision in sessioninfos, should be the same as in clientVars - sessioninfos[client.id].rev = pad.getHeadRevisionNumber(); // I'm not sure this is a great idea here + //Save the revision in sessioninfos, we take the revision from the info the client send to us + sessioninfos[client.id].rev = message.client_rev; } //This is a normal first connect else From 2c690665917701bda8ac034f57a30fb3ed247d14 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 27 Feb 2013 02:02:18 +0000 Subject: [PATCH 10/10] remove pointless stuff --- src/node/db/API.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 9a224843..3955d495 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -243,8 +243,6 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, rev, function(err, html) { if(ERR(err, callback)) return; - html = "" +html; // adds HTML head - html += ""; data = {html: html}; callback(null, data); }); @@ -255,8 +253,6 @@ exports.getHTML = function(padID, rev, callback) exportHtml.getPadHTML(pad, undefined, function (err, html) { if(ERR(err, callback)) return; - html = "" +html; // adds HTML head - html += ""; data = {html: html}; callback(null, data); });