81 lines
2.6 KiB
TypeScript
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();
|
|
};
|
|
};
|