diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js
index 4b594ad..b36d7b5 100644
--- a/src/app/channel/channelManager.js
+++ b/src/app/channel/channelManager.js
@@ -22,6 +22,7 @@ const channelModel = require('../../schemas/channel/channelSchema');
const emoteModel = require('../../schemas/emoteSchema');
const {userModel} = require('../../schemas/user/userSchema');
const userBanModel = require('../../schemas/user/userBanSchema');
+const socketUtils = require('../../utils/socketUtils');
const loggerUtils = require('../../utils/loggerUtils');
const csrfUtils = require('../../utils/csrfUtils');
const presenceUtils = require('../../utils/presenceUtils');
@@ -68,7 +69,7 @@ class channelManager{
async handleConnection(socket){
try{
//ensure unbanned ip and valid CSRF token
- if(!(await this.validateSocket(socket))){
+ if(!(await socketUtils.validateSocket(socket))){
socket.disconnect();
return;
}
@@ -76,7 +77,7 @@ class channelManager{
//Prevent logged out connections and authenticate socket
if(socket.request.session.user != null){
//Authenticate socket
- const userDB = await this.authSocket(socket);
+ const userDB = await socketUtils.authSocket(socket);
//Get the active channel based on the socket
var {activeChan, chanDB} = await this.getActiveChan(socket);
@@ -146,71 +147,7 @@ class channelManager{
//Flip a table if something fucks up
return loggerUtils.socketCriticalExceptionHandler(socket, err);
}
- }
-
- /**
- * Global server-side validation logic for new connections to any channel
- * @param {Socket} socket - Requesting Socket
- * @returns {Boolean} true on success
- */
- async validateSocket(socket){
- //If we're proxied use passthrough IP
- const ip = config.proxied ? socket.handshake.headers['x-forwarded-for'] : socket.handshake.address;
-
- //Look for ban by IP
- const ipBanDB = await userBanModel.checkBanByIP(ip);
-
- //If this ip is randy bobandy
- if(ipBanDB != null){
- //Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
- const expiration = ipBanDB.getDaysUntilExpiration() < 1 ? 0 : ipBanDB.getDaysUntilExpiration();
-
- //If the ban is permanent
- if(ipBanDB.permanent){
- //tell it to fuck off
- socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been permanently banned. Your cleartext IP has been saved to the database. Any associated accounts will be nuked in ${expiration} day(s).`});
- //Otherwise
- }else{
- //tell it to fuck off
- socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been temporarily banned. Your cleartext IP has been saved to the database until the ban expires in ${expiration} day(s).`});
- }
-
-
- return false;
- }
-
-
- //Check for Cross-Site Request Forgery
- if(!csrfUtils.isRequestValid(socket.request)){
- socket.emit("kick", {type: "disconnected", reason: "Invalid CSRF Token!"});
- return false;
- }
-
-
- return true;
- }
-
- /**
- * Global server-side authorization logic for new connections to any channel
- * @param {Socket} socket - Requesting Socket
- * @returns {Mongoose.Document} - Authorized User Document upon success
- */
- 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 loggerUtils.exceptionSmith("User not found!", "unauthorized");
- }
-
- //Set socket user and channel values
- socket.user = {
- id: userDB.id,
- user: userDB.user,
- };
-
- return userDB;
- }
+ }
/**
* Gets active channel from a given socket
diff --git a/src/utils/presenceUtils.js b/src/utils/presenceUtils.js
index 0096b69..310db6c 100644
--- a/src/utils/presenceUtils.js
+++ b/src/utils/presenceUtils.js
@@ -16,7 +16,7 @@ along with this program. If not, see .*/
//local includes
const server = require('../server');
-const userSchema = require('../schemas/user/userSchema');
+const {userModel} = require('../schemas/user/userSchema');
//User activity map to keep us from constantly reading off of the DB
let activityMap = new Map();
@@ -47,7 +47,7 @@ module.exports.getPresence = async function(user, userDB){
//If we wheren't handed a free user doc
if(userDB == null){
//Pull one from the username
- userDB = await userSchema.userModel.findOne({user: user});
+ userDB = await userModel.findOne({user: user});
}
//If for some reason we can't find a user doc
@@ -119,7 +119,7 @@ module.exports.handlePresence = async function(user, userDB, noSave = false){
//If we wheren't handed a free user doc
if(userDB == null){
//Pull one from the username
- userDB = await userSchema.userModel.findOne({user: user});
+ userDB = await userModel.findOne({user: user});
}
//Set last active in user's DB document
diff --git a/src/utils/socketUtils.js b/src/utils/socketUtils.js
new file mode 100644
index 0000000..68fc46a
--- /dev/null
+++ b/src/utils/socketUtils.js
@@ -0,0 +1,97 @@
+/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .*/
+
+const config = require('../../config.json');
+const csrfUtils = require('./csrfUtils');
+const {userModel} = require('../schemas/user/userSchema');
+const userBanModel = require('../schemas/user/userBanSchema');
+
+module.exports.validateSocket = async function(socket, quiet = false){
+ //If we're proxied use passthrough IP
+ const ip = config.proxied ? socket.handshake.headers['x-forwarded-for'] : socket.handshake.address;
+
+ //Look for ban by IP
+ const ipBanDB = await userBanModel.checkBanByIP(ip);
+
+ //If this ip is randy bobandy
+ if(ipBanDB != null){
+ //Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
+ const expiration = ipBanDB.getDaysUntilExpiration() < 1 ? 0 : ipBanDB.getDaysUntilExpiration();
+
+ if(quiet){
+ socket.disconnect();
+ }else{
+ //If the ban is permanent
+ if(ipBanDB.permanent){
+ //tell it to fuck off
+ socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been permanently banned. Your cleartext IP has been saved to the database. Any associated accounts will be nuked in ${expiration} day(s).`});
+ //Otherwise
+ }else{
+ //tell it to fuck off
+ socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been temporarily banned. Your cleartext IP has been saved to the database until the ban expires in ${expiration} day(s).`});
+ }
+ }
+
+ return false;
+ }
+
+
+ //Check for Cross-Site Request Forgery
+ if(!csrfUtils.isRequestValid(socket.request)){
+ if(quiet){
+ socket.disconnect();
+ }else{
+ socket.emit("kick", {type: "disconnected", reason: "Invalid CSRF Token!"});
+ }
+
+ return false;
+ }
+
+
+ return true;
+}
+
+//socket.request.session is already trusted, we don't actually need to verify against DB for authorzation
+//It's just a useful place to grab the DB doc, and is mostly a stand-in from when the only socket-related code was in the channel folder
+module.exports.authSocketLite = async function(socket){
+ const user = socket.request.session.user;
+
+ //Set socket user and channel values
+ socket.user = {
+ id: user.id,
+ user: user.user,
+ };
+
+ //return user object from session
+ return user;
+}
+
+module.exports.authSocket = async function(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 loggerUtils.exceptionSmith("User not found!", "unauthorized");
+ }
+
+ //Set socket user and channel values
+ socket.user = {
+ id: userDB.id,
+ user: userDB.user,
+ };
+
+ return userDB;
+}
\ No newline at end of file
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js
index f7955d1..0377d1e 100644
--- a/www/js/channel/channel.js
+++ b/www/js/channel/channel.js
@@ -89,11 +89,11 @@ class channel{
this.socket.on("kick", async (data) => {
if(data.reason == "Invalid CSRF Token!"){
- //Reload the CSRF token
- await utils.ajax.reloadCSRFToken();
+ //Warn the user
+ new canopyUXUtils.popup('Invalid CSRF Token detected, reloading client...');
- //Retry the connection
- this.connect();
+ //Just reload the fucker
+ setTimeout(()=>{location.reload();}, 1000);
}else{
new canopyUXUtils.popup(`You have been ${data.type} from the channel for the following reason:
${data.reason}`);
}