/*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 channelPermissionSchema = require('./channel/channelPermissionSchema'); //This originally belonged to the permissionSchema, but this avoids circular dependencies. //We could update all references but quite honestly I that would be uglier, this should have a copy too... const rankEnum = channelPermissionSchema.statics.rankEnum; const permissionSchema = new mongoose.Schema({ adminPanel: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, changeRank: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, changePerms: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, banUser: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, nukeUser: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, genPasswordReset: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, registerChannel: { type: mongoose.SchemaTypes.String, enum: rankEnum, default: "admin", required: true }, channelOverrides: { type: channelPermissionSchema, default: () => ({}) }, }); //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){ //Get permission list const perms = await this.getPerms(); //Set user to anon rank if no rank was found for the given user if(user == null || user.rank == null){ user ={ rank: "anon" }; } //Check if this permission exists if(perms[perm] != null){ //if so get required rank as a number requiredRank = this.rankToNum(perms[perm]) //if so get user rank as a number userRank = user ? this.rankToNum(user.rank) : 0; //return whether or not the user is equal to or higher than the required rank for this permission return (userRank >= requiredRank); }else{ //if not scream and shout throw new Error(`Permission check '${perm}' not found!`); } } //Middleware for rank checks permissionSchema.statics.reqPermCheck = function(perm){ return async (req, res, next)=>{ if(await permissionSchema.statics.permCheck(req.session.user, perm)){ next(); }else{ res.status(401); return res.send({errors:[{type: "Unauthorized", msg: "You do not have a high enough rank to access this resource.", date: new Date()}]}); } } } module.exports = mongoose.model("permissions", permissionSchema);