From 7655eebcd9a1b20cdba13a6ac808c4b429acafd1 Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Tue, 7 Jun 2022 03:47:37 +0200 Subject: [PATCH] patched review suggestions and discovered bugs --- src/Controllers/event.controller.ts | 14 +- src/Controllers/media.controller.ts | 30 +-- src/Controllers/organisation.controller.ts | 4 +- src/Controllers/participant.controller.ts | 22 ++- src/Controllers/role.controller.ts | 42 ++--- src/Controllers/role_schema.controller.ts | 8 +- src/Controllers/team.controller.ts | 25 ++- src/Controllers/user_auth.controller.ts | 121 +++++++----- src/Middleware/auth/auth.ts | 210 ++++++++++----------- src/lib/result_schema.ts | 4 +- 10 files changed, 259 insertions(+), 221 deletions(-) diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index 3dfcd84..03fb8eb 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -137,12 +137,14 @@ export const addEvent = async (req: Request, res: Response) => { ); } + const body = result.data; + const event = await prisma.event.create({ data: { - name: req.body.name, - date: req.body.date, - briefDescription: req.body.briefDescription, - fullDescription: req.body.fullDescription, + name: body.name, + date: body.date, + briefDescription: body.briefDescription, + fullDescription: body.fullDescription, }, select: basicEvent, }); @@ -206,7 +208,7 @@ export const updateEvent = async (req: Request<{ pid: string }>, res: Response) }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("discipline", pid); + throw new NotFoundError("event", pid); } throw e; @@ -231,7 +233,7 @@ export const deleteEvent = async (req: Request, res: Res return res.status(204).end(); } catch (e) { if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("discipline", pid); + throw new NotFoundError("event", pid); } throw e; diff --git a/src/Controllers/media.controller.ts b/src/Controllers/media.controller.ts index 11a2cc7..d5b4b36 100644 --- a/src/Controllers/media.controller.ts +++ b/src/Controllers/media.controller.ts @@ -10,6 +10,7 @@ import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import { generateInvalidBodyError, DataType } from "./common"; import { unlink } from "fs/promises"; import ForwardableError from "../Middleware/error/ForwardableError"; +import { table } from "console"; require("express-async-errors"); @@ -204,21 +205,26 @@ export const linkMedia = async (req: Request<{ pid: string }, {}, { mediaPid: st ); } - const updatedRec = await getPrismaUpdateFKT(tableToUpdate[2])({ - where: { pid }, - data: { - visual: { connect: { pid: mediaPid } }, - }, - }); + try { + const updatedRec = await getPrismaUpdateFKT(tableToUpdate[2])({ + where: { pid }, + data: { + visual: { connect: { pid: mediaPid } }, + }, + }); - if (!updatedRec) { - throw new NotFoundError(tableToUpdate[2], pid); + return res.status(200).json({ + type: "success", + payload: { message: "Linking with the visual was successful" }, + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError(tableToUpdate[2], pid); + } + + throw e; } - return res.status(200).json({ - type: "success", - payload: {}, - }); }; export const unlinkMedia = async (req: Request<{ pid: string; mediaPid: string }>, res: Response) => { diff --git a/src/Controllers/organisation.controller.ts b/src/Controllers/organisation.controller.ts index d21ac13..e79d7a3 100644 --- a/src/Controllers/organisation.controller.ts +++ b/src/Controllers/organisation.controller.ts @@ -28,7 +28,7 @@ const detailedOrganisation = { pid: true, name: true, date: true, - description: true, + briefDescription: true, }, }, } as const; @@ -191,7 +191,7 @@ export const updateOrganisation = async ( }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("discipline", pid); + throw new NotFoundError("organisation", pid); } throw e; diff --git a/src/Controllers/participant.controller.ts b/src/Controllers/participant.controller.ts index 40d5721..307dcba 100644 --- a/src/Controllers/participant.controller.ts +++ b/src/Controllers/participant.controller.ts @@ -16,8 +16,6 @@ const InitialParticipant = z.object({ groupPid: z.string().min(1).uuid(), }); -const ParticipantBody = InitialParticipant.extend({ teamPid: z.string().uuid() }); - const returnedParticipant = { pid: true, firstName: true, @@ -41,7 +39,7 @@ const returnedParticipant = { export const createParticipant = async (req: Request<{ teamPid: string }>, res: Response) => { const { teamPid } = req.params; - const result = ParticipantBody.safeParse(req.body); + const result = InitialParticipant.safeParse(req.body); if (result.success === false) { return res.status(400).json( @@ -59,20 +57,20 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: if (req.teamleader?.isAuthenticated) { await requireLeaderOfTeam(req.teamleader, teamPid); - } else { + } else if (req.auth?.permission_level == "STANDARD") { requireResponsibleForGroups(req.auth, body.groupPid); } try { const discipline = await prisma.team.findUnique({ - where: { pid: body.teamPid }, + where: { pid: teamPid }, select: { discipline: true } }); const maxteamsize = discipline?.discipline.maxTeamSize; const userCount = await prisma.participant.count({ - where: { team: { pid: body.teamPid } } + where: { team: { pid: teamPid } } }); if (maxteamsize == userCount) { @@ -85,7 +83,7 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: lastName: body.lastName, relevance: "MEMBER", group: { connect: { pid: body.groupPid } }, - team: { connect: { pid: body.teamPid } }, + team: { connect: { pid: teamPid } }, }, select: returnedParticipant, }); @@ -95,7 +93,7 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { return res .status(404) - .json(generateError(`Could not link to team with ID '${body.teamPid}, or group with ID ${body.groupPid}'`)); + .json(generateError(`Could not link to team with ID '${teamPid}, or group with ID ${body.groupPid}'`)); } throw e; } @@ -107,6 +105,8 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp if (req.teamleader?.isAuthenticated) { await requireResponsibleForParticipant(req.teamleader, pid); + } else if (req.auth?.permission_level == "STANDARD") { + requireResponsibleForGroups(req.auth, await getGroupByParticipantPid(pid)); } const result = InitialParticipant.partial().safeParse(req.body); @@ -143,7 +143,9 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("participant", pid); + return res + .status(404) + .json(generateError(`Could not find participant '${pid}, or link to group with ID ${body.groupPid}.'`)); } throw e; @@ -156,7 +158,7 @@ export const deleteParticipant = async (req: Request<{ pid: string }>, res: Resp if (req.teamleader?.isAuthenticated) { await requireResponsibleForParticipant(req.teamleader, pid); - } else { + } else if (req.auth?.permission_level == "STANDARD") { requireResponsibleForGroups(req.auth, await getGroupByParticipantPid(pid)); } diff --git a/src/Controllers/role.controller.ts b/src/Controllers/role.controller.ts index c9e55bf..1c761e6 100644 --- a/src/Controllers/role.controller.ts +++ b/src/Controllers/role.controller.ts @@ -1,3 +1,4 @@ +import { Prisma } from "@prisma/client"; import { Request, Response } from "express"; import { z } from "zod"; import prisma from "../lib/prisma"; @@ -61,7 +62,7 @@ export async function getRolesForTeam(req: Request<{ pid: string }>, res: Respon if (req.teamleader?.isAuthenticated) { await requireLeaderOfTeam(req.teamleader, pid); } else { - await requireResponsibleForGroups(req.auth, await getGroupsByTeamPid(pid)); + requireResponsibleForGroups(req.auth, await getGroupsByTeamPid(pid)); } const roles = await prisma.role.findMany({ @@ -84,7 +85,6 @@ export async function getRolesForTeam(req: Request<{ pid: string }>, res: Respon const AssignParticipantToRoleBody = z.object({ participantPid: z.string().uuid(), - teamPid: z.string().uuid(), }); // requires: auth(leader of the team) @@ -102,31 +102,29 @@ export async function assignParticipantToRole(req: Request<{ pid: string }>, res if (req.teamleader?.isAuthenticated) { requireResponsibleForParticipant(req.teamleader, participantPid); } else { - await requireResponsibleForGroups(req.auth, await getGroupByParticipantPid(participantPid)); + requireResponsibleForGroups(req.auth, await getGroupByParticipantPid(participantPid)); } - const schema = await prisma.role.findFirst({ - where: { pid, team: { participants: { some: { pid: participantPid } } } }, - select: { participant: { select: { pid: true, firstName: true, lastName: true } } }, - }); + try { + const schema = await prisma.role.update({ where: { pid }, data: { participant: { connect: { pid: participantPid } } }, select: detailedRole }); - if (!schema) { - return res.status(404).json({ - type: "error", + return res.status(200).json({ + type: "success", payload: { - message: `No role with the ID '${pid}' could be found in the scope of the participant with the ID '${participantPid}'`, + message: `The participant with ID '${participantPid}' was successfully assigned to the role with ID '${pid}'`, + ...(schema.participant ? { unassigned: schema.participant } : {}), }, }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + return res.status(404).json({ + type: "error", + payload: { + message: `No role with the ID '${pid}' could be found in the scope of the participant with the ID '${participantPid}'`, + }, + }); + } + + throw e; } - - // No error handling should be neccesary as the existence of the role and participant have already been checked above - await prisma.role.update({ where: { pid }, data: { participant: { connect: { pid: participantPid } } } }); - - return res.status(200).json({ - type: "success", - payload: { - message: `The participant with ID '${participantPid}' was successfully assigned to the role with ID '${pid}'`, - ...(schema.participant ? { unassigned: schema.participant } : {}), - }, - }); } diff --git a/src/Controllers/role_schema.controller.ts b/src/Controllers/role_schema.controller.ts index 374a68b..99c5369 100644 --- a/src/Controllers/role_schema.controller.ts +++ b/src/Controllers/role_schema.controller.ts @@ -3,7 +3,7 @@ import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import { Request, Response } from "express"; import { z } from "zod"; import prisma from "../lib/prisma"; -import { DurationSchemaT, parseSchema, PointSchemaT } from "../lib/result_schema"; +import { DurationSchema, parseSchema, PointSchema } from "../lib/result_schema"; import NotFoundError from "../Middleware/error/NotFoundError"; import SchemaError from "../Middleware/error/SchemaError"; import { @@ -19,7 +19,7 @@ require("express-async-errors"); const RoleSchemaBody = z.object({ name: z.string().min(1), - schema: z.string(), + schema: z.string(PointSchema).or(z.string(DurationSchema)), }); const UpdateBody = RoleSchemaBody.partial(); @@ -138,7 +138,7 @@ export const createRoleSchema = async ( export const UpdateRoleSchema = async (req: Request<{ pid: string }>, res: Response) => { if (req.auth?.permission_level !== "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); + return res.status(403).json(createInsufficientPermissionsError()); } const { pid } = req.params; @@ -150,7 +150,7 @@ export const UpdateRoleSchema = async (req: Request<{ pid: string }>, res: Respo generateInvalidBodyError( { name: DataType.STRING, - schema: DataType.STRING, + schema: DataType.RESULT_SCHEMA, }, result.error ) diff --git a/src/Controllers/team.controller.ts b/src/Controllers/team.controller.ts index 79628e2..16dd84a 100644 --- a/src/Controllers/team.controller.ts +++ b/src/Controllers/team.controller.ts @@ -7,6 +7,8 @@ import { Prisma } from "@prisma/client"; import NotFoundError from "../Middleware/error/NotFoundError"; import { requireResponsibleForGroups } from "../Middleware/auth/auth"; import AuthError from "../Middleware/error/AuthError"; +import { runInNewContext } from "vm"; +import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; require("express-async-errors"); @@ -31,6 +33,9 @@ export const basicTeam = { }; export const getTeams = async (req: Request, res: Response) => { + if (req.auth?.permission_level == "STANDARD") { + throw new AuthError("A STANDARD Admin is not allowed to get all teams!"); + } const teams = await prisma.team.findMany({ select: basicTeam }); res.status(200).json({ type: "success", payload: { teams } }); @@ -41,8 +46,8 @@ export const getTeam = async (req: Request<{ pid: string }>, res: Response) => { if (req.teamleader?.isAuthenticated) { await requireLeaderOfTeam(req.teamleader, pid); - } else { - await requireResponsibleForGroups(req.auth, pid); + } else if (req.auth?.permission_level == "STANDARD") { + requireResponsibleForGroups(req.auth, await getGroupsByTeamPid(pid)); } const team = await prisma.team.findUnique({ @@ -62,8 +67,8 @@ export const updateTeam = async (req: Request, res: Response) => { if (req.teamleader?.isAuthenticated) { await requireLeaderOfTeam(req.teamleader, pid); - } else { - await requireResponsibleForGroups(req.auth, await getGroupsByTeamPid(pid)); + } else if (req.auth?.permission_level == "STANDARD") { + requireResponsibleForGroups(req.auth, await getGroupsByTeamPid(pid)); } const result = TeamBody.omit({ partGroupId: true, partFirstName: true, partLastName: true }).safeParse(req.body); @@ -117,9 +122,17 @@ export const deleteTeam = async (req: Request, res: Response) => { throw new AuthError("STANDARD Admins are not allowed to delete Teams!") } - await prisma.team.delete({ where: { pid } }); + try { + await prisma.team.delete({ where: { pid } }); - res.status(204).json({ type: "success", payload: { message: "Sucesfully deleted team" } }); + res.status(204).json({ type: "success", payload: { message: "Sucesfully deleted team" } }); + } catch (e) { + if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("team", pid); + } + + throw e; + } }; export async function checkTeamExistence(teamPid: string) { diff --git a/src/Controllers/user_auth.controller.ts b/src/Controllers/user_auth.controller.ts index efa67f9..8d65606 100644 --- a/src/Controllers/user_auth.controller.ts +++ b/src/Controllers/user_auth.controller.ts @@ -7,6 +7,8 @@ import { DataType, generateError, generateInvalidBodyError } from "./common"; import { generateTeamleaderJWT } from "../Middleware/auth/teamleaderAuth"; import { createRolesForTeam } from "./role.controller"; import { z } from "zod"; +import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; +import NotFoundError from "../Middleware/error/NotFoundError"; require("express-async-errors"); @@ -49,50 +51,55 @@ export const register = async (req: Request<{}, {}, CreateTeamBody>, res: Respon const body = result.data; - const group = prisma.group.findUnique({ where: { pid: body.partGroupId } }); - - if (typeof group == null) { - return res.status(404).json(generateError("Specified group was not found!")); - } - - const discipline = prisma.discipline.findUnique({ where: { pid: body.disciplineId } }); - - if (typeof discipline == null) { - return res.status(404).json(generateError("Specified discipline was not found!")); - } - - const team = await prisma.team.create({ - data: { - leaderEmail: body.leaderEmail, - name: body.teamName, - roles: undefined, - discipline: { connect: { pid: body.disciplineId } }, - participants: { - create: { - firstName: body.partFirstName, - lastName: body.partLastName, - relevance: "TEAMLEADER", - group: { connect: { pid: body.partGroupId } }, + try { + const team = await prisma.team.create({ + data: { + leaderEmail: body.leaderEmail, + name: body.teamName, + roles: undefined, + discipline: { connect: { pid: body.disciplineId } }, + participants: { + create: { + firstName: body.partFirstName, + lastName: body.partLastName, + relevance: "TEAMLEADER", + group: { connect: { pid: body.partGroupId } }, + }, }, }, - }, - select: { - pid: true, - name: true, - discipline: { select: { pid: true } }, - }, - }); + select: { + pid: true, + name: true, + discipline: { select: { pid: true } }, + }, + }); - await createRolesForTeam(team.pid); + await createRolesForTeam(team.pid); - const usid = nanoid(); + const usid = nanoid(); + + (await mailClient).set(usid, team.pid); + + const eventname = await prisma.discipline.findUnique({ where: { pid: body.disciplineId }, select: { event: { select: { name: true, } } } }).event.name; + verificationMail(req.body.leaderEmail, eventname, usid); + + return res.status(201).json({ type: "success", payload: { team } }); + + } catch (e) { + if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { + return res.status(404).json({ + type: "error", + payload: { + message: `Could not connect to discipline with the ID '${body.disciplineId}' or could not connect participant to group with the ID '${body.partGroupId}'`, + }, + }); + } + + throw e; + } - (await mailClient).set(usid, team.pid); - // TODO: fix "eventname" - verificationMail(req.body.leaderEmail, "eventname", usid); - res.status(201).json({ type: "success", payload: { team } }); }; export const requestToken = async (req: Request, res: Response) => { @@ -117,6 +124,7 @@ export const requestToken = async (req: Request, res: Response) => { (await mailClient).set(usid, team.pid); // TODO: fix "eventname" + // let teamName = await prisma.team.findUnique({ where: { pid: teamId }, select: { discipline: { select: { event: { select: { name: true } } } } } }); verificationMail(team.leaderEmail, "eventname", usid); res.status(200).json({ type: "sucess", payload: { message: "Email sent!" } }); @@ -145,23 +153,32 @@ export const verifyEmail = async (req: Request, res: Response) => { }); } - const team = await prisma.team.update({ - where: { - pid: acc, - }, - data: { - verified: true, - }, - }); + try { + const team = await prisma.team.update({ + where: { + pid: acc, + }, + data: { + verified: true, + }, + }); - mailClient.set(code, ""); + mailClient.set(code, ""); - const token = generateTeamleaderJWT(team); + const token = generateTeamleaderJWT(team); - res.cookie("teamLeaderToken", token, { - path: "/", - maxAge: 1000 * 60 * 60 * 24 * 4, - }); + res.cookie("teamLeaderToken", token, { + path: "/", + maxAge: 1000 * 60 * 60 * 24 * 4, + }); + + res.status(200).json({ type: "succes", payload: { token } }); + } catch (e) { + if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("discipline", acc); + } + + throw e; + } - res.status(200).json({ type: "succes", payload: { token } }); }; diff --git a/src/Middleware/auth/auth.ts b/src/Middleware/auth/auth.ts index ed11793..5026edb 100644 --- a/src/Middleware/auth/auth.ts +++ b/src/Middleware/auth/auth.ts @@ -18,42 +18,82 @@ export const getBearerToken = (authorization: string) => authorization.slice(7); const _requireAdminAuthentication = (config: { optional?: Boolean; controlled?: Boolean } = { optional: false, controlled: false }) => - async (req: Request, res: Response, next: NextFunction) => { - if (!JWT_SECRET) { - throw new Error("JWT_SECRET not set"); - } - - const { authorization } = req.headers; - - if (!authorization) { - if (config.optional) { - return false; + async (req: Request, res: Response, next: NextFunction) => { + if (!JWT_SECRET) { + throw new Error("JWT_SECRET not set"); } - return res.status(403).send({ - type: "error", - payload: { - message: "The requeset did not include the Authorization header", - }, - }); - } + const { authorization } = req.headers; - if (!verifyAuthorizationFormat(authorization)) { - return res.status(400).send({ - type: "error", - payload: { - message: "Malformed Authorization header", - format: "Bearer ", - }, - }); - } + if (!authorization) { + if (config.optional) { + return false; + } - let token_payload_: string | JwtPayload; + return res.status(403).send({ + type: "error", + payload: { + message: "The requeset did not include the Authorization header", + }, + }); + } - try { - token_payload_ = jwt.verify(getBearerToken(authorization), JWT_SECRET); - } catch (e) { - if (e instanceof JsonWebTokenError) { + if (!verifyAuthorizationFormat(authorization)) { + return res.status(400).send({ + type: "error", + payload: { + message: "Malformed Authorization header", + format: "Bearer ", + }, + }); + } + + let token_payload_: string | JwtPayload; + + try { + token_payload_ = jwt.verify(getBearerToken(authorization), JWT_SECRET); + } catch (e) { + if (e instanceof JsonWebTokenError) { + return res.status(403).json({ + type: "error", + payload: { + message: "Token could not be verified; It might be expired", + }, + }); + } + + throw e; + } + + const token_payload = token_payload_ as AuthJWTPayload; + + if (!token_payload.permission_level || !token_payload.pid || !token_payload.revision) { + if (typeof (token_payload as unknown as TeamleaderJWTPayload).team === "string") { + if (config.controlled) { + return false; + } + throw new AuthError("Teamleader authentication is not supported for this operation!"); + } + + throw new AuthError("The token did not include the required information!"); + } + + const { pid, revision } = token_payload; + + let db_revision = await authClient.get(pid); + + if (db_revision === null) { + // Load the revision ID from the main DB and cache it in redis + const user = await prisma.admin.findUnique({ where: { pid }, select: { revision: true } }); + + if (user) { + db_revision = user.revision.toISOString(); + + await authClient.set(pid, db_revision); + } + } + + if (revision !== db_revision || !revision || !db_revision) { return res.status(403).json({ type: "error", payload: { @@ -62,62 +102,22 @@ const _requireAdminAuthentication = }); } - throw e; - } + req.auth = { + isAuthenticated: true, + pid: token_payload.pid, + name: token_payload.name, + permission_level: token_payload.permission_level, + groups: token_payload.groups, + revision: token_payload.revision, + }; - const token_payload = token_payload_ as AuthJWTPayload; - - if (!token_payload.permission_level || !token_payload.pid || !token_payload.revision) { - if (typeof (token_payload as unknown as TeamleaderJWTPayload).team === "string") { - if (config.controlled) { - return false; - } - throw new AuthError("Teamleader authentication is not supported for this operation!"); + if (!config.controlled) { + next(); } - throw new AuthError("The token did not include the required information!"); - } - - const { pid, revision } = token_payload; - - let db_revision = await authClient.get(pid); - - if (db_revision === null) { - // Load the revision ID from the main DB and cache it in redis - const user = await prisma.admin.findUnique({ where: { pid }, select: { revision: true } }); - - if (user) { - db_revision = user.revision.toISOString(); - - await authClient.set(pid, db_revision); - } - } - - if (revision !== db_revision || !revision || !db_revision) { - return res.status(403).json({ - type: "error", - payload: { - message: "Token could not be verified; It might be expired", - }, - }); - } - - req.auth = { - isAuthenticated: true, - pid: token_payload.pid, - name: token_payload.name, - permission_level: token_payload.permission_level, - groups: token_payload.groups, - revision: token_payload.revision, + return true; }; - if (!config.controlled) { - next(); - } - - return true; - }; - export const requireAuthentication = _requireAdminAuthentication({ optional: false, controlled: false }); type AuthType = "admin" | "teamleader"; @@ -144,37 +144,37 @@ function getAuthTypes(type: AuthType | AuthTypeConfig): AuthType[] { export const requireConfiguredAuthentication = (config: AuthConfiguration = { optional: false, type: "admin" }) => - async (req: Request, res: Response, next: NextFunction) => { - const types = getAuthTypes(config.type); - const optional = config.optional; + async (req: Request, res: Response, next: NextFunction) => { + const types = getAuthTypes(config.type); + const optional = config.optional; - let adminFinished = false; - let teamleaderFinished = false; + let adminFinished = false; + let teamleaderFinished = false; - if (types.includes("admin")) { - adminFinished = Boolean(await _requireAdminAuthentication({ optional: true, controlled: true })(req, res, next)); + if (types.includes("admin")) { + adminFinished = Boolean(await _requireAdminAuthentication({ optional: true, controlled: true })(req, res, next)); - if (adminFinished) { - return next(); + if (adminFinished) { + return next(); + } } - } - if (types.includes("teamleader")) { - teamleaderFinished = Boolean( - _requireTeamleaderAuthentication({ optional: true, controlled: true })(req, res, next) - ); + if (types.includes("teamleader")) { + teamleaderFinished = Boolean( + _requireTeamleaderAuthentication({ optional: true, controlled: true })(req, res, next) + ); - if (teamleaderFinished) { - return next(); + if (teamleaderFinished) { + return next(); + } } - } - if (!config.optional) { - throw new AuthError("No sufficient authorization was provided for this operation"); - } + if (!config.optional) { + throw new AuthError("No sufficient authorization was provided for this operation"); + } - next(); - }; + next(); + }; export function requireResponsibleForGroups(auth: AuthJWTPayload | undefined, groupPids: string[] | string) { if (auth?.permission_level === "ELEVATED") { @@ -190,7 +190,7 @@ export function requireResponsibleForGroups(auth: AuthJWTPayload | undefined, gr throw new AuthError("The provided authorization is not valid for the requested operation!"); }); } else { - if (auth?.groups.includes(groupPids)) { + if (!auth?.groups.includes(groupPids)) { throw new AuthError("The provided authorization is not valid for the requested operation!"); } } diff --git a/src/lib/result_schema.ts b/src/lib/result_schema.ts index 7da23c9..fdb6b62 100644 --- a/src/lib/result_schema.ts +++ b/src/lib/result_schema.ts @@ -7,7 +7,7 @@ const SchemaVersion = z.enum(["1.0"]); const TimeUnit = z.enum(["days", "hours", "minutes", "seconds", "milliseconds"]); -const DurationSchema = z +export const DurationSchema = z .object({ type: z.literal("duration"), min: z.number().int({ message: "min must be an integer (relative to smallestUnit)" }), @@ -17,7 +17,7 @@ const DurationSchema = z }) .refine(({ min, max }) => min < max, { message: "min must be smaller than max" }); -const PointSchema = z +export const PointSchema = z .object({ type: z.literal("points"), min: z.number(),