diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
deleted file mode 100644
index c00a959d..00000000
--- a/src/api/util/handlers/route.ts
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
- Copyright (C) 2023 Spacebar and Spacebar Contributors
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
-
-import { DiscordApiErrors, EVENT, FieldErrors, PermissionResolvable, Permissions, RightResolvable, Rights, SpacebarApiErrors, getPermission, getRights } from "@spacebar/util";
-import { AnyValidateFunction } from "ajv/dist/core";
-import { NextFunction, Request, Response } from "express";
-import { ajv } from "@spacebar/schemas";
-import { BigNumber } from "bignumber.js";
-
-const ignoredRequestSchemas = [
- // skip validation for settings proto JSON updates - TODO: figure out if this even possible to fix?
- "SettingsProtoUpdateJsonSchema",
-];
-
-declare global {
- // TODO: fix this
- // eslint-disable-next-line @typescript-eslint/no-namespace
- namespace Express {
- interface Request {
- permission?: Permissions;
- }
- }
-}
-
-export type RouteResponse = {
- status?: number;
- body?: `${string}Response`;
- headers?: Record<string, string>;
-};
-export type stripNulls = { [key: string]: true | stripNulls };
-export interface RouteOptions {
- permission?: PermissionResolvable;
- right?: RightResolvable;
- requestBody?: `${string}Schema`; // typescript interface name
- responses?: {
- [status: number]: {
- // body?: `${string}Response`;
- body?: string;
- };
- };
- stripNulls?: stripNulls | true;
- event?: EVENT | EVENT[];
- summary?: string;
- description?: string;
- query?: {
- [key: string]: {
- type: string;
- required?: boolean;
- description?: string;
- values?: string[];
- };
- };
- deprecated?: boolean;
- spacebarOnly?: boolean;
- // test?: {
- // response?: RouteResponse;
- // body?: unknown;
- // path?: string;
- // event?: EVENT | EVENT[];
- // headers?: Record<string, string>;
- // };
-}
-export function stripNull(obj: object) {
- for (const [key, value] of Object.entries(obj)) {
- if (value instanceof Object || (value && !value.__proto__)) {
- stripNull(value);
- } else if (value === null) {
- //@ts-expect-error this is fine
- delete obj[key];
- }
- }
-}
-// eslint-disable-next-line
-export function followNullPath(obj1: any, nullObj: stripNulls) {
- for (const [key, value] of Object.entries(nullObj)) {
- if (key in obj1)
- if (value instanceof Object) {
- if (obj1[key] instanceof Object)
- //@ts-expect-error this works lol
- followNullPath(obj1[key], nullObj[key]);
- else delete obj1[key];
- } else if (obj1[key] instanceof Object) {
- stripNull(obj1[key]);
- }
- }
-}
-//It's pretty safe to assume numbers over the number limit aren't really meant to be numbers, so we turn them to strings.
-export function bigNumberToString(obj1: unknown) {
- if (obj1 && typeof obj1 === "object") {
- for (const [key, value] of Object.entries(obj1)) {
- if (typeof value === "object") {
- if (value instanceof BigNumber) {
- //@ts-expect-error this is fine lol
- obj1[key] = value.toString();
- }
- bigNumberToString(value);
- }
- }
- }
-}
-export function route(opts: RouteOptions) {
- let validate: AnyValidateFunction | undefined;
- if (opts.requestBody) {
- try {
- validate = ajv.getSchema(opts.requestBody);
- } catch (e) {
- console.error("AJV getSchema failed!");
- throw e;
- }
-
- if (!validate) throw new Error(`Body schema ${opts.requestBody} not found`);
- }
-
- return async (req: Request, res: Response, next: NextFunction) => {
- 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);
-
- const requiredPerms = Array.isArray(opts.permission) ? opts.permission : [opts.permission];
- requiredPerms.forEach((perm) => {
- // bitfield comparison: check if user lacks certain permission
- if (!req.permission!.has(new Permissions(perm))) {
- throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(perm as string);
- }
- });
- }
-
- if (opts.right) {
- const required = new Rights(opts.right);
- req.rights = await getRights(req.user_id);
-
- if (!req.rights || !req.rights.has(required)) {
- throw SpacebarApiErrors.MISSING_RIGHTS.withParams(opts.right as string);
- }
- }
- bigNumberToString(req.body);
-
- if (validate && !ignoredRequestSchemas.includes(opts.requestBody!)) {
- if (opts.stripNulls) {
- if (opts.stripNulls === true) stripNull(req.body);
- else followNullPath(req.body, opts.stripNulls);
- }
-
- const valid = validate(req.body);
- if (!valid) {
- const fields: Record<string, { code?: string; message: string }> = {};
- validate.errors?.forEach(
- (x) =>
- (fields[x.instancePath.slice(1)] = {
- code: x.keyword,
- message: x.message || "",
- }),
- );
- if (process.env.LOG_VALIDATION_ERRORS) console.log(`[VALIDATION ERROR] ${req.method} ${req.originalUrl} - SCHEMA='${opts.requestBody}' -`, validate?.errors);
- throw FieldErrors(fields, validate.errors!);
- }
- }
- next();
- };
-}
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";
|