diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 21b067f58e..dcd9aa371f 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -379,7 +379,7 @@ authenticationController.onSuccessfulLogin = async function (req, uid) { }), user.auth.addSession(uid, req.sessionID), user.updateLastOnlineTime(uid), - user.updateOnlineUsers(uid), + user.onUserOnline(uid, Date.now()), analytics.increment('logins'), db.incrObjectFieldBy('global', 'loginCount', 1), ]); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index a4a4327005..67a1e4bda0 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -112,48 +112,49 @@ async function onMessage(socket, payload) { return winston.warn('[socket.io] Empty payload'); } - const eventName = payload.data[0]; + let eventName = payload.data[0]; const params = typeof payload.data[1] === 'function' ? {} : payload.data[1]; const callback = typeof payload.data[payload.data.length - 1] === 'function' ? payload.data[payload.data.length - 1] : function () {}; - if (!eventName) { - return winston.warn('[socket.io] Empty method name'); - } - - if (typeof eventName !== 'string') { - const escapedName = validator.escape(String(eventName)); - return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); - } + try { + if (!eventName) { + return winston.warn('[socket.io] Empty method name'); + } - const parts = eventName.split('.'); - const namespace = parts[0]; - const methodToCall = parts.reduce((prev, cur) => { - if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) { - return prev[cur]; + if (typeof eventName !== 'string') { + eventName = typeof eventName; + const escapedName = validator.escape(eventName); + return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); } - return null; - }, Namespaces); - if (!methodToCall || typeof methodToCall !== 'function') { - if (process.env.NODE_ENV === 'development') { - winston.warn(`[socket.io] Unrecognized message: ${eventName}`); + const parts = eventName.split('.'); + const namespace = parts[0]; + const methodToCall = parts.reduce((prev, cur) => { + if (prev !== null && prev[cur] && (!prev.hasOwnProperty || prev.hasOwnProperty(cur))) { + return prev[cur]; + } + return null; + }, Namespaces); + + if (!methodToCall || typeof methodToCall !== 'function') { + if (process.env.NODE_ENV === 'development') { + winston.warn(`[socket.io] Unrecognized message: ${eventName}`); + } + const escapedName = validator.escape(String(eventName)); + return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); } - const escapedName = validator.escape(String(eventName)); - return callback({ message: `[[error:invalid-event, ${escapedName}]]` }); - } - socket.previousEvents = socket.previousEvents || []; - socket.previousEvents.push(eventName); - if (socket.previousEvents.length > 20) { - socket.previousEvents.shift(); - } + socket.previousEvents = socket.previousEvents || []; + socket.previousEvents.push(eventName); + if (socket.previousEvents.length > 20) { + socket.previousEvents.shift(); + } - if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) { - winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`); - return socket.disconnect(); - } + if (!eventName.startsWith('admin.') && ratelimit.isFlooding(socket)) { + winston.warn(`[socket.io] Too many emits! Disconnecting uid : ${socket.uid}. Events : ${socket.previousEvents}`); + return socket.disconnect(); + } - try { await checkMaintenance(socket); await validateSession(socket, '[[error:revalidate-failure]]'); diff --git a/src/user/online.js b/src/user/online.js index ffba4c9a94..b7c6b9d45a 100644 --- a/src/user/online.js +++ b/src/user/online.js @@ -27,9 +27,13 @@ module.exports = function (User) { if (now - parseInt(userOnlineTime, 10) < 300000) { return; } - await db.sortedSetAdd('users:online', now, uid); + await User.onUserOnline(uid, now); topics.pushUnreadCount(uid); - plugins.hooks.fire('action:user.online', { uid: uid, timestamp: now }); + }; + + User.onUserOnline = async (uid, timestamp) => { + await db.sortedSetAdd('users:online', timestamp, uid); + plugins.hooks.fire('action:user.online', { uid, timestamp }); }; User.isOnline = async function (uid) { diff --git a/test/socket.io.js b/test/socket.io.js index e95eb6527e..726f6f71ad 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -110,8 +110,7 @@ describe('socket.io', () => { it('should return error for invalid eventName type', (done) => { const eventName = ['topics.loadMoreTags']; io.emit(eventName, (err) => { - const eventAsString = String(eventName); - assert.strictEqual(err.message, `[[error:invalid-event, ${eventAsString}]]`); + assert.strictEqual(err.message, `[[error:invalid-event, object]]`); done(); }); });