feat: add req and socket to als, closes https://github.com/NodeBB/NodeBB/pull/10304

isekai-main
Barış Soner Uşaklı 2 years ago
parent 21919524bb
commit 68ddca1e02

@ -21,6 +21,7 @@ exports.setDefaultPostData = function (reqOrSocket, data) {
exports.buildReqObject = (req, payload) => { exports.buildReqObject = (req, payload) => {
req = req || {}; req = req || {};
const headers = req.headers || (req.request && req.request.headers) || {}; const headers = req.headers || (req.request && req.request.headers) || {};
const session = req.session || (req.request && req.request.session) || {};
const encrypted = req.connection ? !!req.connection.encrypted : false; const encrypted = req.connection ? !!req.connection.encrypted : false;
let { host } = headers; let { host } = headers;
const referer = headers.referer || ''; const referer = headers.referer || '';
@ -34,13 +35,15 @@ exports.buildReqObject = (req, payload) => {
params: req.params, params: req.params,
method: req.method, method: req.method,
body: payload || req.body, body: payload || req.body,
session: req.session, session: session,
ip: req.ip, ip: req.ip,
host: host, host: host,
protocol: encrypted ? 'https' : 'http', protocol: encrypted ? 'https' : 'http',
secure: encrypted, secure: encrypted,
url: referer, url: referer,
path: referer.slice(referer.indexOf(host) + host.length), path: referer.slice(referer.indexOf(host) + host.length),
baseUrl: req.baseUrl,
originalUrl: req.originalUrl,
headers: headers, headers: headers,
}; };
}; };

@ -84,9 +84,14 @@ function onConnection(socket) {
onConnect(socket); onConnect(socket);
socket.onAny((event, ...args) => { socket.onAny((event, ...args) => {
const payload = { data: [event].concat(args) }; const payload = { event: event, ...deserializePayload(args) };
const als = require('../als'); const als = require('../als');
als.run({ uid: socket.uid }, onMessage, socket, payload); const apiHelpers = require('../api/helpers');
als.run({
uid: socket.uid,
req: apiHelpers.buildReqObject(socket, payload),
socket: { ...payload },
}, onMessage, socket, payload);
}); });
socket.on('disconnect', () => { socket.on('disconnect', () => {
@ -123,27 +128,29 @@ async function onConnect(socket) {
plugins.hooks.fire('action:sockets.connect', { socket: socket }); plugins.hooks.fire('action:sockets.connect', { socket: socket });
} }
async function onMessage(socket, payload) { function deserializePayload(payload) {
if (!payload.data.length) { if (!Array.isArray(payload) || !payload.length) {
return winston.warn('[socket.io] Empty payload'); winston.warn('[socket.io] Empty payload');
return {};
} }
const params = typeof payload[0] === 'function' ? {} : payload[0];
const callback = typeof payload[payload.length - 1] === 'function' ? payload[payload.length - 1] : function () {};
return { params, callback };
}
let eventName = payload.data[0]; async function onMessage(socket, payload) {
const params = typeof payload.data[1] === 'function' ? {} : payload.data[1]; const { event, params, callback } = payload;
const callback = typeof payload.data[payload.data.length - 1] === 'function' ? payload.data[payload.data.length - 1] : function () {};
try { try {
if (!eventName) { if (!event) {
return winston.warn('[socket.io] Empty method name'); return winston.warn('[socket.io] Empty method name');
} }
if (typeof eventName !== 'string') { if (typeof event !== 'string') {
eventName = typeof eventName; const escapedName = validator.escape(typeof event);
const escapedName = validator.escape(eventName);
return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
} }
const parts = eventName.split('.'); const parts = event.split('.');
const namespace = parts[0]; const namespace = parts[0];
const methodToCall = parts.reduce((prev, cur) => { const methodToCall = parts.reduce((prev, cur) => {
if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) { if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) {
@ -154,19 +161,19 @@ async function onMessage(socket, payload) {
if (!methodToCall || typeof methodToCall !== 'function') { if (!methodToCall || typeof methodToCall !== 'function') {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
winston.warn(`[socket.io] Unrecognized message: ${eventName}`); winston.warn(`[socket.io] Unrecognized message: ${event}`);
} }
const escapedName = validator.escape(String(eventName)); const escapedName = validator.escape(String(event));
return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); return callback({ message: `[[error:invalid-event, ${escapedName}]]` });
} }
socket.previousEvents = socket.previousEvents || []; socket.previousEvents = socket.previousEvents || [];
socket.previousEvents.push(eventName); socket.previousEvents.push(event);
if (socket.previousEvents.length > 20) { if (socket.previousEvents.length > 20) {
socket.previousEvents.shift(); socket.previousEvents.shift();
} }
if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) { if (!event.startsWith('admin.') && ratelimit.isFlooding(socket)) {
winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`); winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`);
return socket.disconnect(); return socket.disconnect();
} }
@ -175,7 +182,7 @@ async function onMessage(socket, payload) {
await validateSession(socket, '[[error:revalidate-failure]]'); await validateSession(socket, '[[error:revalidate-failure]]');
if (Namespaces[namespace].before) { if (Namespaces[namespace].before) {
await Namespaces[namespace].before(socket, eventName, params); await Namespaces[namespace].before(socket, event, params);
} }
if (methodToCall.constructor && methodToCall.constructor.name === 'AsyncFunction') { if (methodToCall.constructor && methodToCall.constructor.name === 'AsyncFunction') {
@ -187,7 +194,7 @@ async function onMessage(socket, payload) {
}); });
} }
} catch (err) { } catch (err) {
winston.error(`${eventName}\n${err.stack ? err.stack : err.message}`); winston.error(`${event}\n${err.stack ? err.stack : err.message}`);
callback({ message: err.message }); callback({ message: err.message });
} }
} }

@ -176,8 +176,12 @@ function setupExpressApp(app) {
app.use(middleware.processRender); app.use(middleware.processRender);
auth.initialize(app, middleware); auth.initialize(app, middleware);
const als = require('./als'); const als = require('./als');
const apiHelpers = require('./api/helpers');
app.use((req, res, next) => { app.use((req, res, next) => {
als.run({ uid: req.uid }, next); als.run({
uid: req.uid,
req: apiHelpers.buildReqObject(req),
}, next);
}); });
app.use(middleware.autoLocale); // must be added after auth middlewares are added app.use(middleware.autoLocale); // must be added after auth middlewares are added

Loading…
Cancel
Save