diff --git a/config.example.json b/config.example.json index 58445d8..6e7519f 100644 --- a/config.example.json +++ b/config.example.json @@ -8,6 +8,7 @@ "ytdlpPath": "/home/canopy/.local/pipx/venvs/yt-dlp/bin/yt-dlp", "migrate": false, "dropLegacyTokes": false, + "debug": false, "secrets":{ "passwordSecret": "CHANGE_ME", "rememberMeSecret": "CHANGE_ME", diff --git a/config.example.jsonc b/config.example.jsonc index 3f1bd0a..75d4591 100644 --- a/config.example.jsonc +++ b/config.example.jsonc @@ -24,6 +24,11 @@ //Requires migration to be disabled before it takes effect. //WARNING: this does NOT affect user toke counts, migrated or otherwise. Use carefully! "dropLegacyTokes": false, + //Enters the server into debug mode, allows specific commands to be emitted from the client-side dev console + //Usually to get the server to dump some sort of internal data for debugging purposes. + //Obviously, this means enabling this can have some gnar implications. + //Probably don't enable this on your production server unless you REALLY REALLY have to, and you probably don't. + "debug": false, //Server Secrets //Be careful with what you keep in secrets, you should use special chars, but test your deployment, as some chars may break account registration //An update to either kill the server and bitch about the issue in console is planned so it's not so confusing for new admins diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js index 8284420..8fa933f 100644 --- a/src/app/channel/media/queue.js +++ b/src/app/channel/media/queue.js @@ -18,10 +18,12 @@ along with this program. If not, see .*/ const validator = require('validator'); //Local imports +const config = require('../../../../config.json'); const queuedMedia = require('./queuedMedia'); const yanker = require('../../../utils/media/yanker'); const loggerUtils = require('../../../utils/loggerUtils'); const channelModel = require('../../../schemas/channel/channelSchema'); +const permissionModel = require('../../../schemas/permissionSchema'); /** * Object represneting a single channel's media queue @@ -114,6 +116,11 @@ class queue{ socket.on("move", (data) => {this.moveMedia(socket, data)}); socket.on("lock", () => {this.toggleLock(socket)}); socket.on("goLive", (data) => {this.goLive(socket, data)}); + + //If debug mode is enabled + if(config.debug){ + socket.on("dumpQueue", (data) => {this.dumpQueue(socket, data)}); + } } //--- USER FACING QUEUEING FUNCTIONS --- @@ -404,6 +411,44 @@ class queue{ } } + async dumpQueue(socket, data){ + //If we somehow got here while config.debug is disabled, or the user isn't allowed to preform server-side debugging + if(!(config.debug && await permissionModel.permCheck(socket.user, "debug"))){ + //FUCKIN' CHEESE IT! + return; + } + + //If a full data dump was requested + if(data != null && data.full){ + //Pull the channel DB doc + const chanDB = await channelModel.findOne({name:this.channel.name}); + + //Cook and emit a new object from all of the data + socket.emit("dumpQueue", { + cache: { + schedule: Array.from(this.schedule), + nowPlaying: this.nowPlaying + }, + DB: { + schedule: chanDB.media.scheduled, + nowPlaying: chanDB.media.nowPlaying, + archived: chanDB.media.archived, + } + }); + + //DONE. + return; + } + + //Otherwise, just dump whats in RAM + socket.emit("dumpQueue", { + cache: { + schedule: Array.from(this.schedule), + nowPlaying: this.nowPlaying + } + }); + } + //--- INTERNAL USE ONLY QUEUEING FUNCTIONS --- /** * Clears and scheduling timers @@ -1788,7 +1833,9 @@ class queue{ chanDB.media.scheduled = newSched; //Save the DB - await chanDB.save(); + await chanDB.save() + + //End the media; //if something fucked up }catch(err){ diff --git a/src/schemas/permissionSchema.js b/src/schemas/permissionSchema.js index 108c888..322e8e2 100644 --- a/src/schemas/permissionSchema.js +++ b/src/schemas/permissionSchema.js @@ -100,6 +100,12 @@ const permissionSchema = new mongoose.Schema({ type: channelPermissionSchema, default: () => ({}) }, + debug: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, }); //Statics diff --git a/src/server.js b/src/server.js index da30147..50dcda0 100644 --- a/src/server.js +++ b/src/server.js @@ -78,9 +78,6 @@ const config = require('../config.json'); const port = config.port; const dbUrl = `mongodb://${config.db.user}:${config.db.pass}@${config.db.address}:${config.db.port}/${config.db.database}`; -//Check for insecure config -configCheck.securityCheck(); - //Define express const app = express(); @@ -234,6 +231,9 @@ async function asyncKickStart(){ //Kick off scheduled-jobs scheduler.kickoff(); + //Check for insecure config + configCheck.securityCheck(); + //Increment launch counter await statModel.incrementLaunchCount(); diff --git a/src/utils/configCheck.js b/src/utils/configCheck.js index d979b32..411c8b8 100644 --- a/src/utils/configCheck.js +++ b/src/utils/configCheck.js @@ -74,4 +74,9 @@ module.exports.securityCheck = function(){ if(!validator.isStrongPassword(config.mail.pass) || config.mail.pass == "CHANGE_ME"){ loggerUtil.consoleWarn("Insecure Email Password! Change Email password!"); } + + //check debug mode + if(config.debug){ + loggerUtil.consoleWarn("Debug mode enabled! Understand the risks and security implications before enabling on production servers!"); + } } \ No newline at end of file