From cde60bb78d2225a7efbb3a1644f19675cc7d2fa2 Mon Sep 17 00:00:00 2001 From: rainbownapkin Date: Sun, 17 Nov 2024 07:45:58 -0500 Subject: [PATCH] Added DB Document for perms, and auth middleware --- src/routers/adminPanelRouter.js | 4 ++ src/routers/api/channelRouter.js | 6 ++ src/routers/channelRouter.js | 4 ++ src/routers/newChannelRouter.js | 4 ++ src/schemas/permissionSchema.js | 108 +++++++++++++++++++++++++++++++ src/schemas/userSchema.js | 3 +- 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/schemas/permissionSchema.js diff --git a/src/routers/adminPanelRouter.js b/src/routers/adminPanelRouter.js index 76152e0..fd46224 100644 --- a/src/routers/adminPanelRouter.js +++ b/src/routers/adminPanelRouter.js @@ -19,11 +19,15 @@ const { Router } = require('express'); //local imports +const permissionSchema = require("../schemas/permissionSchema"); const adminPanelController = require("../controllers/adminPanelController"); //globals const router = Router(); +//Use authentication middleware +router.use(permissionSchema.reqPermCheck("adminPanel")) + //routing functions router.get('/', adminPanelController.get); diff --git a/src/routers/api/channelRouter.js b/src/routers/api/channelRouter.js index 8125308..5562b66 100644 --- a/src/routers/api/channelRouter.js +++ b/src/routers/api/channelRouter.js @@ -18,6 +18,7 @@ along with this program. If not, see .*/ const { Router } = require('express'); //local imports +const permissionSchema = require("../../schemas/permissionSchema"); const {channelValidator} = require("../../utils/validators"); const registerController = require("../../controllers/api/channel/registerController"); const listController = require("../../controllers/api/channel/listController"); @@ -27,6 +28,11 @@ const deleteController = require("../../controllers/api/channel/deleteController //globals const router = Router(); +//user authentication middleware +router.use("/register",permissionSchema.reqPermCheck("registerChannel")); +router.use("/delete",permissionSchema.reqPermCheck("deleteChannel")); +router.use("/settings",permissionSchema.reqPermCheck("manageChannel")); + //routing functions router.post('/register', channelValidator.name(), channelValidator.description(), channelValidator.thumbnail(), registerController.post); router.get('/list', listController.get); diff --git a/src/routers/channelRouter.js b/src/routers/channelRouter.js index ce5cb78..223559d 100644 --- a/src/routers/channelRouter.js +++ b/src/routers/channelRouter.js @@ -19,12 +19,16 @@ const { Router } = require('express'); //local imports +const permissionSchema = require("../schemas/permissionSchema"); const channelController = require("../controllers/channelController"); const channelSettingsController = require("../controllers/channelSettingsController"); //globals const router = Router(); +//User authentication middleware +router.use("/*/settings",permissionSchema.reqPermCheck("manageChannel")); + //routing functions router.get('/*/settings', channelSettingsController.get); router.get('/*/', channelController.get); diff --git a/src/routers/newChannelRouter.js b/src/routers/newChannelRouter.js index 7533756..48fb02e 100644 --- a/src/routers/newChannelRouter.js +++ b/src/routers/newChannelRouter.js @@ -19,11 +19,15 @@ const { Router } = require('express'); //local imports +const permissionSchema = require("../schemas/permissionSchema"); const newChannelController = require("../controllers/newChannelController"); //globals const router = Router(); +//user authentication middleware +router.use("/",permissionSchema.reqPermCheck("registerChannel")); + //routing functions router.get('/', newChannelController.get); diff --git a/src/schemas/permissionSchema.js b/src/schemas/permissionSchema.js new file mode 100644 index 0000000..ba2e384 --- /dev/null +++ b/src/schemas/permissionSchema.js @@ -0,0 +1,108 @@ +/*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 rankEnum = ["anon","user", "gold", "bot", "mod", "admin"]; + +const permissionSchema = new mongoose.Schema({ + adminPanel: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, + registerChannel: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, + manageChannel: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, + deleteChannel: { + type: mongoose.SchemaTypes.String, + enum: rankEnum, + default: "admin", + required: true + }, +}); + +//Statics +permissionSchema.statics.rankEnum = rankEnum; + +permissionSchema.statics.getPerms = async function(){ + //Not sure why 'this' didn't work from here when calling this, I'm assuming it's because I'm doing it from middleware + //which is probably binding shit to this function, either way this works :P + + //Get the first document we find + var perms = await module.exports.findOne({}); + + if(perms){ + //If we found something then the permissions document exist and this is it, + //So long as no one else has fucked with the database it should be the only one. (is this forshadowing for a future bug?) + return perms; + }else{ + //Otherwise this is the first launch of the install, say hello + console.log("First launch detected! Initializing permissions document in Database!"); + + //create and save the permissions document + perms = await module.exports.create({}); + await perms.save(); + + //live up to the name of the function + return perms; + } +} + +permissionSchema.statics.rankToNum = function(rank){ + return rankEnum.indexOf(rank); +} + +permissionSchema.statics.permCheck = async function(user, perm){ + const perms = await this.getPerms(); + + if(perms[perm] != null){ + requiredRank = this.rankToNum(perms[perm]) + userRank = user ? this.rankToNum(user.rank) : 0; + return (userRank >= requiredRank); + }else{ + throw new Error(`Permission check '${perm}' not found!`); + } +} + +permissionSchema.statics.reqPermCheck = function(perm){ + return async (req, res, next)=>{ + if(req.session.user){ + if(await permissionSchema.statics.permCheck(req.session.user, perm)){ + next(); + }else{ + res.status(401); + res.send({error:`You do not have a high enough rank to access this resource.`}); + } + }else{ + res.status(401); + res.send({error:`You must login to access this resource.`}); + } + } +} + +module.exports = mongoose.model("permissions", permissionSchema); \ No newline at end of file diff --git a/src/schemas/userSchema.js b/src/schemas/userSchema.js index b225e6c..3613ede 100644 --- a/src/schemas/userSchema.js +++ b/src/schemas/userSchema.js @@ -20,6 +20,7 @@ const {mongoose} = require('mongoose'); //local imports const server = require('../server.js'); const statSchema = require('./statSchema.js'); +const permissionSchema = require('./permissionSchema.js'); const hashUtil = require('../utils/hashUtils'); @@ -47,7 +48,7 @@ const userSchema = new mongoose.Schema({ rank: { type: mongoose.SchemaTypes.String, required: true, - enum: ["user", "gold", "bot", "mod", "admin"], + enum: permissionSchema.rankEnum, default: "user" }, tokes: {