diff --git a/src/Middleware/auth/auth.ts b/src/Middleware/auth/auth.ts index 0b66952..6fb22eb 100644 --- a/src/Middleware/auth/auth.ts +++ b/src/Middleware/auth/auth.ts @@ -8,9 +8,9 @@ import prisma from "../../lib/prisma"; const JWT_SECRET = process.env.JWT_SECRET || "secret"; -const verifyAuthorizationFormat = (authorization: string) => /^Bearer .+$/.test(authorization); +export const verifyAuthorizationFormat = (authorization: string) => /^Bearer .+$/.test(authorization); -const getBearerToken = (authorization: string) => authorization.slice(7); +export const getBearerToken = (authorization: string) => authorization.slice(7); export const requireAuthentication = async (req: Request, res: Response, next: NextFunction) => { const { authorization } = req.headers; diff --git a/src/Middleware/auth/teamleaderAuth.ts b/src/Middleware/auth/teamleaderAuth.ts new file mode 100644 index 0000000..489e8d3 --- /dev/null +++ b/src/Middleware/auth/teamleaderAuth.ts @@ -0,0 +1,75 @@ +import { Participant } from "@prisma/client"; +import e, { NextFunction, Request, Response } from "express"; +import jwt, { JsonWebTokenError } from "jsonwebtoken"; +import { getBearerToken, verifyAuthorizationFormat } from "./auth"; + +export interface TeamleaderJWTPayload { + pid: string; + team: string; +} + +const JWT_SECRET = process.env.JWT_SECRET; + +export function generateTeamleaderJWT(teamleader: Participant & { relevance: "TEAMLEADER"; team: { pid: string } }) { + if (!JWT_SECRET) { + throw new Error("JWT_SECRET not set"); + } + + const payload: TeamleaderJWTPayload = { + pid: teamleader.pid, + team: teamleader.team.pid, + }; + + return jwt.sign(payload, JWT_SECRET, { expiresIn: "4 days" }); +} + +export async function requireTeamleaderAuthentication(req: Request, res: Response, next: NextFunction) { + if (!JWT_SECRET) { + throw new Error("JWT_SECRET not set"); + } + + const { authorization } = req.headers; + + if (!authorization) { + return res.status(403).send({ + type: "error", + payload: { + message: + "The request did not include the Authorization header (Only the team leader can perform this operation)", + }, + }); + } + + if (!verifyAuthorizationFormat(authorization)) { + return res.status(400).send({ + type: "error", + payload: { + message: "Malformed Authorization header", + format: "Bearer ", + }, + }); + } + + try { + const token_payload = jwt.verify(getBearerToken(authorization), JWT_SECRET) as TeamleaderJWTPayload; + + req.teamleader = { + isAuthenticated: true, + pid: token_payload.pid, + team: token_payload.team, + }; + + next(); + } 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; +} diff --git a/src/custom.d.ts b/src/custom.d.ts index bb6296a..86509ba 100644 --- a/src/custom.d.ts +++ b/src/custom.d.ts @@ -1,7 +1,9 @@ import { AuthJWTPayload } from "./Controllers/admin_auth.controller"; +import { TeamleaderJWTPayload } from "./Middleware/auth/teamleaderAuth"; declare module "express-serve-static-core" { interface Request { auth?: AuthJWTPayload & { isAuthenticated: boolean }; + teamleader?: TeamleaderJWTPayload & { isAuthenticated: boolean }; } }