From ee9f50c87f367d1b3d8a8f7916afd63e798219c3 Mon Sep 17 00:00:00 2001 From: Holly Date: Sun, 29 Sep 2024 21:35:36 +0100 Subject: [PATCH] add BadgeEditor user role --- server/controller/AdminController.ts | 8 +++--- server/controller/Controller.ts | 40 ++++++++++++++++++++++++---- server/enums/UserLevel.ts | 1 + server/services/UserService.ts | 2 -- server/views/admin/user.ejs | 13 +-------- server/views/home/home.ejs | 5 ++++ 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/server/controller/AdminController.ts b/server/controller/AdminController.ts index 3ed33ae..c8ef8f6 100644 --- a/server/controller/AdminController.ts +++ b/server/controller/AdminController.ts @@ -105,7 +105,7 @@ export default class AdminController_Auth$Admin extends Controller { return this.redirectToAction("parties"); } - public async Badges_Get() { + public async Badges_Get_Auth$BadgeEditor() { const adminBadgesViewModel: AdminBadgesViewModel = { badges: await BadgeService.LoadAll() }; @@ -113,7 +113,7 @@ export default class AdminController_Auth$Admin extends Controller { return this.view(adminBadgesViewModel); } - public async Badge_Get(adminBadgeViewModel: AdminBadgeViewModel) { + public async Badge_Get_Auth$BadgeEditor(adminBadgeViewModel: AdminBadgeViewModel) { const badge = adminBadgeViewModel.id ? await BadgeService.LoadBadge(parseInt(adminBadgeViewModel.id)) : null; if (typeof(adminBadgeViewModel.id) !== "undefined" && badge) { adminBadgeViewModel.name = badge.Name; @@ -130,7 +130,7 @@ export default class AdminController_Auth$Admin extends Controller { return this.view(adminBadgeViewModel); } - public async Badge_Post(adminBadgeViewModel: AdminBadgeViewModel) { + public async Badge_Post_Auth$BadgeEditor(adminBadgeViewModel: AdminBadgeViewModel) { if (typeof(adminBadgeViewModel.id) === "undefined") { return this.badRequest(); } @@ -140,7 +140,7 @@ export default class AdminController_Auth$Admin extends Controller { return this.redirectToAction("badges"); } - public async DeleteBadge_Get(adminDeleteBadgeModel: AdminDeleteBadgeModel) { + public async DeleteBadge_Get_Auth$BadgeEditor(adminDeleteBadgeModel: AdminDeleteBadgeModel) { if (typeof(adminDeleteBadgeModel.id) === "undefined" || typeof(adminDeleteBadgeModel.id) !== "string") { return this.badRequest(); } diff --git a/server/controller/Controller.ts b/server/controller/Controller.ts index fc08fad..2b7ba9a 100644 --- a/server/controller/Controller.ts +++ b/server/controller/Controller.ts @@ -15,13 +15,14 @@ export default abstract class Controller { const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(this)); const rawControllerParts = this.constructor.name.split("_"); const controllerName = rawControllerParts.splice(0, 1)[0].replace("Controller", "").toLowerCase(); - let controllerAuthLevel: UserLevel | undefined; + const controllerAuthLevels: Array = []; + const actionAuthLevels: { [ key : string ]: Array } = {}; for (const prop of rawControllerParts) { if (prop.startsWith("Auth")) { const userLevel = prop.split("$")[1]; // @ts-ignore - controllerAuthLevel = UserLevel[userLevel]; + controllerAuthLevels.push(UserLevel[userLevel]); Console.printInfo(`Set Auth level requirement for ${this.constructor.name} to ${userLevel}`); } } @@ -32,7 +33,7 @@ export default abstract class Controller { } const params = method.split("_"); - const methodNameRaw = params.splice(0, 1)[0] + const methodNameRaw = params.splice(0, 1)[0]; const methodName = methodNameRaw.toLowerCase(); const doAuth = !params.includes("AllowAnonymous"); @@ -44,8 +45,25 @@ export default abstract class Controller { if (doAuth && session === undefined) { return res.redirect(`/account/login?returnTo=${encodeURIComponent(req.url)}`); } - if (session !== undefined && controllerAuthLevel !== undefined && controllerAuthLevel !== session.userLevel) { - return res.status(403).send("Forbidden"); + const methodAuthCheck = actionAuthLevels[`${controllerName}_${methodName}_${req.method.toLowerCase()}`]; + let wasMethodMatch = false; + if (methodAuthCheck && session !== undefined) { + for (const auth of methodAuthCheck) { + if (auth === session.userLevel) { + wasMethodMatch = true; + } + } + } + if (!wasMethodMatch && session !== undefined && controllerAuthLevels.length > 0) { + let hasLevelMatch = false; + for (const level of controllerAuthLevels) { + if (level === session.userLevel) { + hasLevelMatch = true; + } + } + if (!hasLevelMatch) { + return res.status(403).send("Forbidden"); + } } const requestCtx = new RequestCtx(req, res, controllerName, methodName, session); @@ -53,9 +71,12 @@ export default abstract class Controller { } let funcMethods:Array = []; + let thisMethodHttpMethod = ""; for (const param of params) { + //console.log(param); if (param === "Get" || param === "Post" || param === "Put") { funcMethods.push(param); + thisMethodHttpMethod = param.toLowerCase(); // @ts-ignore Controller.FastifyInstance[param.toLowerCase()](`/${controllerName}/${methodName === "index" ? "" : methodName}`, requestHandler); Console.printInfo(`Registered ${this.constructor.name}.${method} to "/${controllerName}/${methodName === "index" ? "" : methodName}" as ${param}`); @@ -67,6 +88,15 @@ export default abstract class Controller { Controller.FastifyInstance[param.toLowerCase()](`/${controllerName}`, requestHandler); Console.printInfo(`Registered ${this.constructor.name}.${method} to "/${controllerName}" as ${param}`); } + } else if (param.startsWith("Auth")) { + const nameWithMethod = `${controllerName}_${methodName}_${thisMethodHttpMethod}`; + const userLevel = param.split("$")[1]; + if (!(nameWithMethod in actionAuthLevels)) { + actionAuthLevels[nameWithMethod] = []; + } + // @ts-ignore + actionAuthLevels[nameWithMethod].push(UserLevel[userLevel]); + Console.printInfo(`Set Auth level requirement for ${this.constructor.name}.${method} to ${userLevel}`); } } diff --git a/server/enums/UserLevel.ts b/server/enums/UserLevel.ts index b2c67a8..57982ce 100644 --- a/server/enums/UserLevel.ts +++ b/server/enums/UserLevel.ts @@ -1,5 +1,6 @@ export enum UserLevel { Unknown = 0, User = 10, + BadgeEditor = 20, Admin = 999 } \ No newline at end of file diff --git a/server/services/UserService.ts b/server/services/UserService.ts index f73dcd8..bd96be7 100644 --- a/server/services/UserService.ts +++ b/server/services/UserService.ts @@ -124,7 +124,6 @@ export default class UserService { await UserPartyRepo.insertUpdate(userParty); } catch (e) { Console.printError(`MultiProbe server service error:\n${e}`); - console.log(e); throw e; } } @@ -134,7 +133,6 @@ export default class UserService { await UserPartyRepo.deactivateAll(currentUserId); } catch (e) { Console.printError(`MultiProbe server service error:\n${e}`); - console.log(e); throw e; } } diff --git a/server/views/admin/user.ejs b/server/views/admin/user.ejs index 2adb02b..9606178 100644 --- a/server/views/admin/user.ejs +++ b/server/views/admin/user.ejs @@ -37,6 +37,7 @@ @@ -50,16 +51,4 @@ - - <%- include("../base/footer") %> \ No newline at end of file diff --git a/server/views/home/home.ejs b/server/views/home/home.ejs index ccd4614..aa44cef 100644 --- a/server/views/home/home.ejs +++ b/server/views/home/home.ejs @@ -12,6 +12,11 @@ Create Party Join Party + <% if (user.UserLevel === UserLevel.BadgeEditor) { %> + + <% } %> <% if (user.UserLevel === UserLevel.Admin) { %>