diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js index 894cc4c..8e03b87 100644 --- a/src/app/channel/channelManager.js +++ b/src/app/channel/channelManager.js @@ -46,6 +46,19 @@ module.exports = class{ //Get the active channel based on the socket var {activeChan, chanDB} = await this.getActiveChan(socket); + //Check for ban + const ban = await chanDB.checkBanByUserDoc(userDB); + if(ban != null){ + //Toss out banned user's + if(ban.expirationDays < 0){ + socket.emit("kick", {type: "Unauthorized", reason: "You have been permanently banned from this channel!"}); + }else{ + socket.emit("kick", {type: "Unauthorized", reason: `You have been temporarily banned from this channel, and will be unbanned in ${ban.getDaysUntilExpiration()} day(s)!`}); + } + socket.disconnect(); + return; + } + //Define listeners this.defineListeners(socket); this.chatHandler.defineListeners(socket); diff --git a/src/controllers/popup/channelUserBanController.js b/src/controllers/popup/channelUserBanController.js new file mode 100644 index 0000000..20b7ae1 --- /dev/null +++ b/src/controllers/popup/channelUserBanController.js @@ -0,0 +1,20 @@ +/*Canopy - The next generation of stoner streaming software +Copyright (C) 2024 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 .*/ + +//root index functions +module.exports.get = async function(req, res){ + res.render('partial/popup/channelUserBan'); +} \ No newline at end of file diff --git a/src/routers/popupRouter.js b/src/routers/popupRouter.js index 5d92616..a0efa78 100644 --- a/src/routers/popupRouter.js +++ b/src/routers/popupRouter.js @@ -21,6 +21,7 @@ const { Router } = require('express'); //local imports const placeholderController = require("../controllers/popup/placeholderController"); const userBanController = require("../controllers/popup/userBanController"); +const channelUserBanController = require("../controllers/popup/channelUserBanController"); //globals const router = Router(); @@ -28,5 +29,6 @@ const router = Router(); //routing functions router.get('/placeholder', placeholderController.get); router.get('/userBan', userBanController.get); +router.get('/channelUserBan', channelUserBanController.get); module.exports = router; diff --git a/src/schemas/channel/channelBanSchema.js b/src/schemas/channel/channelBanSchema.js new file mode 100644 index 0000000..bb5ab70 --- /dev/null +++ b/src/schemas/channel/channelBanSchema.js @@ -0,0 +1,53 @@ +/*Canopy - The next generation of stoner streaming software +Copyright (C) 2024 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 .*/ + +//NPM Imports +const {mongoose} = require('mongoose'); + +const channelBanSchema = new mongoose.Schema({ + user: { + type: mongoose.SchemaTypes.ObjectID, + required: true, + ref: "user" + }, + banDate: { + type: mongoose.SchemaTypes.Date, + required: true, + default: new Date() + }, + expirationDays: { + type: mongoose.SchemaTypes.Number, + required: true, + default: 14 + }, + banAlts: { + type: mongoose.SchemaTypes.Boolean, + required: true, + default: false + } +}); + +//methods +channelBanSchema.methods.getDaysUntilExpiration = function(){ + //Get ban date + const expirationDate = new Date(this.banDate); + //Get expiration days and calculate expiration date + expirationDate.setDate(expirationDate.getDate() + this.expirationDays); + //Calculate and return days until ban expiration + return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1); +} + +module.exports = channelBanSchema; \ No newline at end of file diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index 2d35ac0..7b2f281 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -19,11 +19,12 @@ const {mongoose} = require('mongoose'); const {validationResult, matchedData} = require('express-validator'); //Local Imports -const statModel = require('../statSchema.js'); -const {userModel} = require('../userSchema.js'); -const permissionModel = require('../permissionSchema.js'); -const channelPermissionSchema = require('./channelPermissionSchema.js'); -const { exceptionHandler } = require('../../utils/loggerUtils.js'); +const statModel = require('../statSchema'); +const {userModel} = require('../userSchema'); +const permissionModel = require('../permissionSchema'); +const channelPermissionSchema = require('./channelPermissionSchema'); +const channelBanSchema = require('./channelBanSchema'); +const { exceptionHandler } = require('../../utils/loggerUtils'); const channelSchema = new mongoose.Schema({ id: { @@ -69,28 +70,7 @@ const channelSchema = new mongoose.Schema({ } }], //Thankfully we don't have to keep track of alts, ips, or deleted users so this should be a little easier :P - banList: [{ - user: { - type: mongoose.SchemaTypes.ObjectID, - required: true, - ref: "user" - }, - banDate: { - type: mongoose.SchemaTypes.Date, - required: true, - default: new Date() - }, - expirationDays: { - type: mongoose.SchemaTypes.Number, - required: true, - default: 14 - }, - banAlts: { - type: mongoose.SchemaTypes.Boolean, - required: true, - default: false - } - }] + banList: [channelBanSchema] }); @@ -194,6 +174,21 @@ channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){ } } +channelSchema.statics.processExpiredBans = async function(){ + const chanDB = await this.find({}); + + chanDB.forEach((channel) => { + channel.banList.forEach(async (ban, i) => { + //ignore permanent and non-expired bans + if(ban.expirationDays >= 0 && ban.getDaysUntilExpiration() <= 0){ + //Get the index of the ban + channel.banList.splice(i,1); + return await channel.save(); + } + }) + }); +} + //methods channelSchema.methods.updateSettings = async function(settingsMap){ settingsMap.forEach((value, key) => { @@ -372,6 +367,7 @@ channelSchema.methods.getChanBans = async function(){ var banObj = { banDate: ban.banDate, expirationDays: ban.expirationDays, + banAlts: ban.banAlts, } //Check if the ban was permanent (expiration set before ban date) @@ -382,6 +378,7 @@ channelSchema.methods.getChanBans = async function(){ //Set calculated expiration date banObj.expirationDate = expirationDate; + banObj.daysUntilExpiration = ban.getDaysUntilExpiration(); } //Setup user object (Do this last to keep it at bottom for human-readibility of json :P) diff --git a/src/schemas/userBanSchema.js b/src/schemas/userBanSchema.js index df0fb04..5e8ea80 100644 --- a/src/schemas/userBanSchema.js +++ b/src/schemas/userBanSchema.js @@ -196,6 +196,7 @@ userBanSchema.statics.getBans = async function(){ banDate: ban.banDate, expirationDays: ban.expirationDays, expirationDate: expirationDate, + daysUntilExpiration: ban.getDaysUntilExpiration(), user: userObj, ips: ban.ips, alts: ban.alts, @@ -247,7 +248,7 @@ userBanSchema.methods.getDaysUntilExpiration = function(){ //Get expiration days and calculate expiration date expirationDate.setDate(expirationDate.getDate() + this.expirationDays); //Calculate and return days until ban expiration - return daysUntilExpiraiton = ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1); + return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1); } module.exports = mongoose.model("userBan", userBanSchema); \ No newline at end of file diff --git a/src/utils/scheduler.js b/src/utils/scheduler.js index 8a5d881..840ee14 100644 --- a/src/utils/scheduler.js +++ b/src/utils/scheduler.js @@ -18,9 +18,20 @@ along with this program. If not, see .*/ const cron = require('node-cron'); //Local Imports -const userBanSchema = require('../schemas/userBanSchema'); +const userBanModel = require('../schemas/userBanSchema'); +const channelModel = require('../schemas/channel/channelSchema'); + +module.exports.schedule = function(){ + //Process expired global bans every night at midnight + cron.schedule('0 0 * * *', ()=>{userBanModel.processExpiredBans()},{scheduled: true, timezone: "UTC"}); +} module.exports.kickoff = function(){ - //Process expired bans every night at midnight - cron.schedule('0 0 * * *', ()=>{userBanSchema.processExpiredBans()},{scheduled: true, timezone: "UTC"}); + //Process expired global bans that may have expired since last restart + userBanModel.processExpiredBans() + //Process expired channel bans that may haven ot expired since last restart + channelModel.processExpiredBans(); + + //Schedule jobs + module.exports.schedule(); } \ No newline at end of file diff --git a/src/views/adminPanel.ejs b/src/views/adminPanel.ejs index 7c4aa62..f338d09 100644 --- a/src/views/adminPanel.ejs +++ b/src/views/adminPanel.ejs @@ -23,10 +23,12 @@ along with this program. If not, see .--> <%- include('partial/navbar', {user}); %>

<%= instance %> Admin Panel

- <%- include('partial/adminPanel/channelList', {chanGuide}) %> - <%- include('partial/adminPanel/userList', {user, userList, rankEnum}) %> - <%- include('partial/adminPanel/permList', {permList, rankEnum}) %> - <%- include('partial/adminPanel/userBanList') %> +
+ <%- include('partial/adminPanel/channelList', {chanGuide}) %> + <%- include('partial/adminPanel/userList', {user, userList, rankEnum}) %> + <%- include('partial/adminPanel/permList', {permList, rankEnum}) %> + <%- include('partial/adminPanel/userBanList') %> +