From 5b5f495853cf91ed6135a4839b31875a9953ead9 Mon Sep 17 00:00:00 2001 From: rainbownapkin Date: Wed, 20 Nov 2024 06:54:44 -0500 Subject: [PATCH] Cleaned up 'src/app/channel' --- src/app/channel/activeChannel.js | 63 ++++++++++++- src/app/channel/channelManager.js | 148 ++++++++++++------------------ src/app/channel/chatHandler.js | 67 +++++++------- src/utils/loggerUtils.js | 5 + 4 files changed, 160 insertions(+), 123 deletions(-) diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js index 143c03e..949e438 100644 --- a/src/app/channel/activeChannel.js +++ b/src/app/channel/activeChannel.js @@ -15,8 +15,69 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ module.exports = class{ - constructor(name){ + constructor(server, name){ + this.server = server; this.name = name; this.userList = new Map(); } + + handleConnection(userDB, socket){ + //get current user object from the userlist + var userObj = this.userList.get(userDB.user); + + //If user is already connected + if(userObj){ + //Add this socket on to the userobject + userObj.sockets.push(socket.id); + }else{ + //if this is the first connection, initialize the userObject w/ the current socked id + userObj = { + id: userDB.id, + rank: userDB.rank, + flair: userDB.flair, + sockets: [socket.id] + } + } + + //Set user entry in userlist + this.userList.set(userDB.user, userObj); + + //if everything looks good, admit the connection to the channel + socket.join(socket.chan); + + //Send out the userlist + this.broadcastUserList(socket.chan); + } + + handleDisconnect(socket, reason){ + //If we have more than one active connection + if(this.userList.get(socket.user.user).sockets.length > 1){ + //temporarily store userObj + var userObj = this.userList.get(socket.user.user); + + //Filter out disconnecting socket from socket list, and set as current socket list for user + userObj.sockets = userObj.sockets.filter((id) => { + return id != socket.id; + }); + + //Update the userlist + this.userList.set(socket.user.user, userObj); + }else{ + //If this is the last connection for this user, remove them from the userlist + this.userList.delete(socket.user.user); + } + + //and send out the filtered list + this.broadcastUserList(socket.chan); + } + + broadcastUserList(){ + var userList = []; + + this.userList.forEach((userObj, user) => { + userList.push(user); + }); + + this.server.io.in(this.name).emit("user-list", userList); + } } \ No newline at end of file diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js index 74cb43a..7b0006e 100644 --- a/src/app/channel/channelManager.js +++ b/src/app/channel/channelManager.js @@ -18,6 +18,7 @@ along with this program. If not, see .*/ const channelModel = require('../../schemas/channelSchema'); const flairModel = require('../../schemas/flairSchema'); const userModel = require('../../schemas/userSchema'); +const loggerUtils = require('../../utils/loggerUtils'); const activeChannel = require('./activeChannel'); const chatHandler = require('./chatHandler'); @@ -40,111 +41,78 @@ module.exports = class{ //Prevent logged out connections and authenticate socket if(socket.request.session.user != null){ try{ - //Find the user in the Database since the session won't store enough data to fulfill our needs :P - const userDB = await userModel.findOne({user: socket.request.session.user.user}); + //Authenticate socket + const userDB = await this.authSocket(socket); - //Set socket user and channel values - socket.user = { - id: userDB.id, - user: userDB.user, - }; + //Get the active channel based on the socket + var activeChan = await this.getActiveChan(socket); - socket.chanName = socket.handshake.headers.referer.split('/c/')[1]; - - //Check if channel exists - if(await channelModel.findOne({name: socket.chanName}) == null){ - socket.disconnect("Channel does not exist!"); - return; - } - - //Check if current channel is active - var activeChan = this.activeChannels.get(socket.chan); - if(!activeChan){ - //If not, make it so - activeChan = new activeChannel(socket.chan); - this.activeChannels.set(socket.chan, activeChan); - } - - //Check if this user is already connected - if(activeChan.userList.get(socket.user.user)){ - //get current list of socket connnections of selected user - var userObj = activeChan.userList.get(userDB.user); - //Add this one on - userObj.sockets.push(socket.id); - //Set the user back socket list back - activeChan.userList.set(userDB.user, userObj); - }else{ - //if this is the first connection, initialize the socket array for this user - var userObj = { - id: userDB.id, - rank: userDB.rank, - flair: userDB.flair, - sockets: [socket.id] - } - - activeChan.userList.set(userDB.user, userObj); - } - - //if everything looks good, admit the connection to the channel - socket.join(socket.chan); - - //Send out the userlist - this.broadcastUserList(socket.chan); + //Define listeners + this.defineListeners(socket); + this.chatHandler.defineListeners(socket); + //Connect the socket to it's given channel + activeChan.handleConnection(userDB, socket); }catch(err){ - socket.disconnect("Server Error During Channel Connection Initialization"); - console.log(err); - return; + //Flip a table if something fucks up + return loggerUtils.socketCriticalExceptionHandler(socket, err); } - }else{ + //Toss out anon's socket.disconnect("Unauthenticated"); return; } + } + async authSocket(socket){ + //Find the user in the Database since the session won't store enough data to fulfill our needs :P + const userDB = await userModel.findOne({user: socket.request.session.user.user}); + + if(userDB == null){ + throw new Error("User not found!"); + } + + //Set socket user and channel values + socket.user = { + id: userDB.id, + user: userDB.user, + }; + + return userDB; + } + + async getActiveChan(socket){ + socket.chan = socket.handshake.headers.referer.split('/c/')[1]; + + //Check if channel exists + if(await channelModel.findOne({name: socket.chan}) == null){ + throw new Error("Channel not found!") + } + + //Check if current channel is active + var activeChan = this.activeChannels.get(socket.chan); + + if(!activeChan){ + //If not, make it so + activeChan = new activeChannel(this, socket.chan); + this.activeChannels.set(socket.chan, activeChan); + } + + //Return whatever the active channel is (new or old) + return activeChan; + } + + defineListeners(socket){ //Socket Listeners - socket.conn.on("close", (reason) => { - //Get active channel - var activeChan = this.activeChannels.get(socket.chan); - - //If we have more than one active connection - if(activeChan.userList.get(socket.user.user).sockets.length > 1){ - //temporarily store userObj - var userObj = activeChan.userList.get(socket.user.user); - - //Filter out disconnecting socket from socket list, and set as current socket list for user - userObj.sockets = userObj.sockets.filter((id) => { - return id != socket.id; - }); - - //Update the userlist - activeChan.userList.set(socket.user.user, userObj); - }else{ - //If this is the last connection for this user, remove them from the userlist - activeChan.userList.delete(socket.user.user); - } - - //and send out the filtered list - this.broadcastUserList(socket.chan); - }); - - //define chat listeners - this.chatHandler.defineListeners(socket); - + socket.conn.on("close", (reason) => {this.handleDisconnect(socket, reason)}); } - broadcastUserList(chan){ - var activeChan = this.activeChannels.get(chan); - var userList = []; - - activeChan.userList.forEach((socketlist, user) => { - userList.push(user); - }); - - this.io.in(chan).emit("user-list", userList); + handleDisconnect(socket, reason){ + var activeChan = this.activeChannels.get(socket.chan); + activeChan.handleDisconnect(socket, reason); } - socketToUser(socket){ + getSocketInfo(socket){ const channel = this.activeChannels.get(socket.chan); return channel.userList.get(socket.user.user); } diff --git a/src/app/channel/chatHandler.js b/src/app/channel/chatHandler.js index 327071e..48f6ffd 100644 --- a/src/app/channel/chatHandler.js +++ b/src/app/channel/chatHandler.js @@ -28,39 +28,42 @@ module.exports = class{ } defineListeners(socket){ - socket.on("chatMessage", (data) => { - //Trim and Sanatize for XSS - const msg = validator.trim(validator.escape(data.msg)); - //make sure high is an int - const high = validator.toInt(data.high); - - const user = this.server.socketToUser(socket); + socket.on("chatMessage", (data) => {this.relayChat(socket, data)}); + socket.on("setFlair", async (data) => {this.setFlair(socket, data)}); + } - //nuke the message if its empty or huge - if(!validator.isLength(msg, {min: 1, max: 255})){ - return; + relayChat(socket, data){ + //Trim and Sanatize for XSS + const msg = validator.trim(validator.escape(data.msg)); + //make sure high is an int + const high = validator.toInt(data.high); + + const user = this.server.getSocketInfo(socket); + + //nuke the message if its empty or huge + if(!validator.isLength(msg, {min: 1, max: 255})){ + return; + } + + //nuke the message if the high number is wrong + if(high < 0 || high > 10){ + return; + } + + this.server.io.in(socket.chan).emit("chatMessage", {user: socket.user.user, flair: user.flair, high, msg}); + } + + async setFlair(socket, data){ + const userDB = await userModel.findOne({user: socket.user.user}); + + if(userDB){ + try{ + //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries + userDB.flair = data.flair; + await userDB.save(); + }catch(err){ + return loggerUtils.socketExceptionHandler(socket, err); } - - //nuke the message if the high number is wrong - if(high < 0 || high > 10){ - return; - } - - this.server.io.in(socket.chan).emit("chatMessage", {user: socket.user.user, flair: user.flair, high, msg}); - }); - - socket.on("setFlair", async (data) => { - const userDB = await userModel.findOne({user: socket.user.user}); - - if(userDB){ - try{ - //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries - userDB.flair = data.flair; - await userDB.save(); - }catch(err){ - return loggerUtils.socketExceptionHandler(socket, err); - } - } - }); + } } } \ No newline at end of file diff --git a/src/utils/loggerUtils.js b/src/utils/loggerUtils.js index 86fd372..7e246c5 100644 --- a/src/utils/loggerUtils.js +++ b/src/utils/loggerUtils.js @@ -24,4 +24,9 @@ module.exports.exceptionHandler = function(res, err){ module.exports.socketExceptionHandler = function(socket, err){ //if not yell at the browser for fucking up, and tell it what it did wrong. return socket.emit("error", {errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]}); +} + +module.exports.socketCriticalExceptionHandler = function(socket, err){ + //if not yell at the browser for fucking up, and tell it what it did wrong. + return socket.disconnect("error", {errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]}); } \ No newline at end of file