From bd24aae3818c12aa3fea0b4d34c3f90ef19a24f6 Mon Sep 17 00:00:00 2001 From: rainbownapkin Date: Mon, 18 Nov 2024 08:18:02 -0500 Subject: [PATCH] Added '/api/admin/permissions' post & ajax helper --- .../api/admin/changeRankController.js | 2 +- .../api/admin/listChannelsController.js | 2 +- .../api/admin/listPermissionsController.js | 31 ------- .../api/admin/listUsersController.js | 2 +- .../api/admin/permissionsController.js | 85 +++++++++++++++++++ src/routers/api/adminRouter.js | 6 +- src/validators/accountValidator.js | 8 +- src/validators/permissionsValidator.js | 62 ++++++++++++++ www/js/adminPanel.js | 17 ++++ 9 files changed, 172 insertions(+), 43 deletions(-) delete mode 100644 src/controllers/api/admin/listPermissionsController.js create mode 100644 src/controllers/api/admin/permissionsController.js create mode 100644 src/validators/permissionsValidator.js diff --git a/src/controllers/api/admin/changeRankController.js b/src/controllers/api/admin/changeRankController.js index ce2130c..ca34ff8 100644 --- a/src/controllers/api/admin/changeRankController.js +++ b/src/controllers/api/admin/changeRankController.js @@ -22,7 +22,7 @@ const {exceptionHandler} = require('../../../utils/loggerUtils'); const permissionModel = require('../../../schemas/permissionSchema'); const userModel = require('../../../schemas/userSchema'); -//api account functions +//api change rank functions module.exports.post = async function(req, res){ try{ const validResult = validationResult(req); diff --git a/src/controllers/api/admin/listChannelsController.js b/src/controllers/api/admin/listChannelsController.js index 138a42d..ed3f943 100644 --- a/src/controllers/api/admin/listChannelsController.js +++ b/src/controllers/api/admin/listChannelsController.js @@ -18,7 +18,7 @@ along with this program. If not, see .*/ const {exceptionHandler} = require('../../../utils/loggerUtils.js'); const channelModel = require('../../../schemas/channelSchema.js'); -//api account functions +//api list channel functions module.exports.get = async function(req, res){ try{ const chanGuide = await channelModel.getChannelList(true); diff --git a/src/controllers/api/admin/listPermissionsController.js b/src/controllers/api/admin/listPermissionsController.js deleted file mode 100644 index c3ddd0e..0000000 --- a/src/controllers/api/admin/listPermissionsController.js +++ /dev/null @@ -1,31 +0,0 @@ -/*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 .*/ - -//local imports -const {exceptionHandler} = require('../../../utils/loggerUtils.js'); -const permissionModel = require('../../../schemas/permissionSchema.js'); - -//api account functions -module.exports.get = async function(req, res){ - try{ - const perms = await permissionModel.getPerms(); - - res.status(200); - return res.send(perms); - }catch(err){ - return exceptionHandler(res, err); - } -} \ No newline at end of file diff --git a/src/controllers/api/admin/listUsersController.js b/src/controllers/api/admin/listUsersController.js index 624a957..4f057e8 100644 --- a/src/controllers/api/admin/listUsersController.js +++ b/src/controllers/api/admin/listUsersController.js @@ -18,7 +18,7 @@ along with this program. If not, see .*/ const {exceptionHandler} = require('../../../utils/loggerUtils.js'); const userModel = require('../../../schemas/userSchema'); -//api account functions +//api list account functions module.exports.get = async function(req, res){ try{ const userList = await userModel.getUserList(true); diff --git a/src/controllers/api/admin/permissionsController.js b/src/controllers/api/admin/permissionsController.js new file mode 100644 index 0000000..d1c8399 --- /dev/null +++ b/src/controllers/api/admin/permissionsController.js @@ -0,0 +1,85 @@ +/*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 {exceptionHandler} = require('../../../utils/loggerUtils.js'); +const permissionModel = require('../../../schemas/permissionSchema.js'); + +//api permissions functions +module.exports.get = async function(req, res){ + try{ + const perms = await permissionModel.getPerms(); + + res.status(200); + return res.send(perms); + }catch(err){ + return exceptionHandler(res, err); + } +} + +module.exports.post = async function(req, res){ + try{ + //check for validation errors + const validResult = validationResult(req); + + //if none + if(validResult.isEmpty()){ + //grab validated/sanatized data + const {permissionsMap} = matchedData(req); + const perms = await permissionModel.getPerms(); + var permError = false; + + //For each permission submitted + Object.keys(permissionsMap).forEach((perm) => { + //Check to make sure no one is jumping perms (this should be admins only, but just in-case) + //Setting a boolean inside of an if statement seems fucked, until you realize it won't set it back false on the next loop :P + if(permissionModel.rankToNum(perms[perm]) > permissionModel.rankToNum(req.session.user.rank) || permissionModel.rankToNum(permissionsMap[perm]) > permissionModel.rankToNum(req.session.user.rank)){ + permError = true; + } + + //Set permissions in the permissions model + perms[perm] = permissionsMap[perm]; + }); + + //Flip our shit if something's wrong. + if(permError){ + res.status(401); + return res.send({errors:[{type: "Unauthorized", msg: "New rank must be equal to or below that of the user changing it.", date: new Date()}]}); + } + + await perms.save(); + + //Cleanup return object + var returnObj = perms.toObject(); + + delete returnObj._id + delete returnObj.__v + + //send successful response + res.status(200); + return res.send(returnObj); + //otherwise scream + }else{ + res.status(400); + res.send({errors: validResult.array()}) + } + }catch(err){ + return exceptionHandler(res, err); + } +} \ No newline at end of file diff --git a/src/routers/api/adminRouter.js b/src/routers/api/adminRouter.js index 3af1d11..564e131 100644 --- a/src/routers/api/adminRouter.js +++ b/src/routers/api/adminRouter.js @@ -20,11 +20,12 @@ const { Router } = require('express'); //local imports const accountValidator = require("../../validators/accountValidator"); +const {permissionsValidator} = require("../../validators/permissionsValidator"); const permissionSchema = require("../../schemas/permissionSchema"); const listUsersController = require("../../controllers/api/admin/listUsersController"); const listChannelsController = require("../../controllers/api/admin/listChannelsController"); const changeRankController = require("../../controllers/api/admin/changeRankController"); -const listPermissionsController = require("../../controllers/api/admin/listPermissionsController"); +const permissionsController = require("../../controllers/api/admin/permissionsController"); //globals const router = Router(); @@ -35,7 +36,8 @@ router.use(permissionSchema.reqPermCheck("adminAPI")); //routing functions router.get('/listUsers', listUsersController.get); router.get('/listChannels', listChannelsController.get); -router.get('/listPermissions', listPermissionsController.get); +router.get('/permissions', permissionsController.get); +router.post('/permissions', permissionsValidator.permissionsMap(), permissionsController.post); router.post('/changeRank', accountValidator.user(), accountValidator.rank(), changeRankController.post); module.exports = router; diff --git a/src/validators/accountValidator.js b/src/validators/accountValidator.js index 063d895..d875abd 100644 --- a/src/validators/accountValidator.js +++ b/src/validators/accountValidator.js @@ -18,13 +18,7 @@ along with this program. If not, see .*/ const { check, body, checkSchema, checkExact} = require('express-validator'); //local imports -const permissionSchema = require("../schemas/permissionSchema"); - -function isRank(value){ - rankVal = permissionSchema.rankToNum(value); - - return rankVal != -1; -} +const {isRank} = require('./permissionsValidator'); module.exports = { user: (field = 'user') => body(field).escape().trim().isLength({min: 1, max: 22}), diff --git a/src/validators/permissionsValidator.js b/src/validators/permissionsValidator.js new file mode 100644 index 0000000..738fa3b --- /dev/null +++ b/src/validators/permissionsValidator.js @@ -0,0 +1,62 @@ +/*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 { check, body, checkSchema, checkExact} = require('express-validator'); + +//local imports +const permissionSchema = require("../schemas/permissionSchema"); + +module.exports.isRank = function(value){ + rankVal = permissionSchema.rankToNum(value); + + return rankVal != -1; +} + +module.exports.permissionsValidator = { + permissionsMap: () => checkExact(checkSchema({ + 'permissionsMap.adminPanel': { + optional: true, + custom: { + options: module.exports.isRank + }, + }, + 'permissionsMap.adminAPI': { + optional: true, + custom: { + options: module.exports.isRank + }, + }, + 'permissionsMap.registerChannel': { + optional: true, + custom: { + options: module.exports.isRank + }, + }, + 'permissionsMap.manageChannel': { + optional: true, + custom: { + options: module.exports.isRank + }, + }, + 'permissionsMap.deleteChannel': { + optional: true, + custom: { + options: module.exports.isRank + }, + } + })) +} \ No newline at end of file diff --git a/www/js/adminPanel.js b/www/js/adminPanel.js index f7fe6e4..2813ccf 100644 --- a/www/js/adminPanel.js +++ b/www/js/adminPanel.js @@ -35,6 +35,23 @@ class canopyAdminUtils{ utils.ux.displayResponseError(await response.json()); } } + + async setPermission(permObj){ + var response = await fetch(`/api/admin/permissions`,{ + 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({permissionsMap: Object.fromEntries(permObj)}) + }); + + if(response.status == 200){ + return await response.json(); + }else{ + utils.ux.displayResponseError(await response.json()); + } + } } class adminUserList{