diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index a71dfdf1..fe57880a 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -20,7 +20,7 @@ import { NextFunction, Request, Response } from "express";
import { HTTPError } from "lambert-server/HTTPError";
import { Session, User } from "@spacebar/database";
import { Random } from "@spacebar/extensions";
-import { checkToken, Rights, UserTokenData } from "@spacebar/util";
+import { checkToken, DiscordApiErrors, Rights, UserTokenData } from "@spacebar/util";
export const NO_AUTHORIZATION_ROUTES = [
// Authentication routes
@@ -77,6 +77,7 @@ declare global {
session?: Session;
rights: Rights;
fingerprint?: string;
+ isAuthenticated: boolean;
}
}
}
@@ -96,33 +97,16 @@ export async function Authentication(req: Request, res: Response, next: NextFunc
`__sb_sessid=${(req.fingerprint = Random.getString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 32))}; Secure; HttpOnly; SameSite=None; Path=/`,
);
- if (
- NO_AUTHORIZATION_ROUTES.some((x) => {
- if (typeof x !== "string") {
- return x.test(req.method + " " + url);
- }
+ await handleAuthentication(req);
- const fullRoute = req.method + " " + url;
-
- if (req.method === "HEAD") {
- const urlPart = x.split(" ").slice(1).join(" ");
- if (urlPart.endsWith("/")) {
- return url.startsWith(urlPart);
- } else {
- return url === urlPart;
- }
- }
-
- if (x.endsWith("/")) {
- return fullRoute.startsWith(x);
- } else {
- return fullRoute === x;
- }
- })
- )
- return next();
+ return next();
+}
- if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401));
+export async function handleAuthentication(req: Request) {
+ if (!req.headers.authorization) {
+ req.isAuthenticated = false;
+ return;
+ }
try {
const { decoded, user, session } = (req.tokenData = await checkToken(req.headers.authorization, {
@@ -136,11 +120,9 @@ export async function Authentication(req: Request, res: Response, next: NextFunc
req.user = user;
req.session = session;
req.rights = new Rights(Number(user.rights));
- return next();
- } catch (error) {
- if (error instanceof HTTPError) {
- return next(error);
- }
- return next(new HTTPError(error!.toString(), 400));
+ req.isAuthenticated = true;
+ } catch (e) {
+ req.isAuthenticated = false;
+ console.error("[Authentication] Token was provided, but was invalid:", e);
}
}
diff --git a/src/api/util/handlers/route.ts b/src/api/middlewares/Route.ts
index c00a959d..69c2b25e 100644
--- a/src/api/util/handlers/route.ts
+++ b/src/api/middlewares/Route.ts
@@ -74,6 +74,11 @@ export interface RouteOptions {
// event?: EVENT | EVENT[];
// headers?: Record<string, string>;
// };
+
+ /**
+ * @defaultValue "required"
+ */
+ authentication?: "never" | "optional" | "required";
}
export function stripNull(obj: object) {
for (const [key, value] of Object.entries(obj)) {
@@ -126,7 +131,11 @@ export function route(opts: RouteOptions) {
if (!validate) throw new Error(`Body schema ${opts.requestBody} not found`);
}
+ opts.authentication ??= "required";
+
return async (req: Request, res: Response, next: NextFunction) => {
+ if (opts.authentication === "required" && !req.isAuthenticated) throw DiscordApiErrors.UNAUTHORIZED;
+
if (opts.permission) {
const { guild_id, channel_id } = req.params as { [key: string]: string };
req.permission = await getPermission(req.user_id, guild_id, channel_id);
diff --git a/src/api/middlewares/index.ts b/src/api/middlewares/index.ts
index a2bb00b3..22651b53 100644
--- a/src/api/middlewares/index.ts
+++ b/src/api/middlewares/index.ts
@@ -22,4 +22,5 @@ export * from "./CORS";
export * from "./ErrorHandler";
export * from "./ImageProxy";
export * from "./RateLimit";
+export * from "./Route";
export * from "./Translation";
diff --git a/src/api/util/index.ts b/src/api/util/index.ts
index b57d263a..5fb5a684 100644
--- a/src/api/util/index.ts
+++ b/src/api/util/index.ts
@@ -19,7 +19,6 @@
export * from "./utility/ipAddress";
export * from "./handlers/Message";
export * from "./utility/passwordStrength";
-export * from "./handlers/route";
export * from "./handlers/Voice";
export * from "./utility/captcha";
export * from "./utility/EmbedHandlers";
|