Base implementation of PM back-end started.
This commit is contained in:
parent
7da07c8717
commit
67edef9035
|
|
@ -20,20 +20,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
class message{
|
class message{
|
||||||
/**
|
/**
|
||||||
* Instantiates a chat message object
|
* Instantiates a chat message object
|
||||||
* @param {connectedUser} sender - User who sent the message
|
* @param {String} sender - Name of user who sent the message
|
||||||
* @param {Array} recipients - Array of connected users who are supposed to receive the message
|
* @param {Array} recipients - Array of usernames who are supposed to receive the message
|
||||||
* @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
|
* @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
|
||||||
* @param {Array} links - Array of URLs/Links included in the message.
|
* @param {Array} links - Array of URLs/Links included in the message.
|
||||||
*/
|
*/
|
||||||
constructor(sender, recipients, msg, links){
|
constructor(sender, recipients, msg, links){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User who sent the message
|
* Name of user who sent the message
|
||||||
*/
|
*/
|
||||||
this.sender = sender;
|
this.sender = sender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of strings containing usernames to send message to
|
* Array of usernames who are supposed to receive the message
|
||||||
*/
|
*/
|
||||||
this.recipients = recipients;
|
this.recipients = recipients;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,13 @@ GNU Affero General Public License for more details.
|
||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
|
//NPM Imports
|
||||||
|
const validator = require('validator');//No express here, so regular validator it is!
|
||||||
|
|
||||||
//local includes
|
//local includes
|
||||||
const config = require("../../../config.json");
|
const loggerUtils = require("../../utils/loggerUtils");
|
||||||
const csrfUtils = require("../../utils/csrfUtils");
|
const socketUtils = require("../../utils/socketUtils");
|
||||||
const userBanModel = require("../../schemas/user/userBanSchema");
|
const message = require("./message");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containg global server-side private message relay logic
|
* Class containg global server-side private message relay logic
|
||||||
|
|
@ -43,7 +46,123 @@ class pmHandler{
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleConnection(socket){
|
async handleConnection(socket){
|
||||||
|
try{
|
||||||
|
//ensure unbanned ip and valid CSRF token
|
||||||
|
if(!(await socketUtils.validateSocket(socket))){
|
||||||
|
socket.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the socket wasn't authorized
|
||||||
|
if(await socketUtils.authSocketLite(socket) == null){
|
||||||
|
socket.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Throw socket into room named after it's user
|
||||||
|
socket.join(socket.user.user);
|
||||||
|
|
||||||
|
//Define network related event listeners against socket
|
||||||
|
this.defineListeners(socket);
|
||||||
|
}catch(err){
|
||||||
|
//Flip a table if something fucks up
|
||||||
|
return loggerUtils.socketCriticalExceptionHandler(socket, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineListeners(socket){
|
||||||
|
socket.on("pm", (data)=>{this.handlePM(data, socket)});
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePM(data, socket){
|
||||||
|
try{
|
||||||
|
//Create empty list of recipients
|
||||||
|
let recipients = [];
|
||||||
|
|
||||||
|
//For each requested recipient
|
||||||
|
for(let user of data.recipients){
|
||||||
|
//If the given user is online and didn't send the message
|
||||||
|
if(this.checkPresence(user) && user != socket.user.user){
|
||||||
|
//Add the recipient to the list
|
||||||
|
recipients.push(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If we don't have any valid recipients
|
||||||
|
if(recipients.length <= 0){
|
||||||
|
//Drop that shit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sanatize Message
|
||||||
|
const msg = this.sanatizeMessage(data.msg);
|
||||||
|
|
||||||
|
//If we have an invalid message
|
||||||
|
if(msg == null){
|
||||||
|
//Drop that shit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create message object and relay it off to the recipients
|
||||||
|
this.relayPMObj(new message(
|
||||||
|
socket.user.user,
|
||||||
|
recipients,
|
||||||
|
msg,
|
||||||
|
[]
|
||||||
|
));
|
||||||
|
|
||||||
|
//If something fucked up
|
||||||
|
}catch(err){
|
||||||
|
//Bitch and moan
|
||||||
|
return loggerUtils.socketExceptionHandler(socket, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
relayPMObj(msg){
|
||||||
|
//For each recipient
|
||||||
|
for(let user of msg.recipients){
|
||||||
|
//Send the message
|
||||||
|
this.namespace.to(user).emit("message", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Acknowledge the sent message
|
||||||
|
this.namespace.to(msg.sender).emit("sent", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic function for checking presence
|
||||||
|
* This could be done using Channel Presence, but running off of bare Socket.io functionality makes this easier to implement outside the channel if need be
|
||||||
|
* @param {String} user - Username to check presence of
|
||||||
|
* @returns {Boolean} Whether or not the user is currently able to accept messages
|
||||||
|
*/
|
||||||
|
checkPresence(user){
|
||||||
|
//Pull room map from the guts of socket.io and run a null check against the given username
|
||||||
|
return this.namespace.adapter.rooms.get(user) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanatizes and Validates a single message, Temporary until we get commandPreprocessor split up.
|
||||||
|
* @param {String} msg - message to validate/sanatize
|
||||||
|
* @returns {String} sanatized/validates message, returns null on validation failure
|
||||||
|
*/
|
||||||
|
sanatizeMessage(msg){
|
||||||
|
//if msg is empty or null
|
||||||
|
if(msg == null || msg == ''){
|
||||||
|
//Pimp slap that shit into fucking oblivion
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Trim and Sanatize for XSS
|
||||||
|
msg = validator.trim(validator.escape(msg));
|
||||||
|
|
||||||
|
//Return whether or not the shit was long enough
|
||||||
|
if(validator.isLength(msg, {min: 1, max: 255})){
|
||||||
|
//If it's valid return the message
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if not return nothing
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,17 +173,40 @@ module.exports.errorMiddleware = function(err, req, res, next){
|
||||||
* @param {Error} err - error to dump to file
|
* @param {Error} err - error to dump to file
|
||||||
* @param {Date} date - Date of error, defaults to now
|
* @param {Date} date - Date of error, defaults to now
|
||||||
*/
|
*/
|
||||||
module.exports.dumpError = function(err, date = new Date()){
|
module.exports.dumpError = async function(err, date = new Date()){
|
||||||
try{
|
try{
|
||||||
const content = `Error Date: ${date.toLocaleString()} (UTC-${date.getTimezoneOffset()/60})\nError Type: ${err.name}\nError Msg:${err.message}\nStack Trace:\n\n${err.stack}`;
|
//Crash directory
|
||||||
const path = `log/crash/${date.getTime()}.log`;
|
const dir = "./log/crash/"
|
||||||
|
|
||||||
|
//Double check crash folder exists
|
||||||
|
try{
|
||||||
|
await fs.stat(dir);
|
||||||
|
//If we caught an error (most likely it's missing)
|
||||||
|
}catch(err){
|
||||||
|
//Shout about it
|
||||||
|
module.exports.consoleWarn("Log folder missing, mking dir!")
|
||||||
|
|
||||||
|
//Make it if doesn't
|
||||||
|
await fs.mkdir(dir, {recursive: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Assemble log file path
|
||||||
|
const path = `${dir}${date.getTime()}.log`;
|
||||||
|
//Generate error file content
|
||||||
|
const content = `Error Date: ${date.toLocaleString()} (UTC-${date.getTimezoneOffset()/60})\nError Type: ${err.name}\nError Msg:${err.message}\nStack Trace:\n\n${err.stack}`;
|
||||||
|
|
||||||
|
//Write content to file
|
||||||
fs.writeFile(path, content);
|
fs.writeFile(path, content);
|
||||||
|
|
||||||
|
//Whine about the error
|
||||||
module.exports.consoleWarn(`Warning: Unexpected Server Crash gracefully dumped to '${path}'... SOMETHING MAY BE VERY BROKEN!!!!`);
|
module.exports.consoleWarn(`Warning: Unexpected Server Crash gracefully dumped to '${path}'... SOMETHING MAY BE VERY BROKEN!!!!`);
|
||||||
|
//If somethine went really really wrong
|
||||||
}catch(doubleErr){
|
}catch(doubleErr){
|
||||||
|
//Use humor to cope with the pain
|
||||||
module.exports.consoleWarn("Yo Dawg, I herd you like errors, so I put an error in your error dump, so you can dump while you dump:");
|
module.exports.consoleWarn("Yo Dawg, I herd you like errors, so I put an error in your error dump, so you can dump while you dump:");
|
||||||
|
//Dump the original error to console
|
||||||
module.exports.consoleWarn(err);
|
module.exports.consoleWarn(err);
|
||||||
|
//Dump the error we had saving that error to file to console
|
||||||
module.exports.consoleWarn(doubleErr);
|
module.exports.consoleWarn(doubleErr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +67,11 @@ module.exports.validateSocket = async function(socket, quiet = false){
|
||||||
//socket.request.session is already trusted, we don't actually need to verify against DB for authorzation
|
//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
|
//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){
|
module.exports.authSocketLite = async function(socket){
|
||||||
const user = socket.request.session.user;
|
const user = socket.request.session.user;
|
||||||
|
|
||||||
|
if(user == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
//Set socket user and channel values
|
//Set socket user and channel values
|
||||||
socket.user = {
|
socket.user = {
|
||||||
|
|
@ -84,7 +88,7 @@ module.exports.authSocket = async function(socket){
|
||||||
const userDB = await userModel.findOne({user: socket.request.session.user.user});
|
const userDB = await userModel.findOne({user: socket.request.session.user.user});
|
||||||
|
|
||||||
if(userDB == null){
|
if(userDB == null){
|
||||||
throw loggerUtils.exceptionSmith("User not found!", "unauthorized");
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set socket user and channel values
|
//Set socket user and channel values
|
||||||
|
|
|
||||||
24
www/js/channel/pmHandler.js
Normal file
24
www/js/channel/pmHandler.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*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 <https://www.gnu.org/licenses/>.*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for handling incoming Private Messages
|
||||||
|
*/
|
||||||
|
class pmHandler{
|
||||||
|
constructor(client){
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue