mirror of
https://github.com/Steffo99/festa.git
synced 2024-12-23 15:14:23 +00:00
99 lines
3.1 KiB
TypeScript
99 lines
3.1 KiB
TypeScript
|
import { Response as Response } from "./throwables"
|
||
|
import { Token, User } from "@prisma/client"
|
||
|
import { database } from "../prismaClient"
|
||
|
|
||
|
/**
|
||
|
* Object containing multiple functions related to API authentication.
|
||
|
*
|
||
|
* @see {@link festaAPI} and its parameters {@link FestaAPI}.
|
||
|
*/
|
||
|
export type FestaAuthenticator<Config, Auth> = {
|
||
|
/**
|
||
|
* The value that the `WWW-Authenticate` header should be set to in a handler using this authenticator.
|
||
|
*/
|
||
|
header: string,
|
||
|
|
||
|
/**
|
||
|
* Async function which uses the value of the `Authorization` HTTP header to authenticate the user agent performing the API request.
|
||
|
*
|
||
|
* Any thrown {@link Error} should be caught by the handler, and its {@link Error.message} returned by the API.
|
||
|
*
|
||
|
* @param config - The current configuration of the request handler.
|
||
|
* @param header - The value of the `Authorization` HTTP header.
|
||
|
* @throws {ThrowableResponse}
|
||
|
*/
|
||
|
perform: (params: { config: Config, header: string | undefined }) => Promise<Auth>,
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* {@link FestaAuthenticator} which does not require any authentication.
|
||
|
*
|
||
|
* Never throws.
|
||
|
*/
|
||
|
export const festaNoAuth: FestaAuthenticator<any, {}> = {
|
||
|
header: "",
|
||
|
perform: async ({ }) => {
|
||
|
return {}
|
||
|
},
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Structure of the authentication data returned by the Festa API.
|
||
|
*/
|
||
|
export type FestaToken = Token & { user: User }
|
||
|
|
||
|
|
||
|
/**
|
||
|
* {@link FestaAuthenticator} which authenticates the user agent based on the value of its Bearer token.
|
||
|
*
|
||
|
* Returns the {@link FestaToken} if successful, or `undefined` if the Authorization header is missing.
|
||
|
*
|
||
|
* Throws an HTTP 401 error if the header is malformed or the token is invalid or expired.
|
||
|
*/
|
||
|
export const festaBearerAuthOptional: FestaAuthenticator<any, FestaToken | undefined> = {
|
||
|
header: "Bearer",
|
||
|
perform: async ({ header }) => {
|
||
|
if (!header || header === "false") {
|
||
|
return undefined
|
||
|
}
|
||
|
|
||
|
const token = header.match(/^Bearer (\S+)$/)?.[1]
|
||
|
|
||
|
if (!token) {
|
||
|
throw Response.error({ status: 401, message: "Malformed Authorization header" })
|
||
|
}
|
||
|
|
||
|
const dbToken = await database.token.findUnique({ where: { token }, include: { user: true } })
|
||
|
if (!dbToken) {
|
||
|
throw Response.error({ status: 401, message: "Invalid Authorization token" })
|
||
|
}
|
||
|
|
||
|
const now = new Date()
|
||
|
if (dbToken.expiresAt.getTime() < now.getTime()) {
|
||
|
throw Response.error({ status: 401, message: "Expired Authorization token" })
|
||
|
}
|
||
|
|
||
|
return dbToken
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@link FestaAuthenticator} which authenticates the user agent based on the value of its Bearer token.
|
||
|
*
|
||
|
* Returns the {@link FestaToken} if successful.
|
||
|
*
|
||
|
* Throws an HTTP 401 error if the header is missing or malformed, or the token is invalid or expired.
|
||
|
*/
|
||
|
export const festaBearerAuthRequired: FestaAuthenticator<any, FestaToken> = {
|
||
|
header: "Bearer",
|
||
|
perform: async (params) => {
|
||
|
if (!params.header) {
|
||
|
throw Response.error({ status: 401, message: "Missing Authorization header" })
|
||
|
}
|
||
|
|
||
|
return await festaBearerAuthOptional.perform(params) as FestaToken
|
||
|
}
|
||
|
}
|