diff --git a/src/app/channel/channelManager.js b/src/app/channel/channelManager.js index cddc5dd..894cc4c 100644 --- a/src/app/channel/channelManager.js +++ b/src/app/channel/channelManager.js @@ -16,7 +16,7 @@ along with this program. If not, see .*/ //Local Imports const channelModel = require('../../schemas/channel/channelSchema'); -const userModel = require('../../schemas/userSchema'); +const {userModel} = require('../../schemas/userSchema'); const loggerUtils = require('../../utils/loggerUtils'); const activeChannel = require('./activeChannel'); const chatHandler = require('./chatHandler'); diff --git a/src/app/channel/chatHandler.js b/src/app/channel/chatHandler.js index c6c2955..64bbb21 100644 --- a/src/app/channel/chatHandler.js +++ b/src/app/channel/chatHandler.js @@ -19,7 +19,7 @@ const validator = require('validator');//No express here, so regular validator i //local imports const loggerUtils = require('../../utils/loggerUtils'); -const userModel = require('../../schemas/userSchema'); +const {userModel} = require('../../schemas/userSchema'); module.exports = class{ constructor(server){ diff --git a/src/controllers/adminPanelController.js b/src/controllers/adminPanelController.js index 098f62f..42ba146 100644 --- a/src/controllers/adminPanelController.js +++ b/src/controllers/adminPanelController.js @@ -16,7 +16,7 @@ along with this program. If not, see .*/ //Config const config = require('../../config.json'); -const userModel = require('../schemas/userSchema'); +const {userModel} = require('../schemas/userSchema'); const permissionModel = require('../schemas/permissionSchema'); const channelModel = require('../schemas/channel/channelSchema'); const {exceptionHandler} = require("../utils/loggerUtils"); diff --git a/src/controllers/api/account/deleteController.js b/src/controllers/api/account/deleteController.js index a930b4d..45ed2c7 100644 --- a/src/controllers/api/account/deleteController.js +++ b/src/controllers/api/account/deleteController.js @@ -18,7 +18,7 @@ along with this program. If not, see .*/ const {validationResult, matchedData} = require('express-validator'); //local imports -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); const accountUtils = require('../../../utils/sessionUtils.js'); const {exceptionHandler} = require('../../../utils/loggerUtils.js'); diff --git a/src/controllers/api/account/registerController.js b/src/controllers/api/account/registerController.js index e294dc4..ee07654 100644 --- a/src/controllers/api/account/registerController.js +++ b/src/controllers/api/account/registerController.js @@ -18,7 +18,7 @@ along with this program. If not, see .*/ const {validationResult, matchedData} = require('express-validator'); //local imports -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); const {exceptionHandler} = require('../../../utils/loggerUtils.js'); module.exports.post = async function(req, res){ diff --git a/src/controllers/api/account/updateController.js b/src/controllers/api/account/updateController.js index 8cc5d3b..50ffd0e 100644 --- a/src/controllers/api/account/updateController.js +++ b/src/controllers/api/account/updateController.js @@ -18,7 +18,7 @@ along with this program. If not, see .*/ const {validationResult, matchedData} = require('express-validator'); //local imports -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); const accountUtils = require('../../../utils/sessionUtils.js'); const {exceptionHandler} = require('../../../utils/loggerUtils.js'); diff --git a/src/controllers/api/admin/banController.js b/src/controllers/api/admin/banController.js new file mode 100644 index 0000000..63fc1a2 --- /dev/null +++ b/src/controllers/api/admin/banController.js @@ -0,0 +1,59 @@ +/*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 {validationResult, matchedData} = require('express-validator'); + +//local imports +const banModel = require('../../../schemas/userBanSchema'); +const {userModel} = require('../../../schemas/userSchema'); +const {exceptionHandler} = require('../../../utils/loggerUtils'); + +module.exports.get = async function(req, res){ + try{ + //get bans + const bans = await banModel.getBans(); + + //send bans + res.status(200); + return res.send(bans); + }catch(err){ + return exceptionHandler(res, err); + } +} + +module.exports.post = async function(req, res){ + try{ + const validResult = validationResult(req); + if(validResult.isEmpty()){ + const {user} = matchedData(req); + const userDB = await userModel.findOne({user}); + + if(userDB == null){ + res.status(400); + res.send({errors:[{type: "Bad Query", msg: "User not found.", date: new Date()}]}); + } + + await banModel.banByUserDoc(userDB); + + }else{ + res.status(400); + return res.send({errors: validResult.array()}) + } + }catch(err){ + return exceptionHandler(res, err); + } +} \ No newline at end of file diff --git a/src/controllers/api/admin/changeRankController.js b/src/controllers/api/admin/changeRankController.js index 2ba0ea8..d509be1 100644 --- a/src/controllers/api/admin/changeRankController.js +++ b/src/controllers/api/admin/changeRankController.js @@ -20,7 +20,7 @@ const {validationResult, matchedData} = require('express-validator'); //local imports const {exceptionHandler} = require('../../../utils/loggerUtils'); const permissionModel = require('../../../schemas/permissionSchema'); -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); //api change rank functions module.exports.post = async function(req, res){ diff --git a/src/controllers/api/admin/listUsersController.js b/src/controllers/api/admin/listUsersController.js index 4f057e8..217c3ef 100644 --- a/src/controllers/api/admin/listUsersController.js +++ b/src/controllers/api/admin/listUsersController.js @@ -16,7 +16,7 @@ along with this program. If not, see .*/ //local imports const {exceptionHandler} = require('../../../utils/loggerUtils.js'); -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); //api list account functions module.exports.get = async function(req, res){ diff --git a/src/controllers/api/channel/rankController.js b/src/controllers/api/channel/rankController.js index e779c7a..5f9eb9c 100644 --- a/src/controllers/api/channel/rankController.js +++ b/src/controllers/api/channel/rankController.js @@ -20,7 +20,7 @@ const {validationResult, matchedData} = require('express-validator'); //local imports const {exceptionHandler} = require('../../../utils/loggerUtils'); const permissionModel = require('../../../schemas/permissionSchema'); -const userModel = require('../../../schemas/userSchema'); +const {userModel} = require('../../../schemas/userSchema'); const channelModel = require('../../../schemas/channel/channelSchema'); //api channel rank functions diff --git a/src/controllers/api/channel/registerController.js b/src/controllers/api/channel/registerController.js index 1a2a390..d299e09 100644 --- a/src/controllers/api/channel/registerController.js +++ b/src/controllers/api/channel/registerController.js @@ -19,7 +19,7 @@ const {validationResult, matchedData} = require('express-validator'); //local imports const {exceptionHandler} = require('../../../utils/loggerUtils.js'); -const userModel = require('../../../schemas/userSchema.js'); +const {userModel} = require('../../../schemas/userSchema.js'); const channelModel = require('../../../schemas/channel/channelSchema'); //api account functions diff --git a/src/controllers/profileController.js b/src/controllers/profileController.js index c6248c6..322891e 100644 --- a/src/controllers/profileController.js +++ b/src/controllers/profileController.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ //Local Imports -const userModel = require('../schemas/userSchema'); +const {userModel} = require('../schemas/userSchema'); const {exceptionHandler} = require('../utils/loggerUtils.js'); //Config diff --git a/src/routers/api/adminRouter.js b/src/routers/api/adminRouter.js index 771c582..aa96d7a 100644 --- a/src/routers/api/adminRouter.js +++ b/src/routers/api/adminRouter.js @@ -27,6 +27,7 @@ const listUsersController = require("../../controllers/api/admin/listUsersContro const listChannelsController = require("../../controllers/api/admin/listChannelsController"); const changeRankController = require("../../controllers/api/admin/changeRankController"); const permissionsController = require("../../controllers/api/admin/permissionsController"); +const banController = require("../../controllers/api/admin/banController"); //globals const router = Router(); @@ -40,5 +41,7 @@ router.get('/listChannels', listChannelsController.get); router.get('/permissions', permissionsController.get); router.post('/permissions', checkExact([permissionsValidator.permissionsMap(), channelPermissionValidator.channelPermissionsMap()]), permissionsController.post); router.post('/changeRank', accountValidator.user(), accountValidator.rank(), changeRankController.post); +router.get('/ban', banController.get); +router.post('/ban', accountValidator.user(), banController.post); module.exports = router; diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index 9dcb4b4..089b441 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -20,7 +20,7 @@ const {validationResult, matchedData} = require('express-validator'); //Local Imports const statModel = require('../statSchema.js'); -const userModel = require('../userSchema.js'); +const {userModel} = require('../userSchema.js'); const permissionModel = require('../permissionSchema.js'); const channelPermissionSchema = require('./channelPermissionSchema.js'); const { exceptionHandler } = require('../../utils/loggerUtils.js'); diff --git a/src/schemas/userBanSchema.js b/src/schemas/userBanSchema.js new file mode 100644 index 0000000..0068f95 --- /dev/null +++ b/src/schemas/userBanSchema.js @@ -0,0 +1,121 @@ +/*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'); + +//Local Imports +const {userSchema} = require('./userSchema'); + +const userBanSchema = new mongoose.Schema({ + user: { + type: mongoose.SchemaTypes.ObjectID, + required: true, + ref: "user" + }, + //To be used in future when ip-hashing/better session tracking is implemented + ips: { + type: [mongoose.SchemaTypes.String], + required: false + }, + //To be used in future when alt-detection has been implemented + alts: { + type: [userSchema], + required: false + }, + banDate: { + + type: mongoose.SchemaTypes.Date, + required: true, + default: new Date() + }, + expirationDays: { + type: mongoose.SchemaTypes.Number, + required: true, + default: 30 + }, + //If true, then expiration date deletes associated accounts instead of deleting the ban record + deleteAccountOnExpire: { + type: mongoose.SchemaTypes.Boolean, + required: true, + default: false + } +}); + +userBanSchema.statics.checkBanByUserDoc = async function(userDB){ + const banDB = await this.find({}); + var foundBan = null; + + banDB.forEach((ban) => { + if(ban.user.toString() == userDB._id.toString()){ + foundBan = ban; + } + }); + + return foundBan; +} + +userBanSchema.statics.checkBan = async function(user){ + const userDB = await userModel.findOne({user: user.user}); + return this.checkBanByUserDoc(userDB); +} + +userBanSchema.statics.banByUserDoc = async function(userDB){ + if(await this.checkBanByUserDoc(userDB) != null){ + throw new Error("User already banned"); + } + + return await this.create({user: userDB._id}); +} + +userBanSchema.statics.ban = async function(user){ + const userDB = await userModel.findOne({user: user.user}); + return this.banByUserDoc(userDB); +} + +userBanSchema.statics.getBans = async function(){ + const banDB = await this.find({}).populate('user'); + var bans = []; + + banDB.forEach((ban) => { + //Calcualte expiration date + var expirationDate = new Date(ban.banDate); + expirationDate.setDate(expirationDate.getDate() + ban.expirationDays); + + const userObj = { + id: ban.user.id, + user: ban.user.user, + img: ban.user.img, + date: ban.user.date + } + + const banObj = { + banDate: ban.banDate, + expirationDays: ban.expirationDays, + expirationDate: expirationDate, + user: userObj, + ips: ban.ips, + alts: ban.alts, + deleteAccountOnExpire: ban.deleteAccountOnExpire + } + + bans.push(banObj); + }); + + return bans; +} + +module.exports = mongoose.model("userBan", userBanSchema); \ No newline at end of file diff --git a/src/schemas/userSchema.js b/src/schemas/userSchema.js index ebd5b7e..c18c578 100644 --- a/src/schemas/userSchema.js +++ b/src/schemas/userSchema.js @@ -282,4 +282,5 @@ userSchema.methods.nuke = async function(pass){ } } -module.exports = mongoose.model("user", userSchema); \ No newline at end of file +module.exports.userSchema = userSchema; +module.exports.userModel = mongoose.model("user", userSchema); \ No newline at end of file diff --git a/src/utils/sessionUtils.js b/src/utils/sessionUtils.js index ec3fe87..cc2f0f1 100644 --- a/src/utils/sessionUtils.js +++ b/src/utils/sessionUtils.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ //local imports -const userModel = require('../schemas/userSchema.js'); +const {userModel} = require('../schemas/userSchema.js'); //this module is good for keeping wrappers for userModel and other shit in that does more session handling than database access/modification. diff --git a/src/views/adminPanel.ejs b/src/views/adminPanel.ejs index f53f4d0..7c4aa62 100644 --- a/src/views/adminPanel.ejs +++ b/src/views/adminPanel.ejs @@ -26,6 +26,7 @@ along with this program. If not, see .--> <%- include('partial/adminPanel/channelList', {chanGuide}) %> <%- include('partial/adminPanel/userList', {user, userList, rankEnum}) %> <%- include('partial/adminPanel/permList', {permList, rankEnum}) %> + <%- include('partial/adminPanel/userBanList') %>