mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	feat: add req and socket to als, closes https://github.com/NodeBB/NodeBB/pull/10304
This commit is contained in:
		| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user