120 lines
2.7 KiB
TypeScript
120 lines
2.7 KiB
TypeScript
import { decodeToken } from "#lib/auth/token.js";
|
|
import { hashPassword } from "#lib/password.js";
|
|
import { prisma } from "#lib/server/prisma.js";
|
|
import { APIError, TypesafeAPIContextWithRequest } from "astro-typesafe-api/server";
|
|
import { z } from "zod";
|
|
|
|
export async function checkAuthorizationHeaderNoThrow(authorization: string): Promise<ReturnType<typeof checkAuthorizationHeader> | null> {
|
|
try {
|
|
return await checkAuthorizationHeader(authorization)
|
|
} catch(e) {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function checkAuthorizationHeader(authorization: string) {
|
|
if (!authorization) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Request is missing an 'Authorization' header."
|
|
})
|
|
}
|
|
|
|
if (authorization.startsWith("Basic")) {
|
|
const payload = btoa(authorization.split(" ")[1]).split(":");
|
|
|
|
if (payload.length !== 2) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Malformed 'Authorization' header."
|
|
})
|
|
}
|
|
|
|
const [email, password] = payload;
|
|
|
|
const user = await prisma.benutzer.findUnique({
|
|
where: {
|
|
email
|
|
}
|
|
})
|
|
|
|
if (!user || user.passwort !== hashPassword(password)) {
|
|
throw new APIError({
|
|
code: "UNAUTHORIZED",
|
|
message: "Unknown combination of email and password."
|
|
})
|
|
}
|
|
|
|
return user;
|
|
} else if (authorization.startsWith("Bearer")) {
|
|
const token = authorization.split(" ")[1]
|
|
|
|
if (!token) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Malformed 'Authorization' header."
|
|
})
|
|
}
|
|
|
|
const payload = decodeToken(token)
|
|
|
|
if ((payload.exp || 0) < Date.now()) {
|
|
throw new APIError({
|
|
code: "UNAUTHORIZED",
|
|
message: "Access Token has expired."
|
|
})
|
|
}
|
|
|
|
const user = await prisma.benutzer.findUnique({
|
|
where: {
|
|
id: payload.id
|
|
}
|
|
})
|
|
|
|
if (!user) {
|
|
throw new APIError({
|
|
code: "UNAUTHORIZED",
|
|
message: "Invalid Bearer Token."
|
|
})
|
|
}
|
|
|
|
return user;
|
|
}
|
|
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Invalid authorization method in 'Authorization' header."
|
|
})
|
|
}
|
|
|
|
export async function authorizationMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {
|
|
return await checkAuthorizationHeader(ctx.request.headers.get("Authorization"));
|
|
}
|
|
|
|
export async function maybeAuthorizationMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {
|
|
try {
|
|
return authorizationMiddleware(input, ctx)
|
|
} catch(e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export const authorizationHeaders = {
|
|
Authorization: z.string()
|
|
}
|
|
|
|
export async function adminMiddleware(input: any, ctx: TypesafeAPIContextWithRequest<any>) {
|
|
try {
|
|
const user = await authorizationMiddleware(input, ctx)
|
|
|
|
if (user.rolle === "ADMIN") {
|
|
return user
|
|
}
|
|
} catch(e) {
|
|
}
|
|
|
|
throw new APIError({
|
|
code: "FORBIDDEN",
|
|
"message": "Diese Route ist für Admins vorbehalten."
|
|
})
|
|
} |