diff --git a/src/Controllers/admin_auth.controller.ts b/src/Controllers/admin_auth.controller.ts index 760e85d..bb9ed32 100644 --- a/src/Controllers/admin_auth.controller.ts +++ b/src/Controllers/admin_auth.controller.ts @@ -6,7 +6,7 @@ import argon2 from "argon2"; import jwt from "jsonwebtoken"; import { DataType, generateInvalidBodyError } from "./common"; -const JWT_SECRET = process.env.JWT_SECRET || "secret"; +const JWT_SECRET = process.env.JWT_SECRET; const TOKEN_EXPIRY = "4 days"; export interface AuthJWTPayload { @@ -18,6 +18,10 @@ export interface AuthJWTPayload { } function createAdminJWT(admin: Admin & { groups: Group[] }) { + if (!JWT_SECRET) { + throw new Error("JWT_SECRET not set"); + } + const payload: AuthJWTPayload = { pid: admin.pid, name: admin.name, diff --git a/src/Controllers/role.controller.ts b/src/Controllers/role.controller.ts index f5088c9..63721fe 100644 --- a/src/Controllers/role.controller.ts +++ b/src/Controllers/role.controller.ts @@ -2,9 +2,12 @@ import { Role } from "@prisma/client"; import { Request, Response } from "express"; import { z } from "zod"; import prisma from "../lib/prisma"; +import { requireLeaderOfTeam, requireResponsibleForParticipant } from "../Middleware/auth/teamleaderAuth"; import NotFoundError from "../Middleware/error/NotFoundError"; import { DataType, generateInvalidBodyError } from "./common"; +require("express-async-errors"); + /** * * @param teamPid: Pid of the team to add the roles to @@ -29,7 +32,8 @@ export async function createRolesForTeam(teamPid: string) { export async function getRolesForTeam(req: Request<{ teamPid: string }>, res: Response) { const teamPid = req.params.teamPid; - // TODO: Check if leader of team + requireLeaderOfTeam(req.teamleader, teamPid); + const roles = await prisma.role.findMany({ where: { team: { pid: teamPid } }, select: { @@ -63,6 +67,8 @@ export async function assignParticipantToRole(req: Request<{ pid: string }>, res const { participantPid } = zBody.data; const rolePid = req.params.pid; + requireResponsibleForParticipant(req.teamleader, participantPid); + const schema = await prisma.role.findFirst({ where: { pid: rolePid, team: { participants: { some: { pid: participantPid } } } }, select: { participant: { select: { pid: true, firstName: true, lastName: true } } }, diff --git a/src/Middleware/auth/auth.ts b/src/Middleware/auth/auth.ts index 6fb22eb..981c116 100644 --- a/src/Middleware/auth/auth.ts +++ b/src/Middleware/auth/auth.ts @@ -6,13 +6,17 @@ import { authClient } from "../../lib/redis"; import jwt, { JsonWebTokenError, JwtPayload } from "jsonwebtoken"; import prisma from "../../lib/prisma"; -const JWT_SECRET = process.env.JWT_SECRET || "secret"; +const JWT_SECRET = process.env.JWT_SECRET; export const verifyAuthorizationFormat = (authorization: string) => /^Bearer .+$/.test(authorization); export const getBearerToken = (authorization: string) => authorization.slice(7); export const requireAuthentication = async (req: Request, res: Response, next: NextFunction) => { + if (!JWT_SECRET) { + throw new Error("JWT_SECRET not set"); + } + const { authorization } = req.headers; if (!authorization) { diff --git a/src/Middleware/auth/teamleaderAuth.ts b/src/Middleware/auth/teamleaderAuth.ts index 489e8d3..9e8d358 100644 --- a/src/Middleware/auth/teamleaderAuth.ts +++ b/src/Middleware/auth/teamleaderAuth.ts @@ -1,7 +1,9 @@ import { Participant } from "@prisma/client"; import e, { NextFunction, Request, Response } from "express"; import jwt, { JsonWebTokenError } from "jsonwebtoken"; +import AuthError from "../error/AuthError"; import { getBearerToken, verifyAuthorizationFormat } from "./auth"; +import prisma from "../../lib/prisma"; export interface TeamleaderJWTPayload { pid: string; @@ -73,3 +75,23 @@ export async function requireTeamleaderAuthentication(req: Request, res: Respons throw e; } + +export function requireLeaderOfTeam(auth: TeamleaderJWTPayload | undefined, teamPid: string) { + if (auth?.team !== teamPid) { + throw new AuthError("The provided authorization is not valid for the requested team"); + } +} + +export async function requireResponsibleForParticipant(auth: TeamleaderJWTPayload | undefined, participantPid: string) { + if (!auth) { + throw new AuthError("There was an error with your authorization"); + } + + const teamPid = ( + await prisma.participant.findUnique({ where: { pid: participantPid }, select: { team: { select: { pid: true } } } }) + )?.team.pid; + + if (teamPid !== auth.team) { + throw new AuthError("The provided authorization is not valid for the requested participant"); + } +} diff --git a/src/Middleware/error/AuthError.ts b/src/Middleware/error/AuthError.ts new file mode 100644 index 0000000..0faae4c --- /dev/null +++ b/src/Middleware/error/AuthError.ts @@ -0,0 +1,13 @@ +import ForwardableError from "./ForwardableError"; + +export default class AuthError extends ForwardableError { + protected __oid = "AUTH_ERROR"; + + constructor(message?: string) { + super(403, message ?? "The request did not provide sufficient authentication"); + } + + static isAuthError(err: any): err is AuthError { + return err.__oid === "AUTH_ERROR"; + } +}