Files
optima/src/api/middleware/authorization.ts
T

81 lines
2.6 KiB
TypeScript

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();
};
};