Started work on site-wide toke command management & errorHandler

This commit is contained in:
rainbow napkin 2024-12-11 07:16:42 -05:00
parent d516fed309
commit af7f4219a5
12 changed files with 146 additions and 11 deletions

View file

@ -35,8 +35,7 @@ module.exports.post = async function(req, res){
//if we found any related nuked bans //if we found any related nuked bans
if(nukedBans != null){ if(nukedBans != null){
//Shit our pants! //Shit our pants!
res.status(401); return errorHandler(res, 'Cannon re-create banned account!', 'unauthorized');
return res.send({errors:[{msg:"Cannot re-create banned account!",type:"unauthorized"}]});
} }
await userModel.register(user) await userModel.register(user)

View file

@ -0,0 +1,64 @@
/*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 <https://www.gnu.org/licenses/>.*/
//npm imports
const {validationResult, matchedData} = require('express-validator');
//local imports
const {exceptionHandler, errorHandler} = require('../../../utils/loggerUtils.js');
const tokeCommandModel = require('../../../schemas/tokebot/tokeCommandSchema.js');
module.exports.get = async function(req, res){
try{
const tokeList = await tokeCommandModel.getCommandStrings();
res.status(200);
return res.send(tokeList);
}catch(err){
return exceptionHandler(res, err);
}
}
module.exports.post = async function(req, res){
try{
//get validation error results
const validResult = validationResult(req);
//if they're empty
if(validResult.isEmpty()){
const {command} = matchedData(req);
const foundToke = await tokeCommandModel.findOne({command});
if(foundToke != null){
return errorHandler(res, `Toke command '!${command}' already exists!`);
}
//Add the toke
const tokeDB = await tokeCommandModel.create({command});
//Return the updated command list
res.status(200);
return res.send(await tokeCommandModel.getCommandStrings());
}else{
//otherwise scream
res.status(400);
return res.send({errors: validResult.array()})
}
}catch(err){
return exceptionHandler(res, err);
}
}

View file

@ -18,7 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
const { Router } = require('express'); const { Router } = require('express');
//local imports //local imports
const {accountValidator} = require("../../validators/accountValidator"); const accountValidator = require("../../validators/accountValidator");
const loginController = require("../../controllers/api/account/loginController"); const loginController = require("../../controllers/api/account/loginController");
const logoutController = require("../../controllers/api/account/logoutController"); const logoutController = require("../../controllers/api/account/logoutController");
const registerController = require("../../controllers/api/account/registerController"); const registerController = require("../../controllers/api/account/registerController");

View file

@ -20,14 +20,16 @@ const { Router } = require('express');
//local imports //local imports
const {accountValidator} = require("../../validators/accountValidator"); const accountValidator = require("../../validators/accountValidator");
const {permissionsValidator, channelPermissionValidator} = require("../../validators/permissionsValidator"); const {permissionsValidator, channelPermissionValidator} = require("../../validators/permissionsValidator");
const tokebotValidator = require("../../validators/tokebotValidator");
const permissionSchema = require("../../schemas/permissionSchema"); const permissionSchema = require("../../schemas/permissionSchema");
const listUsersController = require("../../controllers/api/admin/listUsersController"); const listUsersController = require("../../controllers/api/admin/listUsersController");
const listChannelsController = require("../../controllers/api/admin/listChannelsController"); const listChannelsController = require("../../controllers/api/admin/listChannelsController");
const changeRankController = require("../../controllers/api/admin/changeRankController"); const changeRankController = require("../../controllers/api/admin/changeRankController");
const permissionsController = require("../../controllers/api/admin/permissionsController"); const permissionsController = require("../../controllers/api/admin/permissionsController");
const banController = require("../../controllers/api/admin/banController"); const banController = require("../../controllers/api/admin/banController");
const tokeCommandController = require('../../controllers/api/admin/tokeCommandController');
//globals //globals
const router = Router(); const router = Router();
@ -42,5 +44,7 @@ router.get('/ban', permissionSchema.reqPermCheck("adminPanel"), banController.g
//Sometimes they're so simple you don't need to put your validators in their own special place :P //Sometimes they're so simple you don't need to put your validators in their own special place :P
router.post('/ban', permissionSchema.reqPermCheck("banUser"), accountValidator.user(), body("permanent").isBoolean(), body("expirationDays").isInt(), banController.post); router.post('/ban', permissionSchema.reqPermCheck("banUser"), accountValidator.user(), body("permanent").isBoolean(), body("expirationDays").isInt(), banController.post);
router.delete('/ban', permissionSchema.reqPermCheck("banUser"), accountValidator.user(), banController.delete); router.delete('/ban', permissionSchema.reqPermCheck("banUser"), accountValidator.user(), banController.delete);
router.get('/tokeCommands', permissionSchema.reqPermCheck("adminPanel"), tokeCommandController.get);
router.post('/tokeCommands', permissionSchema.reqPermCheck("editTokeCommands"), tokebotValidator.command(), tokeCommandController.post);
module.exports = router; module.exports = router;

View file

@ -21,8 +21,8 @@ const { Router } = require('express');
//local imports //local imports
const permissionSchema = require("../../schemas/permissionSchema"); const permissionSchema = require("../../schemas/permissionSchema");
const channelModel = require("../../schemas/channel/channelSchema"); const channelModel = require("../../schemas/channel/channelSchema");
const {channelValidator} = require("../../validators/channelValidator"); const channelValidator = require("../../validators/channelValidator");
const {accountValidator} = require("../../validators/accountValidator"); const accountValidator = require("../../validators/accountValidator");
const {channelPermissionValidator} = require("../../validators/permissionsValidator"); const {channelPermissionValidator} = require("../../validators/permissionsValidator");
const registerController = require("../../controllers/api/channel/registerController"); const registerController = require("../../controllers/api/channel/registerController");
const listController = require("../../controllers/api/channel/listController"); const listController = require("../../controllers/api/channel/listController");

View file

@ -51,6 +51,12 @@ const permissionSchema = new mongoose.Schema({
default: "admin", default: "admin",
required: true required: true
}, },
editTokeCommands: {
type: mongoose.SchemaTypes.String,
enum: rankEnum,
default: "admin",
required: true
},
banUser: { banUser: {
type: mongoose.SchemaTypes.String, type: mongoose.SchemaTypes.String,
enum: rankEnum, enum: rankEnum,

View file

@ -15,10 +15,15 @@ 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/>.*/
//At some point this will be a bit more advanced, right now it's just a placeholder :P //At some point this will be a bit more advanced, right now it's just a placeholder :P
module.exports.errorHandler = function(res, msg, type = "Generic"){
res.status(400);
return res.send({errors: [{type, msg, date: new Date()}]});
}
module.exports.exceptionHandler = function(res, err){ module.exports.exceptionHandler = function(res, err){
//if not yell at the browser for fucking up, and tell it what it did wrong. //if not yell at the browser for fucking up, and tell it what it did wrong.
res.status(400); res.status(400);
return res.send({errors: [{type: "Caught Exception", msg: err.message, date: new Date()}]}); module.exports.errorHandler(res, err.message, "Caught Exception");
} }
module.exports.socketExceptionHandler = function(socket, err){ module.exports.socketExceptionHandler = function(socket, err){

View file

@ -20,13 +20,13 @@ const { check, body, checkSchema, checkExact} = require('express-validator');
//local imports //local imports
const {isRank} = require('./permissionsValidator'); const {isRank} = require('./permissionsValidator');
module.exports.accountValidator = { module.exports = {
user: (field = 'user') => body(field).escape().trim().isLength({min: 1, max: 22}), user: (field = 'user') => body(field).escape().trim().isLength({min: 1, max: 22}),
//Password security requirements may change over time, therefore we should only validate against strongPassword() when creating new accounts //Password security requirements may change over time, therefore we should only validate against strongPassword() when creating new accounts
//that way we don't break old ones upon change //that way we don't break old ones upon change
pass: (field = 'pass') => body(field).notEmpty().escape().trim(), pass: (field = 'pass') => body(field).notEmpty().escape().trim(),
securePass: (field) => module.exports.accountValidator.pass(field).isStrongPassword({minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1}), securePass: (field) => module.exports.pass(field).isStrongPassword({minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1}),
email: (field = 'email') => body(field).optional().isEmail().normalizeEmail(), email: (field = 'email') => body(field).optional().isEmail().normalizeEmail(),

View file

@ -18,9 +18,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
const { check, body, checkSchema, checkExact} = require('express-validator'); const { check, body, checkSchema, checkExact} = require('express-validator');
//local imports //local imports
const {accountValidator} = require('./accountValidator'); const accountValidator = require('./accountValidator');
module.exports.channelValidator = { module.exports = {
name: (field = 'name') => check(field).escape().trim().isLength({min: 1, max: 50}), name: (field = 'name') => check(field).escape().trim().isLength({min: 1, max: 50}),
description: (field = 'description') => body(field).escape().trim().isLength({min: 1, max: 1000}), description: (field = 'description') => body(field).escape().trim().isLength({min: 1, max: 1000}),

View file

@ -52,6 +52,12 @@ module.exports.permissionsValidator = {
options: module.exports.isRank options: module.exports.isRank
}, },
}, },
'permissionsMap.editTokeCommands': {
optional: true,
custom: {
options: module.exports.isRank
}
},
'permissionsMap.banUser': { 'permissionsMap.banUser': {
optional: true, optional: true,
custom: { custom: {

View file

@ -0,0 +1,22 @@
/*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 <https://www.gnu.org/licenses/>.*/
//NPM Imports
const { check } = require('express-validator');
module.exports = {
command: (field = 'command') => check(field).escape().trim().isAlphanumeric().isLength({min: 1, max: 30}),
}

View file

@ -169,6 +169,35 @@ class canopyAdminUtils{
utils.ux.displayResponseError(await response.json()); utils.ux.displayResponseError(await response.json());
} }
} }
async getTokeCommands(){
var response = await fetch(`/api/admin/tokeCommands`,{
method: "GET"
});
if(response.status == 200){
return await response.json();
}else{
utils.ux.displayResponseError(await response.json());
}
}
async addTokeCommand(command){
var response = await fetch(`/api/admin/tokeCommands`,{
method: "POST",
headers: {
"Content-Type": "application/json"
},
//Unfortunately JSON doesn't natively handle ES6 maps, and god forbid someone update the standard in a way that's backwards compatible...
body: JSON.stringify({command})
});
if(response.status == 200){
return await response.json();
}else{
utils.ux.displayResponseError(await response.json());
}
}
} }
class adminUserList{ class adminUserList{