etherpad-lite/src/node/hooks/express/socketio.js

99 lines
4.4 KiB
JavaScript
Raw Normal View History

var settings = require('../../utils/Settings');
var socketio = require('socket.io');
var socketIORouter = require("../../handler/SocketIORouter");
2012-03-01 19:00:58 +01:00
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess");
2012-02-25 16:44:37 +01:00
var padMessageHandler = require("../../handler/PadMessageHandler");
2012-02-25 16:44:37 +01:00
2015-04-07 07:55:05 -05:00
var cookieParser = require('cookie-parser');
var sessionModule = require('express-session');
const util = require('util');
2012-02-25 16:44:37 +01:00
exports.expressCreateServer = function (hook_name, args, cb) {
//init socket.io and redirect all requests to the MessageHandler
// there shouldn't be a browser that isn't compatible to all
// transports in this list at once
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
var io = socketio({
transports: settings.socketTransportProtocols
}).listen(args.server, {
/*
* Do not set the "io" cookie.
*
* The "io" cookie is created by socket.io, and its purpose is to offer an
* handle to perform load balancing with session stickiness when the library
* falls back to long polling or below.
*
* In Etherpad's case, if an operator needs to load balance, he can use the
* "express_sid" cookie, and thus "io" is of no use.
*
* Moreover, socket.io API does not offer a way of setting the "secure" flag
* on it, and thus is a liability.
*
* Let's simply nuke "io".
*
* references:
* https://socket.io/docs/using-multiple-nodes/#Sticky-load-balancing
* https://github.com/socketio/socket.io/issues/2276#issuecomment-147184662 (not totally true, actually, see above)
*/
cookie: false,
});
2012-02-25 16:44:37 +01:00
// REQUIRE a signed express-session cookie to be present, then load the session. See
// http://www.danielbaulig.de/socket-ioexpress for more info. After the session is loaded, ensure
// that the user has authenticated (if authentication is required).
//
// !!!WARNING!!! Requests to /socket.io are NOT subject to the checkAccess middleware in
// webaccess.js. If this handler fails to check for a signed express-session cookie or fails to
// check whether the user has authenticated, then any random person on the Internet can read,
// modify, or create any pad (unless the pad is password protected or an HTTP API session is
// required).
const cookieParserFn = util.promisify(cookieParser(webaccess.secret, {}));
const getSession = util.promisify(args.app.sessionStore.get).bind(args.app.sessionStore);
io.use(async (socket, next) => {
const req = socket.request;
if (!req.headers.cookie) {
// socketio.js-client on node.js doesn't support cookies (see https://git.io/JU8u9), so the
// token and express_sid cookies have to be passed via a query parameter for unit tests.
req.headers.cookie = socket.handshake.query.cookie;
}
if (!req.headers.cookie && settings.loadTest) {
console.warn('bypassing socket.io authentication check due to settings.loadTest');
return next(null, true);
}
try {
await cookieParserFn(req, {});
const expressSid = req.signedCookies.express_sid;
const needAuthn = settings.requireAuthentication;
if (needAuthn && !expressSid) throw new Error('signed express_sid cookie is required');
if (expressSid) {
const session = await getSession(expressSid);
if (!session) throw new Error('bad session or session has expired');
req.session = new sessionModule.Session(req, session);
if (needAuthn && req.session.user == null) throw new Error('authentication required');
}
} catch (err) {
return next(new Error(`access denied: ${err}`), false);
}
return next(null, true);
2012-04-19 14:25:12 +02:00
});
2014-11-04 19:11:06 +00:00
// var socketIOLogger = log4js.getLogger("socket.io");
// Debug logging now has to be set at an environment level, this is stupid.
// https://github.com/Automattic/socket.io/wiki/Migrating-to-1.0
// This debug logging environment is set in Settings.js
2012-02-25 16:44:37 +01:00
//minify socket.io javascript
// Due to a shitty decision by the SocketIO team minification is
// no longer available, details available at:
// http://stackoverflow.com/questions/23981741/minify-socket-io-socket-io-js-with-1-0
// if(settings.minify) io.enable('browser client minification');
2012-02-25 16:44:37 +01:00
//Initalize the Socket.IO Router
socketIORouter.setSocketIO(io);
socketIORouter.addComponent("pad", padMessageHandler);
hooks.callAll("socketio", {"app": args.app, "io": io, "server": args.server});
2012-02-25 16:44:37 +01:00
}