import { Context, Env, MiddlewareHandler } from "hono"; import AuthorizationError from "../../Errors/AuthorizationError"; import { sessions } from "../../managers/sessions"; import { Variables } from "../../types/HonoTypes"; import GenericError from "../../Errors/GenericError"; import { events } from "../../modules/globalEvents"; /** * Authorization Middleware * * This middleware will do all of the authorization for all the routes that may need authorization. * It will check which auth type is being used and pull the correct credentials from said auth type and * supply them as a variable to the route. If there is an error thrown at any point in this middleware, it * will hault and will not proceed to the route handler. * * Eventually this method will analyze roles and permissions and supply those as objects to the route handler. * * ## Auth Types * - Bearer: Access Token for user authentication * - Key: API Key * * @param ctx - Hono Context Object * @param next - Move onto the handler */ export const authMiddleware = (permParams?: { permissions?: string[]; scopes?: string[]; forbiddenAuthTypes?: string[]; }): MiddlewareHandler<{ Variables: Variables; }> => { return async (ctx, next) => { const authorization = ctx.req.header()["authorization"]; if (!authorization) throw new AuthorizationError("Missing 'authorization' header."); const components = authorization.match( /^(Bearer|Key)\s([a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)$/, ); if (!components) throw new AuthorizationError( "Invalid or malformed authorization header...", ); const authType: string = components[1] ?? ""; const authValue: string = components[2] ?? ""; if (permParams?.forbiddenAuthTypes?.includes(authType)) throw new GenericError({ name: "NonpermittedAuthType", message: "The authorization method you are using is not permitted for this API request.", cause: `Type '${authType}' is not permitted.`, status: 403, }); if (authType) { const session = await sessions.fetch({ accessToken: authValue }); const user = await session.fetchUser(); ctx.set("user", user); if ( permParams?.permissions && permParams?.permissions.length > 0 && ( await Promise.all( permParams?.permissions.map((p) => user.hasPermission(p)), ) ).includes(false) ) throw new GenericError({ name: "InsufficentPermission", message: "You do not have sufficent permissions to do this.", status: 403, }); } await next(); }; };