mirror of
https://github.com/detleph/server.git
synced 2026-09-04 00:26:03 +02:00
Add methods for requiring more specific levels of teamleader auth
+ Add AuthError
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 } } },
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user