summary refs log tree commit diff
path: root/src/api
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-25 12:55:42 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-25 13:00:31 +1000
commitd946547a9233d866e793e1c68f11d98cb2f7d390 (patch)
tree2ff2677432e2e874f0784b115202f3846e68deb0 /src/api
parentMerge remote-tracking branch 'upstream/staging' into fix/categoryNames (diff)
parentMerge pull request #799 from MaddyUnderStars/feat/captchaVerify (diff)
downloadserver-d946547a9233d866e793e1c68f11d98cb2f7d390.tar.xz
Merge remote-tracking branch 'upstream/staging' into fix/categoryNames
Also allow voice to skip checks
Diffstat (limited to '')
-rw-r--r--src/api/Server.ts23
-rw-r--r--src/api/index.ts2
-rw-r--r--src/api/middlewares/Authentication.ts5
-rw-r--r--src/api/middlewares/BodyParser.ts2
-rw-r--r--src/api/middlewares/ErrorHandler.ts3
-rw-r--r--src/api/middlewares/RateLimit.ts9
-rw-r--r--src/api/middlewares/TestClient.ts71
-rw-r--r--src/api/middlewares/Translation.ts4
-rw-r--r--src/api/routes/-/healthz.ts2
-rw-r--r--src/api/routes/-/readyz.ts2
-rw-r--r--src/api/routes/applications/#id/bot/index.ts32
-rw-r--r--src/api/routes/applications/#id/entitlements.ts2
-rw-r--r--src/api/routes/applications/#id/index.ts17
-rw-r--r--src/api/routes/applications/#id/skus.ts5
-rw-r--r--src/api/routes/applications/detectable.ts2
-rw-r--r--src/api/routes/applications/index.ts12
-rw-r--r--src/api/routes/auth/location-metadata.ts15
-rw-r--r--src/api/routes/auth/login.ts30
-rw-r--r--src/api/routes/auth/mfa/totp.ts22
-rw-r--r--src/api/routes/auth/register.ts24
-rw-r--r--src/api/routes/channels/#channel_id/followers.ts2
-rw-r--r--src/api/routes/channels/#channel_id/index.ts9
-rw-r--r--src/api/routes/channels/#channel_id/invites.ts72
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/ack.ts5
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts2
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/index.ts112
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts82
-rw-r--r--src/api/routes/channels/#channel_id/messages/bulk-delete.ts7
-rw-r--r--src/api/routes/channels/#channel_id/messages/index.ts49
-rw-r--r--src/api/routes/channels/#channel_id/permissions.ts10
-rw-r--r--src/api/routes/channels/#channel_id/pins.ts14
-rw-r--r--src/api/routes/channels/#channel_id/purge.ts25
-rw-r--r--src/api/routes/channels/#channel_id/recipients.ts6
-rw-r--r--src/api/routes/channels/#channel_id/typing.ts4
-rw-r--r--src/api/routes/channels/#channel_id/webhooks.ts6
-rw-r--r--src/api/routes/discoverable-guilds.ts6
-rw-r--r--src/api/routes/discovery.ts4
-rw-r--r--src/api/routes/downloads.ts6
-rw-r--r--src/api/routes/experiments.ts4
-rw-r--r--src/api/routes/gateway/bot.ts4
-rw-r--r--src/api/routes/gateway/index.ts4
-rw-r--r--src/api/routes/gifs/search.ts10
-rw-r--r--src/api/routes/gifs/trending-gifs.ts10
-rw-r--r--src/api/routes/gifs/trending.ts15
-rw-r--r--src/api/routes/guild-recommendations.ts12
-rw-r--r--src/api/routes/guilds/#guild_id/audit-logs.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/bans.ts48
-rw-r--r--src/api/routes/guilds/#guild_id/channels.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/delete.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/discovery-requirements.ts50
-rw-r--r--src/api/routes/guilds/#guild_id/emojis.ts18
-rw-r--r--src/api/routes/guilds/#guild_id/index.ts29
-rw-r--r--src/api/routes/guilds/#guild_id/integrations.ts4
-rw-r--r--src/api/routes/guilds/#guild_id/invites.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/index.ts21
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/nick.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/members/index.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/premium.ts2
-rw-r--r--src/api/routes/guilds/#guild_id/prune.ts6
-rw-r--r--src/api/routes/guilds/#guild_id/regions.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/roles/#role_id/index.ts16
-rw-r--r--src/api/routes/guilds/#guild_id/roles/index.ts21
-rw-r--r--src/api/routes/guilds/#guild_id/stickers.ts9
-rw-r--r--src/api/routes/guilds/#guild_id/templates.ts14
-rw-r--r--src/api/routes/guilds/#guild_id/vanity-url.ts6
-rw-r--r--src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts13
-rw-r--r--src/api/routes/guilds/#guild_id/webhooks.ts4
-rw-r--r--src/api/routes/guilds/#guild_id/welcome_screen.ts5
-rw-r--r--src/api/routes/guilds/#guild_id/widget.json.ts6
-rw-r--r--src/api/routes/guilds/#guild_id/widget.png.ts21
-rw-r--r--src/api/routes/guilds/#guild_id/widget.ts4
-rw-r--r--src/api/routes/guilds/index.ts6
-rw-r--r--src/api/routes/guilds/templates/index.ts37
-rw-r--r--src/api/routes/invites/index.ts20
-rw-r--r--src/api/routes/oauth2/tokens.ts2
-rw-r--r--src/api/routes/outbound-promotions.ts2
-rw-r--r--src/api/routes/partners/#guild_id/requirements.ts51
-rw-r--r--src/api/routes/ping.ts6
-rw-r--r--src/api/routes/policies/instance/domains.ts17
-rw-r--r--src/api/routes/policies/instance/index.ts5
-rw-r--r--src/api/routes/policies/instance/limits.ts4
-rw-r--r--src/api/routes/scheduled-maintenances/upcoming_json.ts10
-rw-r--r--src/api/routes/science.ts2
-rw-r--r--src/api/routes/stage-instances.ts2
-rw-r--r--src/api/routes/sticker-packs/index.ts2
-rw-r--r--src/api/routes/stickers/#sticker_id/index.ts4
-rw-r--r--src/api/routes/stop.ts13
-rw-r--r--src/api/routes/store/published-listings/applications.ts2
-rw-r--r--src/api/routes/store/published-listings/applications/#id/subscription-plans.ts2
-rw-r--r--src/api/routes/store/published-listings/skus.ts2
-rw-r--r--src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts2
-rw-r--r--src/api/routes/teams.ts2
-rw-r--r--src/api/routes/track.ts2
-rw-r--r--src/api/routes/updates.ts14
-rw-r--r--src/api/routes/users/#id/index.ts4
-rw-r--r--src/api/routes/users/#id/profile.ts20
-rw-r--r--src/api/routes/users/#id/relationships.ts43
-rw-r--r--src/api/routes/users/@me/activities/statistics/applications.ts2
-rw-r--r--src/api/routes/users/@me/affinities/guilds.ts2
-rw-r--r--src/api/routes/users/@me/affinities/users.ts2
-rw-r--r--src/api/routes/users/@me/applications/#app_id/entitlements.ts2
-rw-r--r--src/api/routes/users/@me/billing/country-code.ts2
-rw-r--r--src/api/routes/users/@me/billing/payment-sources.ts2
-rw-r--r--src/api/routes/users/@me/billing/subscriptions.ts2
-rw-r--r--src/api/routes/users/@me/channels.ts4
-rw-r--r--src/api/routes/users/@me/connections.ts2
-rw-r--r--src/api/routes/users/@me/delete.ts14
-rw-r--r--src/api/routes/users/@me/devices.ts2
-rw-r--r--src/api/routes/users/@me/disable.ts13
-rw-r--r--src/api/routes/users/@me/email-settings.ts2
-rw-r--r--src/api/routes/users/@me/entitlements.ts2
-rw-r--r--src/api/routes/users/@me/guilds.ts5
-rw-r--r--src/api/routes/users/@me/guilds/premium/subscription-slots.ts2
-rw-r--r--src/api/routes/users/@me/index.ts44
-rw-r--r--src/api/routes/users/@me/library.ts2
-rw-r--r--src/api/routes/users/@me/mfa/codes.ts29
-rw-r--r--src/api/routes/users/@me/mfa/totp/disable.ts19
-rw-r--r--src/api/routes/users/@me/mfa/totp/enable.ts37
-rw-r--r--src/api/routes/users/@me/notes.ts27
-rw-r--r--src/api/routes/users/@me/relationships.ts39
-rw-r--r--src/api/routes/users/@me/settings.ts4
-rw-r--r--src/api/routes/voice/regions.ts5
-rw-r--r--src/api/start.ts8
-rw-r--r--src/api/util/entities/AssetCacheItem.ts2
-rw-r--r--src/api/util/handlers/Instance.ts3
-rw-r--r--src/api/util/handlers/Message.ts52
-rw-r--r--src/api/util/handlers/route.ts18
-rw-r--r--src/api/util/index.ts3
-rw-r--r--src/api/util/utility/RandomInviteID.ts7
-rw-r--r--src/api/util/utility/String.ts2
-rw-r--r--src/api/util/utility/captcha.ts46
-rw-r--r--src/api/util/utility/ipAddress.ts6
-rw-r--r--src/api/util/utility/passwordStrength.ts10
134 files changed, 967 insertions, 821 deletions
diff --git a/src/api/Server.ts b/src/api/Server.ts
index 136f9814..e92335a5 100644
--- a/src/api/Server.ts
+++ b/src/api/Server.ts
@@ -1,16 +1,16 @@
+import { Config, getOrInitialiseDatabase, initEvent, registerRoutes } from "@fosscord/util";
+import { NextFunction, Request, Response, Router } from "express";
 import { Server, ServerOptions } from "lambert-server";
+import morgan from "morgan";
+import path from "path";
+import { red } from "picocolors";
 import { Authentication, CORS } from "./middlewares/";
-import { Config, getOrInitialiseDatabase, initEvent, registerRoutes } from "@fosscord/util";
-import { ErrorHandler } from "./middlewares/ErrorHandler";
 import { BodyParser } from "./middlewares/BodyParser";
-import { Router, Request, Response, NextFunction } from "express";
-import path from "path";
+import { ErrorHandler } from "./middlewares/ErrorHandler";
 import { initRateLimits } from "./middlewares/RateLimit";
 import TestClient from "./middlewares/TestClient";
 import { initTranslation } from "./middlewares/Translation";
-import morgan from "morgan";
 import { initInstance } from "./util/handlers/Instance";
-import { red } from "picocolors"
 
 export interface FosscordServerOptions extends ServerOptions {}
 
@@ -85,8 +85,13 @@ export class FosscordServer extends Server {
 		this.app.use(ErrorHandler);
 		TestClient(this.app);
 
-		if (logRequests) console.log(red(`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`));
-		
+		if (logRequests)
+			console.log(
+				red(
+					`Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!`
+				)
+			);
+
 		return super.start();
 	}
-}
\ No newline at end of file
+}
diff --git a/src/api/index.ts b/src/api/index.ts
index adc7649c..5f97a463 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,3 +1,3 @@
-export * from "./Server";
 export * from "./middlewares/";
+export * from "./Server";
 export * from "./util/";
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts
index 2d9ccf57..6d063953 100644
--- a/src/api/middlewares/Authentication.ts
+++ b/src/api/middlewares/Authentication.ts
@@ -1,6 +1,5 @@
+import { checkToken, Config, HTTPError, Rights } from "@fosscord/util";
 import { NextFunction, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
-import { checkToken, Config, Rights } from "@fosscord/util";
 
 export const NO_AUTHORIZATION_ROUTES = [
 	// Authentication routes
@@ -10,7 +9,7 @@ export const NO_AUTHORIZATION_ROUTES = [
 	"/auth/mfa/totp",
 	// Routes with a seperate auth system
 	"/webhooks/",
-	// Public information endpoints 
+	// Public information endpoints
 	"/ping",
 	"/gateway",
 	"/experiments",
diff --git a/src/api/middlewares/BodyParser.ts b/src/api/middlewares/BodyParser.ts
index 35db3c6f..36d89da7 100644
--- a/src/api/middlewares/BodyParser.ts
+++ b/src/api/middlewares/BodyParser.ts
@@ -1,6 +1,6 @@
+import { HTTPError } from "@fosscord/util";
 import bodyParser, { OptionsJson } from "body-parser";
 import { NextFunction, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
 
 export function BodyParser(opts?: OptionsJson) {
 	const jsonParser = bodyParser.json(opts);
diff --git a/src/api/middlewares/ErrorHandler.ts b/src/api/middlewares/ErrorHandler.ts
index 8a046e06..813adc18 100644
--- a/src/api/middlewares/ErrorHandler.ts
+++ b/src/api/middlewares/ErrorHandler.ts
@@ -1,6 +1,5 @@
+import { ApiError, FieldError, HTTPError } from "@fosscord/util";
 import { NextFunction, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
-import { ApiError, FieldError } from "@fosscord/util";
 const EntityNotFoundErrorRegex = /"(\w+)"/;
 
 export function ErrorHandler(error: Error, req: Request, res: Response, next: NextFunction) {
diff --git a/src/api/middlewares/RateLimit.ts b/src/api/middlewares/RateLimit.ts
index 47180b62..dc93dcef 100644
--- a/src/api/middlewares/RateLimit.ts
+++ b/src/api/middlewares/RateLimit.ts
@@ -1,6 +1,6 @@
-import { Config, getRights, listenEvent, Rights } from "@fosscord/util";
-import { NextFunction, Request, Response, Router } from "express";
 import { getIpAdress } from "@fosscord/api";
+import { Config, getRights, listenEvent } from "@fosscord/util";
+import { NextFunction, Request, Response, Router } from "express";
 import { API_PREFIX_TRAILING_SLASH } from "./Authentication";
 
 // Docs: https://discord.com/developers/docs/topics/rate-limits
@@ -48,7 +48,7 @@ export default function rateLimit(opts: {
 		// exempt user? if so, immediately short circuit
 		if (req.user_id) {
 			const rights = await getRights(req.user_id);
-			if (rights.has("BYPASS_RATE_LIMITS")) return;
+			if (rights.has("BYPASS_RATE_LIMITS")) return next();
 		}
 
 		const bucket_id = opts.bucket || req.originalUrl.replace(API_PREFIX_TRAILING_SLASH, "");
@@ -121,6 +121,7 @@ export default function rateLimit(opts: {
 export async function initRateLimits(app: Router) {
 	const { routes, global, ip, error, disabled } = Config.get().limits.rate;
 	if (disabled) return;
+	console.log("Enabling rate limits...");
 	await listenEvent(EventRateLimit, (event) => {
 		Cache.set(event.channel_id as string, event.data);
 		event.acknowledge?.();
@@ -163,7 +164,7 @@ export async function initRateLimits(app: Router) {
 	app.use("/auth/register", rateLimit({ onlyIp: true, success: true, ...routes.auth.register }));
 }
 
-async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number; }) {
+async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number }) {
 	const id = opts.executor_id + opts.bucket_id;
 	let limit = Cache.get(id);
 	if (!limit) {
diff --git a/src/api/middlewares/TestClient.ts b/src/api/middlewares/TestClient.ts
index c8ea57f6..2784c8ab 100644
--- a/src/api/middlewares/TestClient.ts
+++ b/src/api/middlewares/TestClient.ts
@@ -1,17 +1,17 @@
-import express, { Request, Response, Application } from "express";
+import { Config } from "@fosscord/util";
+import express, { Application, Request, Response } from "express";
 import fs from "fs";
+import fetch, { Headers, Response as FetchResponse } from "node-fetch";
 import path from "path";
-import fetch, { Response as FetchResponse, Headers } from "node-fetch";
-import ProxyAgent from 'proxy-agent';
-import { Config } from "@fosscord/util";
-import { AssetCacheItem } from "../util/entities/AssetCacheItem"
 import { green } from "picocolors";
+import ProxyAgent from "proxy-agent";
+import { AssetCacheItem } from "../util/entities/AssetCacheItem";
 
-const AssetsPath = path.join(__dirname, "..", "..", "..", "assets")
+const AssetsPath = path.join(__dirname, "..", "..", "..", "assets");
 
 export default function TestClient(app: Application) {
 	const agent = new ProxyAgent();
-	
+
 	//build client page
 	let html = fs.readFileSync(path.join(AssetsPath, "index.html"), { encoding: "utf8" });
 	html = applyEnv(html);
@@ -22,31 +22,29 @@ export default function TestClient(app: Application) {
 	//load asset cache
 	let newAssetCache: Map<string, AssetCacheItem> = new Map<string, AssetCacheItem>();
 	let assetCacheDir = path.join(AssetsPath, "cache");
-	if(process.env.ASSET_CACHE_DIR)
-		assetCacheDir = process.env.ASSET_CACHE_DIR
+	if (process.env.ASSET_CACHE_DIR) assetCacheDir = process.env.ASSET_CACHE_DIR;
 
-	console.log(`[TestClient] ${green(`Using asset cache path: ${assetCacheDir}`)}`)
-	if(!fs.existsSync(assetCacheDir)) {
+	console.log(`[TestClient] ${green(`Using asset cache path: ${assetCacheDir}`)}`);
+	if (!fs.existsSync(assetCacheDir)) {
 		fs.mkdirSync(assetCacheDir);
 	}
-	if(fs.existsSync(path.join(assetCacheDir, "index.json"))) {
+	if (fs.existsSync(path.join(assetCacheDir, "index.json"))) {
 		let rawdata = fs.readFileSync(path.join(assetCacheDir, "index.json"));
 		newAssetCache = new Map<string, AssetCacheItem>(Object.entries(JSON.parse(rawdata.toString())));
 	}
 
-	app.use("/assets", express.static(path.join(AssetsPath)));	
+	app.use("/assets", express.static(path.join(AssetsPath)));
 	app.get("/assets/:file", async (req: Request, res: Response) => {
 		delete req.headers.host;
 		let response: FetchResponse;
 		let buffer: Buffer;
 		let assetCacheItem: AssetCacheItem = new AssetCacheItem(req.params.file);
-		if(newAssetCache.has(req.params.file)){
+		if (newAssetCache.has(req.params.file)) {
 			assetCacheItem = newAssetCache.get(req.params.file)!;
 			assetCacheItem.Headers.forEach((value: any, name: any) => {
 				res.set(name, value);
 			});
-		}
-		else {
+		} else {
 			console.log(`[TestClient] Downloading file not yet cached! Asset file: ${req.params.file}`);
 			response = await fetch(`https://discord.com/assets/${req.params.file}`, {
 				agent,
@@ -55,7 +53,7 @@ export default function TestClient(app: Application) {
 					...req.headers
 				}
 			});
-			
+
 			//set cache info
 			assetCacheItem.Headers = Object.fromEntries(stripHeaders(response.headers));
 			assetCacheItem.FilePath = path.join(assetCacheDir, req.params.file);
@@ -66,7 +64,7 @@ export default function TestClient(app: Application) {
 			//download file
 			fs.writeFileSync(assetCacheItem.FilePath, await response.buffer());
 		}
-		
+
 		assetCacheItem.Headers.forEach((value: string, name: string) => {
 			res.set(name, value);
 		});
@@ -77,8 +75,8 @@ export default function TestClient(app: Application) {
 		res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
 		res.set("content-type", "text/html");
 
-		if(!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.")
-		
+		if (!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.");
+
 		res.send(fs.readFileSync(path.join(__dirname, "..", "..", "..", "assets", "developers.html"), { encoding: "utf8" }));
 	});
 	app.get("*", (req: Request, res: Response) => {
@@ -86,23 +84,18 @@ export default function TestClient(app: Application) {
 		res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24);
 		res.set("content-type", "text/html");
 
-		if(req.url.startsWith("/api") || req.url.startsWith("/__development")) return;
+		if (req.url.startsWith("/api") || req.url.startsWith("/__development")) return;
 
-		if(!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.")
+		if (!useTestClient) return res.send("Test client is disabled on this instance. Use a stand-alone client to connect this instance.");
 		if (req.url.startsWith("/invite")) return res.send(html.replace("9b2b7f0632acd0c5e781", "9f24f709a3de09b67c49"));
-		
+
 		res.send(html);
 	});
-
-	
 }
 
 function applyEnv(html: string): string {
-	const CDN_ENDPOINT = (Config.get().cdn.endpointClient || Config.get()?.cdn.endpointPublic || process.env.CDN || "").replace(
-		/(https?)?(:\/\/?)/g,
-		""
-	);
-	const GATEWAY_ENDPOINT = Config.get().gateway.endpointClient || Config.get()?.gateway.endpointPublic || process.env.GATEWAY || "";
+	const CDN_ENDPOINT = (Config.get()?.cdn.endpointPublic || process.env.CDN || "").replace(/(https?)?(:\/\/?)/g, "");
+	const GATEWAY_ENDPOINT = Config.get()?.gateway.endpointPublic || process.env.GATEWAY || "";
 
 	if (CDN_ENDPOINT) {
 		html = html.replace(/CDN_HOST: .+/, `CDN_HOST: \`${CDN_ENDPOINT}\`,`);
@@ -117,23 +110,29 @@ function applyPlugins(html: string): string {
 	// plugins
 	let files = fs.readdirSync(path.join(AssetsPath, "plugins"));
 	let plugins = "";
-	files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script src='/assets/plugins/${x}'></script>\n`; });
+	files.forEach((x) => {
+		if (x.endsWith(".js")) plugins += `<script src='/assets/plugins/${x}'></script>\n`;
+	});
 	return html.replaceAll("<!-- plugin marker -->", plugins);
 }
 
-function applyInlinePlugins(html: string): string{
+function applyInlinePlugins(html: string): string {
 	// inline plugins
 	let files = fs.readdirSync(path.join(AssetsPath, "inline-plugins"));
 	let plugins = "";
-	files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script src='/assets/inline-plugins/${x}'></script>\n\n`; });
+	files.forEach((x) => {
+		if (x.endsWith(".js")) plugins += `<script src='/assets/inline-plugins/${x}'></script>\n\n`;
+	});
 	return html.replaceAll("<!-- inline plugin marker -->", plugins);
 }
 
-function applyPreloadPlugins(html: string): string{
+function applyPreloadPlugins(html: string): string {
 	//preload plugins
 	let files = fs.readdirSync(path.join(AssetsPath, "preload-plugins"));
 	let plugins = "";
-	files.forEach(x =>{if(x.endsWith(".js")) plugins += `<script>${fs.readFileSync(path.join(AssetsPath, "preload-plugins", x))}</script>\n`; });
+	files.forEach((x) => {
+		if (x.endsWith(".js")) plugins += `<script>${fs.readFileSync(path.join(AssetsPath, "preload-plugins", x))}</script>\n`;
+	});
 	return html.replaceAll("<!-- preload plugin marker -->", plugins);
 }
 
@@ -147,7 +146,7 @@ function stripHeaders(headers: Headers): Headers {
 		"expect-ct",
 		"access-control-allow-origin",
 		"content-encoding"
-	].forEach(headerName => {
+	].forEach((headerName) => {
 		headers.delete(headerName);
 	});
 	return headers;
diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts
index 64b03bf8..8e5e67e6 100644
--- a/src/api/middlewares/Translation.ts
+++ b/src/api/middlewares/Translation.ts
@@ -1,9 +1,9 @@
+import { Router } from "express";
 import fs from "fs";
-import path from "path";
 import i18next from "i18next";
 import i18nextMiddleware from "i18next-http-middleware";
 import i18nextBackend from "i18next-node-fs-backend";
-import { Router } from "express";
+import path from "path";
 
 export async function initTranslation(router: Router) {
 	const languages = fs.readdirSync(path.join(__dirname, "..", "..", "..", "assets", "locales"));
diff --git a/src/api/routes/-/healthz.ts b/src/api/routes/-/healthz.ts
index f7bcfebf..5dee9e86 100644
--- a/src/api/routes/-/healthz.ts
+++ b/src/api/routes/-/healthz.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 import { getConnection } from "typeorm";
 
 const router = Router();
diff --git a/src/api/routes/-/readyz.ts b/src/api/routes/-/readyz.ts
index f7bcfebf..5dee9e86 100644
--- a/src/api/routes/-/readyz.ts
+++ b/src/api/routes/-/readyz.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 import { getConnection } from "typeorm";
 
 const router = Router();
diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts
index 5cae5215..e663059e 100644
--- a/src/api/routes/applications/#id/bot/index.ts
+++ b/src/api/routes/applications/#id/bot/index.ts
@@ -1,14 +1,14 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { Application, Config, FieldErrors, generateToken, OrmUtils, Snowflake, trimSpecial, User, handleFile } from "@fosscord/util";
+import { Application, Config, FieldErrors, generateToken, handleFile, OrmUtils, trimSpecial, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
 import { verifyToken } from "node-2fa";
 
 const router: Router = Router();
 
 router.post("/", route({}), async (req: Request, res: Response) => {
-	const app = await Application.findOne({where: {id: req.params.id}});
-	if(!app) return res.status(404);
+	const app = await Application.findOne({ where: { id: req.params.id } });
+	if (!app) return res.status(404);
 	const username = trimSpecial(app.name);
 	const discriminator = await User.generateDiscriminator(username);
 	if (!discriminator) {
@@ -16,8 +16,8 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 		throw FieldErrors({
 			username: {
 				code: "USERNAME_TOO_MANY_USERS",
-				message: req?.t("auth:register.USERNAME_TOO_MANY_USERS"),
-			},
+				message: req?.t("auth:register.USERNAME_TOO_MANY_USERS")
+			}
 		});
 	}
 
@@ -47,37 +47,37 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 		flags: "0",
 		data: {
 			hash: null,
-			valid_tokens_since: new Date(),
+			valid_tokens_since: new Date()
 		},
 		settings: {},
 		extended_settings: {},
 		fingerprints: [],
-		notes: {},
+		notes: {}
 	});
 	await user.save();
 	app.bot = user;
 	await app.save();
-	res.send().status(204)
+	res.send().status(204);
 });
 
 router.post("/reset", route({}), async (req: Request, res: Response) => {
-	let bot = await User.findOne({where: {id: req.params.id}});
-	let owner = await User.findOne({where: {id: req.user_id}});
-	if(!bot) return res.status(404);
-	if(owner?.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) {
+	let bot = await User.findOne({ where: { id: req.params.id } });
+	let owner = await User.findOne({ where: { id: req.user_id } });
+	if (!bot) return res.status(404);
+	if (owner?.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) {
 		throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
 	}
 	bot.data = { hash: undefined, valid_tokens_since: new Date() };
 	await bot.save();
 	let token = await generateToken(bot.id);
-	res.json({token}).status(200);
+	res.json({ token }).status(200);
 });
 
 router.patch("/", route({}), async (req: Request, res: Response) => {
 	if (req.body.avatar) req.body.avatar = await handleFile(`/avatars/${req.params.id}`, req.body.avatar as string);
-	let app = OrmUtils.mergeDeep(await User.findOne({where: {id: req.params.id}}), req.body);
+	let app = OrmUtils.mergeDeep(await User.findOne({ where: { id: req.params.id } }), req.body);
 	await app.save();
 	res.json(app).status(200);
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/applications/#id/entitlements.ts b/src/api/routes/applications/#id/entitlements.ts
index cfcfe40f..26054eb0 100644
--- a/src/api/routes/applications/#id/entitlements.ts
+++ b/src/api/routes/applications/#id/entitlements.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts
index 0aced582..398227fd 100644
--- a/src/api/routes/applications/#id/index.ts
+++ b/src/api/routes/applications/#id/index.ts
@@ -1,22 +1,22 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
+import { Application, OrmUtils } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	let results = await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"] });
+	let results = await Application.findOne({ where: { id: req.params.id }, relations: ["owner", "bot"] });
 	res.json(results).status(200);
 });
 
 router.patch("/", route({}), async (req: Request, res: Response) => {
 	delete req.body.icon;
-	let app = OrmUtils.mergeDeep(await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"]}), req.body);
-	if(app.bot) {
-		app.bot.bio = req.body.description
+	let app = OrmUtils.mergeDeep(await Application.findOne({ where: { id: req.params.id }, relations: ["owner", "bot"] }), req.body);
+	if (app.bot) {
+		app.bot.bio = req.body.description;
 		app.bot?.save();
 	}
-	if(req.body.tags) app.tags = req.body.tags;
+	if (req.body.tags) app.tags = req.body.tags;
 	await app.save();
 	res.json(app).status(200);
 });
@@ -26,5 +26,4 @@ router.post("/delete", route({}), async (req: Request, res: Response) => {
 	res.send().status(200);
 });
 
-
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/applications/#id/skus.ts b/src/api/routes/applications/#id/skus.ts
index 5b667f36..df7ad4bb 100644
--- a/src/api/routes/applications/#id/skus.ts
+++ b/src/api/routes/applications/#id/skus.ts
@@ -1,6 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -8,4 +7,4 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	res.json([]).status(200);
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/applications/detectable.ts b/src/api/routes/applications/detectable.ts
index 28ce42da..f012a595 100644
--- a/src/api/routes/applications/detectable.ts
+++ b/src/api/routes/applications/detectable.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts
index 033dcc51..191833f2 100644
--- a/src/api/routes/applications/index.ts
+++ b/src/api/routes/applications/index.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util";
+import { Application, OrmUtils, trimSpecial, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -11,14 +11,14 @@ export interface ApplicationCreateSchema {
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	//TODO
-	let results = await Application.find({where: {owner: {id: req.user_id}}, relations: ["owner", "bot"] });
+	let results = await Application.find({ where: { owner: { id: req.user_id } }, relations: ["owner", "bot"] });
 	res.json(results).status(200);
 });
 
 router.post("/", route({}), async (req: Request, res: Response) => {
 	const body = req.body as ApplicationCreateSchema;
-	const user = await User.findOne({where: {id: req.user_id}})
-	if(!user) res.status(420);
+	const user = await User.findOne({ where: { id: req.user_id } });
+	if (!user) res.status(420);
 	let app = OrmUtils.mergeDeep(new Application(), {
 		name: trimSpecial(body.name),
 		description: "",
@@ -31,4 +31,4 @@ router.post("/", route({}), async (req: Request, res: Response) => {
 	res.json(app).status(200);
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/auth/location-metadata.ts b/src/api/routes/auth/location-metadata.ts
index f4c2bd16..b8caf579 100644
--- a/src/api/routes/auth/location-metadata.ts
+++ b/src/api/routes/auth/location-metadata.ts
@@ -1,13 +1,12 @@
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
-import { getIpAdress, IPAnalysis } from "@fosscord/api";
+import { getIpAdress, IPAnalysis, route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
-    //TODO
-    //Note: It's most likely related to legal. At the moment Discord hasn't finished this too
-    const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
-	res.json({ consent_required: false, country_code: country_code, promotional_email_opt_in: { required: true, pre_checked: false}});
+router.get("/", route({}), async (req: Request, res: Response) => {
+	//TODO
+	//Note: It's most likely related to legal. At the moment Discord hasn't finished this too
+	const country_code = (await IPAnalysis(getIpAdress(req))).country_code;
+	res.json({ consent_required: false, country_code: country_code, promotional_email_opt_in: { required: true, pre_checked: false } });
 });
 
 export default router;
diff --git a/src/api/routes/auth/login.ts b/src/api/routes/auth/login.ts
index 9fc5924d..68b2656a 100644
--- a/src/api/routes/auth/login.ts
+++ b/src/api/routes/auth/login.ts
@@ -1,21 +1,29 @@
 import { Request, Response, Router } from "express";
-import { route } from "@fosscord/api";
-import bcrypt from "bcrypt";
+import { route, getIpAdress, verifyCaptcha } from "@fosscord/api";
 import { Config, User, generateToken, adjustEmail, FieldErrors, LoginSchema } from "@fosscord/util";
 import crypto from "crypto";
 
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
+
 const router: Router = Router();
 export default router;
 
 router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Response) => {
 	const { login, password, captcha_key, undelete } = req.body as LoginSchema;
 	const email = adjustEmail(login);
+	const ip = getIpAdress(req);
 
 	const config = Config.get();
 
 	if (config.login.requireCaptcha && config.security.captcha.enabled) {
+		const { sitekey, service } = config.security.captcha;
 		if (!captcha_key) {
-			const { sitekey, service } = config.security.captcha;
 			return res.status(400).json({
 				captcha_key: ["captcha-required"],
 				captcha_sitekey: sitekey,
@@ -23,7 +31,15 @@ router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Respo
 			});
 		}
 
-		// TODO: check captcha
+		const ip = getIpAdress(req);
+		const verify = await verifyCaptcha(captcha_key, ip);
+		if (!verify.success) {
+			return res.status(400).json({
+				captcha_key: verify["error-codes"],
+				captcha_sitekey: sitekey,
+				captcha_service: service
+			})
+		}
 	}
 
 	const user = await User.findOneOrFail({
@@ -57,9 +73,9 @@ router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Respo
 		return res.json({
 			ticket: ticket,
 			mfa: true,
-			sms: false,	// TODO
-			token: null,
-		})
+			sms: false, // TODO
+			token: null
+		});
 	}
 
 	const token = await generateToken(user.id);
diff --git a/src/api/routes/auth/mfa/totp.ts b/src/api/routes/auth/mfa/totp.ts
index 421dbafa..9938569e 100644
--- a/src/api/routes/auth/mfa/totp.ts
+++ b/src/api/routes/auth/mfa/totp.ts
@@ -1,8 +1,8 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { BackupCode, FieldErrors, generateToken, TotpSchema, User } from "@fosscord/util";
-import { verifyToken } from "node-2fa";
+import { BackupCode, generateToken, TotpSchema, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
+import { verifyToken } from "node-2fa";
 const router = Router();
 
 router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Response) => {
@@ -10,23 +10,17 @@ router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Respon
 
 	const user = await User.findOneOrFail({
 		where: {
-			totp_last_ticket: ticket,
+			totp_last_ticket: ticket
 		},
-		select: [
-			"id",
-			"totp_secret",
-			"settings",
-		],
+		select: ["id", "totp_secret", "settings"]
 	});
 
 	const backup = await BackupCode.findOne({ where: { code: code, expired: false, consumed: false, user: { id: user.id } } });
 
 	if (!backup) {
 		const ret = verifyToken(user.totp_secret!, code);
-		if (!ret || ret.delta != 0)
-			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-	}
-	else {
+		if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+	} else {
 		backup.consumed = true;
 		await backup.save();
 	}
@@ -35,7 +29,7 @@ router.post("/", route({ body: "TotpSchema" }), async (req: Request, res: Respon
 
 	return res.json({
 		token: await generateToken(user.id),
-		user_settings: user.settings,
+		user_settings: user.settings
 	});
 });
 
diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts
index 09366a12..d3b5a59c 100644
--- a/src/api/routes/auth/register.ts
+++ b/src/api/routes/auth/register.ts
@@ -1,7 +1,14 @@
 import { Request, Response, Router } from "express";
-import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, trimSpecial, RegisterSchema } from "@fosscord/util";
-import { route, getIpAdress, IPAnalysis, isProxy } from "@fosscord/api";
-import bcrypt from "bcrypt";
+import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, RegisterSchema } from "@fosscord/util";
+import { route, getIpAdress, IPAnalysis, isProxy, verifyCaptcha } from "@fosscord/api";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 import { HTTPError } from "@fosscord/util";
 
 const router: Router = Router();
@@ -38,8 +45,8 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re
 	}
 
 	if (register.requireCaptcha && security.captcha.enabled) {
+		const { sitekey, service } = security.captcha;
 		if (!body.captcha_key) {
-			const { sitekey, service } = security.captcha;
 			return res?.status(400).json({
 				captcha_key: ["captcha-required"],
 				captcha_sitekey: sitekey,
@@ -47,7 +54,14 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re
 			});
 		}
 
-		// TODO: check captcha
+		const verify = await verifyCaptcha(body.captcha_key, ip);
+		if (!verify.success) {
+			return res.status(400).json({
+				captcha_key: verify["error-codes"],
+				captcha_sitekey: sitekey,
+				captcha_service: service
+			})
+		}
 	}
 
 	if (!register.allowMultipleAccounts) {
diff --git a/src/api/routes/channels/#channel_id/followers.ts b/src/api/routes/channels/#channel_id/followers.ts
index 641af4f8..c06db61b 100644
--- a/src/api/routes/channels/#channel_id/followers.ts
+++ b/src/api/routes/channels/#channel_id/followers.ts
@@ -1,4 +1,4 @@
-import { Router, Response, Request } from "express";
+import { Router } from "express";
 const router: Router = Router();
 // TODO:
 
diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts
index bb8b868b..a65cf451 100644
--- a/src/api/routes/channels/#channel_id/index.ts
+++ b/src/api/routes/channels/#channel_id/index.ts
@@ -1,17 +1,16 @@
+import { route } from "@fosscord/api";
 import {
 	Channel,
 	ChannelDeleteEvent,
-	ChannelPermissionOverwriteType,
+	ChannelModifySchema,
 	ChannelType,
 	ChannelUpdateEvent,
 	emitEvent,
-	Recipient,
 	handleFile,
-	ChannelModifySchema
+	OrmUtils,
+	Recipient
 } from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
 
 const router: Router = Router();
 // TODO: delete channel
diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts
index b5c65c0d..3a1d2666 100644
--- a/src/api/routes/channels/#channel_id/invites.ts
+++ b/src/api/routes/channels/#channel_id/invites.ts
@@ -1,45 +1,45 @@
-import { Router, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { random } from "@fosscord/api";
-import { Channel, Invite, InviteCreateEvent, emitEvent, User, Guild, PublicInviteRelation } from "@fosscord/util";
+import { Channel, emitEvent, Guild, HTTPError, Invite, InviteCreateEvent, OrmUtils, PublicInviteRelation, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { isTextChannel } from "./messages";
-import { OrmUtils } from "@fosscord/util";
 
 const router: Router = Router();
 
-router.post("/", route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE", right: "CREATE_INVITES" }),
-			async (req: Request, res: Response) => {
-	const { user_id } = req;
-	const { channel_id } = req.params;
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
-	isTextChannel(channel.type);
-
-	if (!channel.guild_id) {
-		throw new HTTPError("This channel doesn't exist", 404);
+router.post(
+	"/",
+	route({ body: "InviteCreateSchema", permission: "CREATE_INSTANT_INVITE", right: "CREATE_INVITES" }),
+	async (req: Request, res: Response) => {
+		const { user_id } = req;
+		const { channel_id } = req.params;
+		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, select: ["id", "name", "type", "guild_id"] });
+		isTextChannel(channel.type);
+
+		if (!channel.guild_id) {
+			throw new HTTPError("This channel doesn't exist", 404);
+		}
+		const { guild_id } = channel;
+
+		const expires_at = new Date(req.body.max_age * 1000 + Date.now());
+
+		const invite = await OrmUtils.mergeDeep(new Invite(), {
+			temporary: req.body.temporary || true,
+			max_uses: req.body.max_uses,
+			max_age: req.body.max_age,
+			expires_at,
+			guild_id,
+			channel_id,
+			inviter_id: user_id
+		}).save();
+		//TODO: check this, removed toJSON call
+		const data = JSON.parse(JSON.stringify(invite));
+		data.inviter = await User.getPublicUser(req.user_id);
+		data.guild = await Guild.findOne({ where: { id: guild_id } });
+		data.channel = channel;
+
+		await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
+		res.status(201).send(data);
 	}
-	const { guild_id } = channel;
-
-	const expires_at = new Date(req.body.max_age * 1000 + Date.now());
-
-	const invite = await OrmUtils.mergeDeep(new Invite(),{
-		temporary: req.body.temporary || true,
-		max_uses: req.body.max_uses,
-		max_age: req.body.max_age,
-		expires_at,
-		guild_id,
-		channel_id,
-		inviter_id: user_id
-	}).save();
-	//TODO: check this, removed toJSON call
-	const data = JSON.parse(JSON.stringify(invite));
-	data.inviter = await User.getPublicUser(req.user_id);
-	data.guild = await Guild.findOne({ where: { id: guild_id } });
-	data.channel = channel;
-
-	await emitEvent({ event: "INVITE_CREATE", data, guild_id } as InviteCreateEvent);
-	res.status(201).send(data);
-});
+);
 
 router.get("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => {
 	const { channel_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
index 041f4d5e..5ebeed49 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/ack.ts
@@ -1,7 +1,6 @@
-import { emitEvent, getPermission, MessageAckEvent, ReadState, Snowflake } from "@fosscord/util";
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import { emitEvent, getPermission, MessageAckEvent, OrmUtils, ReadState } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
index b2cb6763..fbbc65f0 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
index d7e27062..b082e083 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -1,25 +1,22 @@
+import { handleMessage, postHandleMessage, route } from "@fosscord/api";
 import {
 	Attachment,
 	Channel,
-	Embed,
-	DiscordApiErrors,
 	emitEvent,
 	FosscordApiErrors,
 	getPermission,
 	getRights,
- 	Message,
+	HTTPError,
+	Message,
 	MessageCreateEvent,
+	MessageCreateSchema,
 	MessageDeleteEvent,
 	MessageUpdateEvent,
 	Snowflake,
-	uploadFile, 
-	MessageCreateSchema
+	uploadFile
 } from "@fosscord/util";
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
 import multer from "multer";
-import { route } from "@fosscord/api";
-import { handleMessage, postHandleMessage } from "@fosscord/api";
-import { HTTPError } from "@fosscord/util";
 
 const router = Router();
 // TODO: message content/embed string length limit
@@ -33,50 +30,53 @@ const messageUpload = multer({
 	storage: multer.memoryStorage()
 }); // max upload 50 mb
 
-router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id } = req.params;
-	let body = req.body as MessageCreateSchema;
+router.patch(
+	"/",
+	route({ body: "MessageCreateSchema", permission: "SEND_MESSAGES", right: "SEND_MESSAGES" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id } = req.params;
+		let body = req.body as MessageCreateSchema;
 
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
+		const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
 
-	const permissions = await getPermission(req.user_id, undefined, channel_id);
-	
-	const rights = await getRights(req.user_id);
+		const permissions = await getPermission(req.user_id, undefined, channel_id);
 
-	if ((req.user_id !== message.author_id)) {
-		if (!rights.has("MANAGE_MESSAGES")) {
-			permissions.hasThrow("MANAGE_MESSAGES");
-			body = { flags: body.flags };
-// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
-		}
-	} else rights.hasThrow("SELF_EDIT_MESSAGES");
-
-	const new_message = await handleMessage({
-		...message,
-		// TODO: should message_reference be overridable?
-		// @ts-ignore
-		message_reference: message.message_reference,
-		...body,
-		author_id: message.author_id,
-		channel_id,
-		id: message_id,
-		edited_timestamp: new Date()
-	});
-
-	await Promise.all([
-		new_message!.save(),
-		await emitEvent({
-			event: "MESSAGE_UPDATE",
+		const rights = await getRights(req.user_id);
+
+		if (req.user_id !== message.author_id) {
+			if (!rights.has("MANAGE_MESSAGES")) {
+				permissions.hasThrow("MANAGE_MESSAGES");
+				body = { flags: body.flags };
+				// guild admins can only suppress embeds of other messages, no such restriction imposed to instance-wide admins
+			}
+		} else rights.hasThrow("SELF_EDIT_MESSAGES");
+
+		const new_message = await handleMessage({
+			...message,
+			// TODO: should message_reference be overridable?
+			// @ts-ignore
+			message_reference: message.message_reference,
+			...body,
+			author_id: message.author_id,
 			channel_id,
-			data: { ...new_message, nonce: undefined }
-		} as MessageUpdateEvent)
-	]);
+			id: message_id,
+			edited_timestamp: new Date()
+		});
 
-	postHandleMessage(message);
+		await Promise.all([
+			new_message!.save(),
+			await emitEvent({
+				event: "MESSAGE_UPDATE",
+				channel_id,
+				data: { ...new_message, nonce: undefined }
+			} as MessageUpdateEvent)
+		]);
 
-	return res.json(message);
-});
+		postHandleMessage(message);
 
+		return res.json(message);
+	}
+);
 
 // Backfill message with specific timestamp
 router.put(
@@ -94,7 +94,7 @@ router.put(
 		const { channel_id, message_id } = req.params;
 		let body = req.body as MessageCreateSchema;
 		const attachments: Attachment[] = [];
-		
+
 		const rights = await getRights(req.user_id);
 		rights.hasThrow("SEND_MESSAGES");
 
@@ -103,13 +103,13 @@ router.put(
 			throw new HTTPError("Message IDs must be positive integers", 400);
 		}
 
-		const snowflake = Snowflake.deconstruct(message_id)
+		const snowflake = Snowflake.deconstruct(message_id);
 		if (Date.now() < snowflake.timestamp) {
 			// message is in the future
 			throw FosscordApiErrors.CANNOT_BACKFILL_TO_THE_FUTURE;
 		}
 
-		const exists = await Message.findOne({ where: { id: message_id, channel_id: channel_id }});
+		const exists = await Message.findOne({ where: { id: message_id, channel_id: channel_id } });
 		if (exists) {
 			throw FosscordApiErrors.CANNOT_REPLACE_BY_BACKFILL;
 		}
@@ -136,19 +136,19 @@ router.put(
 			channel_id,
 			attachments,
 			edited_timestamp: undefined,
-			timestamp: new Date(snowflake.timestamp),
+			timestamp: new Date(snowflake.timestamp)
 		});
 
 		//Fix for the client bug
-		delete message.member
-		
+		delete message.member;
+
 		await Promise.all([
 			message.save(),
 			emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
 			channel.save()
 		]);
 
-		postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
 
 		return res.json(message);
 	}
@@ -160,7 +160,7 @@ router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res:
 	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, relations: ["attachments"] });
 
 	const permissions = await getPermission(req.user_id, undefined, channel_id);
-	
+
 	if (message.author_id !== req.user_id) permissions.hasThrow("READ_MESSAGE_HISTORY");
 
 	return res.json(message);
@@ -171,10 +171,10 @@ router.delete("/", route({}), async (req: Request, res: Response) => {
 
 	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
 	const message = await Message.findOneOrFail({ where: { id: message_id } });
-	
+
 	const rights = await getRights(req.user_id);
 
-	if ((message.author_id !== req.user_id)) {
+	if (message.author_id !== req.user_id) {
 		if (!rights.has("MANAGE_MESSAGES")) {
 			const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
 			permission.hasThrow("MANAGE_MESSAGES");
diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
index d0ab35bb..44de5c45 100644
--- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
+++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts
@@ -1,8 +1,10 @@
+import { route } from "@fosscord/api";
 import {
 	Channel,
 	emitEvent,
 	Emoji,
 	getPermission,
+	HTTPError,
 	Member,
 	Message,
 	MessageReactionAddEvent,
@@ -13,9 +15,7 @@ import {
 	PublicUserProjection,
 	User
 } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { Router, Response, Request } from "express";
-import { HTTPError } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { In } from "typeorm";
 
 const router = Router();
@@ -101,48 +101,52 @@ router.get("/:emoji", route({ permission: "VIEW_CHANNEL" }), async (req: Request
 	res.json(users);
 });
 
-router.put("/:emoji/:user_id", route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }), async (req: Request, res: Response) => {
-	const { message_id, channel_id, user_id } = req.params;
-	if (user_id !== "@me") throw new HTTPError("Invalid user");
-	const emoji = getEmoji(req.params.emoji);
-
-	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
-	const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
-	const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
-
-	if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
-
-	if (emoji.id) {
-		const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id } });
-		if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
-		emoji.animated = external_emoji.animated;
-		emoji.name = external_emoji.name;
-	}
+router.put(
+	"/:emoji/:user_id",
+	route({ permission: "READ_MESSAGE_HISTORY", right: "SELF_ADD_REACTIONS" }),
+	async (req: Request, res: Response) => {
+		const { message_id, channel_id, user_id } = req.params;
+		if (user_id !== "@me") throw new HTTPError("Invalid user");
+		const emoji = getEmoji(req.params.emoji);
+
+		const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
+		const message = await Message.findOneOrFail({ where: { id: message_id, channel_id } });
+		const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name);
+
+		if (!already_added) req.permission!.hasThrow("ADD_REACTIONS");
+
+		if (emoji.id) {
+			const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id } });
+			if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS");
+			emoji.animated = external_emoji.animated;
+			emoji.name = external_emoji.name;
+		}
 
-	if (already_added) {
-		if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
-		already_added.count++;
-	} else message.reactions.push({ count: 1, emoji, user_ids: [req.user_id] });
+		if (already_added) {
+			if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error
+			already_added.count++;
+		} else message.reactions.push({ count: 1, emoji, user_ids: [req.user_id] });
 
-	await message.save();
+		await message.save();
 
-	const member = channel.guild_id && (await Member.findOneOrFail({ where: { id: req.user_id } }));
+		const member = channel.guild_id && (await Member.findOneOrFail({ where: { id: req.user_id } }));
 
-	await emitEvent({
-		event: "MESSAGE_REACTION_ADD",
-		channel_id,
-		data: {
-			user_id: req.user_id,
+		await emitEvent({
+			event: "MESSAGE_REACTION_ADD",
 			channel_id,
-			message_id,
-			guild_id: channel.guild_id,
-			emoji,
-			member
-		}
-	} as MessageReactionAddEvent);
+			data: {
+				user_id: req.user_id,
+				channel_id,
+				message_id,
+				guild_id: channel.guild_id,
+				emoji,
+				member
+			}
+		} as MessageReactionAddEvent);
 
-	res.sendStatus(204);
-});
+		res.sendStatus(204);
+	}
+);
 
 router.delete("/:emoji/:user_id", route({}), async (req: Request, res: Response) => {
 	let { message_id, channel_id, user_id } = req.params;
diff --git a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
index af44b522..561a40c0 100644
--- a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
+++ b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts
@@ -1,7 +1,6 @@
-import { Router, Response, Request } from "express";
-import { Channel, Config, emitEvent, getPermission, getRights, MessageDeleteBulkEvent, Message } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Channel, Config, emitEvent, getPermission, getRights, HTTPError, Message, MessageDeleteBulkEvent } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { In } from "typeorm";
 
 const router: Router = Router();
@@ -13,7 +12,7 @@ export default router;
 // https://discord.com/developers/docs/resources/channel#bulk-delete-messages
 router.post("/", route({ body: "BulkDeleteSchema" }), async (req: Request, res: Response) => {
 	const { channel_id } = req.params;
-	const channel = await Channel.findOneOrFail({where:{ id: channel_id} });
+	const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
 	if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
 
 	const rights = await getRights(req.user_id);
diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index 9ab0d97d..5fdcb6f9 100644
--- a/src/api/routes/channels/#channel_id/messages/index.ts
+++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -1,4 +1,4 @@
-import { Router, Response, Request } from "express";
+import { handleMessage, postHandleMessage, route } from "@fosscord/api";
 import {
 	Attachment,
 	Channel,
@@ -7,16 +7,15 @@ import {
 	DmChannelDTO,
 	emitEvent,
 	getPermission,
-	getRights,
+	HTTPError,
+	Member,
 	Message,
 	MessageCreateEvent,
+	MessageCreateSchema,
 	Snowflake,
-	uploadFile,
-	Member,
-	MessageCreateSchema
+	uploadFile
 } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
-import { handleMessage, postHandleMessage, route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 import multer from "multer";
 import { FindManyOptions, LessThan, MoreThan } from "typeorm";
 import { URL } from "url";
@@ -69,23 +68,20 @@ router.get("/", async (req: Request, res: Response) => {
 	permissions.hasThrow("VIEW_CHANNEL");
 	if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]);
 
-	let query: FindManyOptions<Message> & { where: { id?: any; }; } = {
+	let query: FindManyOptions<Message> & { where: { id?: any } } = {
 		order: { id: "DESC" },
 		take: limit,
 		where: { channel_id },
 		relations: ["author", "webhook", "application", "mentions", "mention_roles", "mention_channels", "sticker_items", "attachments"]
 	};
-	
 
 	if (after) {
 		if (after > new Snowflake()) return res.status(422);
 		query.where.id = MoreThan(after);
-	}
-	else if (before) { 
+	} else if (before) {
 		if (before < req.params.channel_id) return res.status(422);
 		query.where.id = LessThan(before);
-	}
-	else if (around) {
+	} else if (around) {
 		query.where.id = [
 			MoreThan((BigInt(around) - BigInt(halfLimit)).toString()),
 			LessThan((BigInt(around) + BigInt(halfLimit)).toString())
@@ -110,15 +106,14 @@ router.get("/", async (req: Request, res: Response) => {
 				const uri = y.proxy_url.startsWith("http") ? y.proxy_url : `https://example.org${y.proxy_url}`;
 				y.proxy_url = `${endpoint == null ? "" : endpoint}${new URL(uri).pathname}`;
 			});
-			
+
 			/**
 			Some clients ( discord.js ) only check if a property exists within the response,
 			which causes erorrs when, say, the `application` property is `null`.
 			**/
-			
+
 			for (let curr in x) {
-				if (x[curr] === null)
-					delete x[curr];
+				if (x[curr] === null) delete x[curr];
 			}
 
 			return x;
@@ -130,7 +125,7 @@ router.get("/", async (req: Request, res: Response) => {
 const messageUpload = multer({
 	limits: {
 		fileSize: 1024 * 1024 * 100,
-		fields: 10,
+		fields: 10
 		// files: 1
 	},
 	storage: multer.memoryStorage()
@@ -162,16 +157,15 @@ router.post(
 
 		const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] });
 		if (!channel.isWritable()) {
-			throw new HTTPError(`Cannot send messages to channel of type ${channel.type}`, 400)
+			throw new HTTPError(`Cannot send messages to channel of type ${channel.type}`, 400);
 		}
 
-		const files = req.files as Express.Multer.File[] ?? [];
+		const files = (req.files as Express.Multer.File[]) ?? [];
 		for (let currFile of files) {
 			try {
 				const file: any = await uploadFile(`/attachments/${channel.id}`, currFile);
 				attachments.push({ ...file, proxy_url: file.url });
-			}
-			catch (error) {
+			} catch (error) {
 				return res.status(400).json(error);
 			}
 		}
@@ -212,11 +206,11 @@ router.post(
 				})
 			);
 		}
-	
-	    //Defining member fields
+
+		//Defining member fields
 		var member = await Member.findOneOrFail({ where: { id: req.user_id }, relations: ["roles"] });
 		// TODO: This doesn't work either
-        // member.roles = member.roles.filter((role) => {
+		// member.roles = member.roles.filter((role) => {
 		// 	return role.id !== role.guild_id;
 		// }).map((role) => {
 		// 	return role.id;
@@ -225,7 +219,7 @@ router.post(
 		// TODO: Figure this out
 		// delete message.member.last_message_id;
 		// delete message.member.index;
-		
+
 		await Promise.all([
 			message.save(),
 			emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent),
@@ -233,9 +227,8 @@ router.post(
 			channel.save()
 		]);
 
-		postHandleMessage(message).catch((e) => { }); // no await as it shouldnt block the message send function and silently catch error
+		postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error
 
 		return res.json(message);
 	}
 );
-
diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts
index 34052fe5..bd462ea6 100644
--- a/src/api/routes/channels/#channel_id/permissions.ts
+++ b/src/api/routes/channels/#channel_id/permissions.ts
@@ -1,17 +1,15 @@
+import { route } from "@fosscord/api";
 import {
 	Channel,
 	ChannelPermissionOverwrite,
 	ChannelPermissionOverwriteSchema,
-	ChannelPermissionOverwriteType,
 	ChannelUpdateEvent,
 	emitEvent,
-	getPermission,
+	HTTPError,
 	Member,
 	Role
 } from "@fosscord/util";
-import { Router, Response, Request } from "express";
-import { HTTPError } from "@fosscord/util";
-import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -22,7 +20,7 @@ router.put(
 		const { channel_id, overwrite_id } = req.params;
 		const body = req.body as ChannelPermissionOverwriteSchema;
 
-		let channel = await Channel.findOneOrFail({ where: {id: channel_id} });
+		let channel = await Channel.findOneOrFail({ where: { id: channel_id } });
 		if (!channel.guild_id) throw new HTTPError("Channel not found", 404);
 
 		if (body.type === 0) {
diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts
index 003638c5..5c28feac 100644
--- a/src/api/routes/channels/#channel_id/pins.ts
+++ b/src/api/routes/channels/#channel_id/pins.ts
@@ -1,16 +1,6 @@
-import {
-	Channel,
-	ChannelPinsUpdateEvent,
-	Config,
-	emitEvent,
-	getPermission,
-	Message,
-	MessageUpdateEvent,
-	DiscordApiErrors
-} from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Channel, ChannelPinsUpdateEvent, Config, DiscordApiErrors, emitEvent, Message, MessageUpdateEvent } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts
index 1ef6e1d7..aebdb832 100644
--- a/src/api/routes/channels/#channel_id/purge.ts
+++ b/src/api/routes/channels/#channel_id/purge.ts
@@ -1,10 +1,18 @@
-import { HTTPError, PurgeSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import {
+	Channel,
+	Config,
+	emitEvent,
+	getPermission,
+	getRights,
+	HTTPError,
+	Message,
+	MessageDeleteBulkEvent,
+	PurgeSchema
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
+import { Between, FindManyOptions, In, Not } from "typeorm";
 import { isTextChannel } from "./messages";
-import { FindManyOptions, Between, Not } from "typeorm";
-import { Channel, Config, emitEvent, getPermission, getRights, Message, MessageDeleteBulkEvent } from "@fosscord/util";
-import { Router, Response, Request } from "express";
-import { In } from "typeorm";
 
 const router: Router = Router();
 
@@ -13,7 +21,12 @@ export default router;
 /**
 TODO: apply the delete bit by bit to prevent client and database stress
 **/
-router.post("/",route({ /*body: "PurgeSchema",*/ }), async (req: Request, res: Response) => {
+router.post(
+	"/",
+	route({
+		/*body: "PurgeSchema",*/
+	}),
+	async (req: Request, res: Response) => {
 		const { channel_id } = req.params;
 		const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
 
diff --git a/src/api/routes/channels/#channel_id/recipients.ts b/src/api/routes/channels/#channel_id/recipients.ts
index 069212e2..276a0eda 100644
--- a/src/api/routes/channels/#channel_id/recipients.ts
+++ b/src/api/routes/channels/#channel_id/recipients.ts
@@ -1,4 +1,4 @@
-import { Request, Response, Router } from "express";
+import { route } from "@fosscord/api";
 import {
 	Channel,
 	ChannelRecipientAddEvent,
@@ -6,12 +6,12 @@ import {
 	DiscordApiErrors,
 	DmChannelDTO,
 	emitEvent,
+	OrmUtils,
 	PublicUserProjection,
 	Recipient,
 	User
 } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/typing.ts b/src/api/routes/channels/#channel_id/typing.ts
index 99460f6e..26d0fcfa 100644
--- a/src/api/routes/channels/#channel_id/typing.ts
+++ b/src/api/routes/channels/#channel_id/typing.ts
@@ -1,6 +1,6 @@
-import { Channel, emitEvent, Member, TypingStartEvent } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { Router, Request, Response } from "express";
+import { Channel, emitEvent, Member, TypingStartEvent } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts
index b11c8eb9..38dcb869 100644
--- a/src/api/routes/channels/#channel_id/webhooks.ts
+++ b/src/api/routes/channels/#channel_id/webhooks.ts
@@ -1,9 +1,7 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
-import { Channel, Config, getPermission, trimSpecial, Webhook } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
+import { Channel, Config, DiscordApiErrors, HTTPError, trimSpecial, Webhook } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { isTextChannel } from "./messages/index";
-import { DiscordApiErrors } from "@fosscord/util";
 
 const router: Router = Router();
 //TODO: implement webhooks
diff --git a/src/api/routes/discoverable-guilds.ts b/src/api/routes/discoverable-guilds.ts
index 35ecf28c..2bf49287 100644
--- a/src/api/routes/discoverable-guilds.ts
+++ b/src/api/routes/discoverable-guilds.ts
@@ -1,8 +1,8 @@
-import { Guild, Config } from "@fosscord/util";
+import { Config, Guild } from "@fosscord/util";
 
-import { Router, Request, Response } from "express";
-import { route } from "..";
+import { Request, Response, Router } from "express";
 import { Like } from "typeorm";
+import { route } from "..";
 
 const router = Router();
 
diff --git a/src/api/routes/discovery.ts b/src/api/routes/discovery.ts
index 30c418c6..7b9edd48 100644
--- a/src/api/routes/discovery.ts
+++ b/src/api/routes/discovery.ts
@@ -1,5 +1,5 @@
 import { Categories } from "@fosscord/util";
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
 import { route } from "..";
 
 const router = Router();
@@ -10,7 +10,7 @@ router.get("/categories", route({}), async (req: Request, res: Response) => {
 
 	const { locale, primary_only } = req.query;
 
-	const out = primary_only ? await Categories.find() : await Categories.find({ where: {is_primary: true} });
+	const out = primary_only ? await Categories.find() : await Categories.find({ where: { is_primary: true } });
 
 	res.send(out);
 });
diff --git a/src/api/routes/downloads.ts b/src/api/routes/downloads.ts
index 44530353..c86c1fb0 100644
--- a/src/api/routes/downloads.ts
+++ b/src/api/routes/downloads.ts
@@ -1,6 +1,6 @@
-import { Router, Response, Request } from "express";
+import { Config, Release } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { route } from "..";
-import { Release, Config } from "@fosscord/util";
 
 const router = Router();
 
@@ -10,7 +10,7 @@ router.get("/:branch", route({}), async (req: Request, res: Response) => {
 	const { platform } = req.query;
 	//TODO
 
-	if(!platform || !["linux", "osx", "win"].includes(platform.toString())) return res.status(404)
+	if (!platform || !["linux", "osx", "win"].includes(platform.toString())) return res.status(404);
 
 	const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } });
 
diff --git a/src/api/routes/experiments.ts b/src/api/routes/experiments.ts
index fcbd9271..0355c631 100644
--- a/src/api/routes/experiments.ts
+++ b/src/api/routes/experiments.ts
@@ -1,11 +1,11 @@
-import { Router, Response, Request } from "express";
+import { Request, Response, Router } from "express";
 import { route } from "..";
 
 const router = Router();
 
 router.get("/", route({}), (req: Request, res: Response) => {
 	// TODO:
-	res.send({ fingerprint: "", assignments: [], guild_experiments:[] });
+	res.send({ fingerprint: "", assignments: [], guild_experiments: [] });
 });
 
 export default router;
diff --git a/src/api/routes/gateway/bot.ts b/src/api/routes/gateway/bot.ts
index f1dbb9df..0e44f6b2 100644
--- a/src/api/routes/gateway/bot.ts
+++ b/src/api/routes/gateway/bot.ts
@@ -1,6 +1,6 @@
-import { Config } from "@fosscord/util";
-import { Router, Response, Request } from "express";
 import { route, RouteOptions } from "@fosscord/api";
+import { Config } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/gateway/index.ts b/src/api/routes/gateway/index.ts
index 9bad7478..47037573 100644
--- a/src/api/routes/gateway/index.ts
+++ b/src/api/routes/gateway/index.ts
@@ -1,6 +1,6 @@
-import { Config } from "@fosscord/util";
-import { Router, Response, Request } from "express";
 import { route, RouteOptions } from "@fosscord/api";
+import { Config } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts
index 1099dc4a..8b5e984a 100644
--- a/src/api/routes/gifs/search.ts
+++ b/src/api/routes/gifs/search.ts
@@ -1,7 +1,7 @@
-import { Router, Response, Request } from "express";
-import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
+import fetch from "node-fetch";
+import ProxyAgent from "proxy-agent";
 import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { q, media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
 	const response = await fetch(`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
@@ -20,7 +20,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		headers: { "Content-Type": "application/json" }
 	});
 
-	const { results } = await response.json() as any;
+	const { results } = (await response.json()) as any;
 
 	res.json(results.map(parseGifResult)).status(200);
 });
diff --git a/src/api/routes/gifs/trending-gifs.ts b/src/api/routes/gifs/trending-gifs.ts
index 2b28d9d2..65a9600e 100644
--- a/src/api/routes/gifs/trending-gifs.ts
+++ b/src/api/routes/gifs/trending-gifs.ts
@@ -1,7 +1,7 @@
-import { Router, Response, Request } from "express";
-import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
+import fetch from "node-fetch";
+import ProxyAgent from "proxy-agent";
 import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
@@ -11,7 +11,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
 	const response = await fetch(`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`, {
@@ -20,7 +20,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		headers: { "Content-Type": "application/json" }
 	});
 
-	const { results } = await response.json() as any;
+	const { results } = (await response.json()) as any;
 
 	res.json(results.map(parseGifResult)).status(200);
 });
diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts
index 61eb76c4..45396ff0 100644
--- a/src/api/routes/gifs/trending.ts
+++ b/src/api/routes/gifs/trending.ts
@@ -1,9 +1,8 @@
-import { Router, Response, Request } from "express";
-import fetch from "node-fetch";
-import ProxyAgent from 'proxy-agent';
 import { route } from "@fosscord/api";
-import { Config } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
+import { Config, HTTPError } from "@fosscord/util";
+import { Request, Response, Router } from "express";
+import fetch from "node-fetch";
+import ProxyAgent from "proxy-agent";
 
 const router = Router();
 
@@ -34,7 +33,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	const { media_format, locale } = req.query;
 
 	const apiKey = getGifApiKey();
-	
+
 	const agent = new ProxyAgent();
 
 	const [responseSource, trendGifSource] = await Promise.all([
@@ -50,8 +49,8 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		})
 	]);
 
-	const { tags } = await responseSource.json() as any;
-	const { results } = await trendGifSource.json() as any;
+	const { tags } = (await responseSource.json()) as any;
+	const { results } = (await trendGifSource.json()) as any;
 
 	res.json({
 		categories: tags.map((x: any) => ({ name: x.searchterm, src: x.image })),
diff --git a/src/api/routes/guild-recommendations.ts b/src/api/routes/guild-recommendations.ts
index bd0140d6..0248a9c3 100644
--- a/src/api/routes/guild-recommendations.ts
+++ b/src/api/routes/guild-recommendations.ts
@@ -1,8 +1,8 @@
-import { Guild, Config } from "@fosscord/util";
+import { Config, Guild } from "@fosscord/util";
 
-import { Router, Request, Response } from "express";
+import { Request, Response, Router } from "express";
+import { Like } from "typeorm";
 import { route } from "..";
-import {Like} from "typeorm"
 
 const router = Router();
 
@@ -13,12 +13,12 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	// TODO: implement this with default typeorm query
 	// const guilds = await Guild.find({ where: { features: "DISCOVERABLE" } }); //, take: Math.abs(Number(limit)) });
 
-	const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
+	const genLoadId = (size: Number) => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join("");
 
 	const guilds = showAllGuilds
 		? await Guild.find({ take: Math.abs(Number(limit || 24)) })
-		: await Guild.find({ where: { features: Like('%DISCOVERABLE%') }, take: Math.abs(Number(limit || 24)) });
-	res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}`}).status(200);
+		: await Guild.find({ where: { features: Like("%DISCOVERABLE%") }, take: Math.abs(Number(limit || 24)) });
+	res.send({ recommended_guilds: guilds, load_id: `server_recs/${genLoadId(32)}` }).status(200);
 });
 
 export default router;
diff --git a/src/api/routes/guilds/#guild_id/audit-logs.ts b/src/api/routes/guilds/#guild_id/audit-logs.ts
index b54835fc..05b9982e 100644
--- a/src/api/routes/guilds/#guild_id/audit-logs.ts
+++ b/src/api/routes/guilds/#guild_id/audit-logs.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 //TODO: implement audit logs
diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts
index 3d405344..4600b4cb 100644
--- a/src/api/routes/guilds/#guild_id/bans.ts
+++ b/src/api/routes/guilds/#guild_id/bans.ts
@@ -1,8 +1,18 @@
-import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, Ban, User, Member, BanRegistrySchema, BanModeratorSchema } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { getIpAdress, route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import {
+	Ban,
+	BanModeratorSchema,
+	BanRegistrySchema,
+	DiscordApiErrors,
+	emitEvent,
+	GuildBanAddEvent,
+	GuildBanRemoveEvent,
+	HTTPError,
+	Member,
+	OrmUtils,
+	User
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -44,16 +54,16 @@ router.get("/:user", route({ permission: "BAN_MEMBERS" }), async (req: Request,
 	const { guild_id } = req.params;
 	const user_id = req.params.ban;
 
-	let ban = await Ban.findOneOrFail({ where: { guild_id, user_id } }) as BanRegistrySchema;
-	
+	let ban = (await Ban.findOneOrFail({ where: { guild_id, user_id } })) as BanRegistrySchema;
+
 	if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
 	// pretend self-bans don't exist to prevent victim chasing
-	
+
 	/* Filter secret from registry. */
-	
+
 	ban = ban as BanModeratorSchema;
 
-	delete ban.ip
+	delete ban.ip;
 
 	return res.json(ban);
 });
@@ -62,14 +72,14 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER
 	const { guild_id } = req.params;
 	const banned_user_id = req.params.user_id;
 
-	if ( (req.user_id === banned_user_id) && (banned_user_id === req.permission!.cache.guild?.owner_id))
+	if (req.user_id === banned_user_id && banned_user_id === req.permission!.cache.guild?.owner_id)
 		throw new HTTPError("You are the guild owner, hence can't ban yourself", 403);
-	
+
 	if (req.permission!.cache.guild?.owner_id === banned_user_id) throw new HTTPError("You can't ban the owner", 400);
-	
+
 	const banned_user = await User.getPublicUser(banned_user_id);
 
-	const ban = OrmUtils.mergeDeep(new Ban(),{
+	const ban = OrmUtils.mergeDeep(new Ban(), {
 		user_id: banned_user_id,
 		guild_id: guild_id,
 		ip: getIpAdress(req),
@@ -93,14 +103,14 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER
 	return res.json(ban);
 });
 
-router.put("/@me", route({ body: "BanCreateSchema"}), async (req: Request, res: Response) => {
+router.put("/@me", route({ body: "BanCreateSchema" }), async (req: Request, res: Response) => {
 	const { guild_id } = req.params;
 
 	const banned_user = await User.getPublicUser(req.params.user_id);
 
-	if (req.permission!.cache.guild?.owner_id === req.params.user_id) 
+	if (req.permission!.cache.guild?.owner_id === req.params.user_id)
 		throw new HTTPError("You are the guild owner, hence can't ban yourself", 403);
-	
+
 	const ban = OrmUtils.mergeDeep(new Ban(), {
 		user_id: req.params.user_id,
 		guild_id: guild_id,
@@ -129,12 +139,12 @@ router.delete("/:user_id", route({ permission: "BAN_MEMBERS" }), async (req: Req
 	const { guild_id, user_id } = req.params;
 
 	let ban = await Ban.findOneOrFail({ where: { guild_id, user_id } });
-	
+
 	if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN;
 	// make self-bans irreversible and hide them from view to avoid victim chasing
-	
+
 	const banned_user = await User.getPublicUser(user_id);
-	
+
 	await Promise.all([
 		Ban.delete({
 			user_id: user_id,
diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts
index 8f2d3643..3563eb4c 100644
--- a/src/api/routes/guilds/#guild_id/channels.ts
+++ b/src/api/routes/guilds/#guild_id/channels.ts
@@ -1,7 +1,6 @@
-import { Router, Response, Request } from "express";
-import { Channel, ChannelUpdateEvent, getPermission, emitEvent, ChannelModifySchema, ChannelReorderSchema } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Channel, ChannelModifySchema, ChannelReorderSchema, ChannelUpdateEvent, emitEvent, HTTPError } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts
index e2624651..e6a1a6b2 100644
--- a/src/api/routes/guilds/#guild_id/delete.ts
+++ b/src/api/routes/guilds/#guild_id/delete.ts
@@ -1,7 +1,6 @@
-import { Channel, emitEvent, GuildDeleteEvent, Guild, Member, Message, Role, Invite, Emoji } from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { emitEvent, Guild, GuildDeleteEvent, HTTPError } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
index ad20633f..c0260fe7 100644
--- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts
+++ b/src/api/routes/guilds/#guild_id/discovery-requirements.ts
@@ -1,38 +1,36 @@
-import { Guild, Config } from "@fosscord/util";
-
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;	
-    // TODO:
-    // Load from database
-    // Admin control, but for now it allows anyone to be discoverable
+	const { guild_id } = req.params;
+	// TODO:
+	// Load from database
+	// Admin control, but for now it allows anyone to be discoverable
 
 	res.send({
 		guild_id: guild_id,
 		safe_environment: true,
-        healthy: true,
-        health_score_pending: false,
-        size: true,
-        nsfw_properties: {},
-        protected: true,
-        sufficient: true,
-        sufficient_without_grace_period: true,
-        valid_rules_channel: true,
-        retention_healthy: true,
-        engagement_healthy: true,
-        age: true,
-        minimum_age: 0,
-        health_score: {
-            avg_nonnew_participators: 0,
-            avg_nonnew_communicators: 0,
-            num_intentful_joiners: 0,
-            perc_ret_w1_intentful: 0
-        },
-        minimum_size: 0
+		healthy: true,
+		health_score_pending: false,
+		size: true,
+		nsfw_properties: {},
+		protected: true,
+		sufficient: true,
+		sufficient_without_grace_period: true,
+		valid_rules_channel: true,
+		retention_healthy: true,
+		engagement_healthy: true,
+		age: true,
+		minimum_age: 0,
+		health_score: {
+			avg_nonnew_participators: 0,
+			avg_nonnew_communicators: 0,
+			num_intentful_joiners: 0,
+			perc_ret_w1_intentful: 0
+		},
+		minimum_size: 0
 	});
 });
 
diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts
index 4bf4bdcd..db5ae325 100644
--- a/src/api/routes/guilds/#guild_id/emojis.ts
+++ b/src/api/routes/guilds/#guild_id/emojis.ts
@@ -1,7 +1,19 @@
-import { Router, Request, Response } from "express";
-import { Config, DiscordApiErrors, emitEvent, Emoji, EmojiCreateSchema, EmojiModifySchema, GuildEmojisUpdateEvent, handleFile, Member, Snowflake, User } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import {
+	Config,
+	DiscordApiErrors,
+	emitEvent,
+	Emoji,
+	EmojiCreateSchema,
+	EmojiModifySchema,
+	GuildEmojisUpdateEvent,
+	handleFile,
+	Member,
+	OrmUtils,
+	Snowflake,
+	User
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts
index a9712c71..af889982 100644
--- a/src/api/routes/guilds/#guild_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/index.ts
@@ -1,8 +1,18 @@
-import { Request, Response, Router } from "express";
-import { DiscordApiErrors, emitEvent, getPermission, getRights, Guild, GuildUpdateEvent, GuildUpdateSchema, handleFile, Member } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import {
+	DiscordApiErrors,
+	emitEvent,
+	getPermission,
+	getRights,
+	Guild,
+	GuildUpdateEvent,
+	GuildUpdateSchema,
+	handleFile,
+	HTTPError,
+	Member,
+	OrmUtils
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
@@ -21,17 +31,16 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 	return res.send(guild);
 });
 
-router.patch("/", route({ body: "GuildUpdateSchema"}), async (req: Request, res: Response) => {
+router.patch("/", route({ body: "GuildUpdateSchema" }), async (req: Request, res: Response) => {
 	const body = req.body as GuildUpdateSchema;
 	const { guild_id } = req.params;
-	
-	
+
 	const rights = await getRights(req.user_id);
 	const permission = await getPermission(req.user_id, guild_id);
-	
-	if (!rights.has("MANAGE_GUILDS")||!permission.has("MANAGE_GUILD"))
+
+	if (!rights.has("MANAGE_GUILDS") || !permission.has("MANAGE_GUILD"))
 		throw DiscordApiErrors.MISSING_PERMISSIONS.withParams("MANAGE_GUILD");
-	
+
 	// TODO: guild update check image
 
 	if (body.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
diff --git a/src/api/routes/guilds/#guild_id/integrations.ts b/src/api/routes/guilds/#guild_id/integrations.ts
index 90650111..6a5abec3 100644
--- a/src/api/routes/guilds/#guild_id/integrations.ts
+++ b/src/api/routes/guilds/#guild_id/integrations.ts
@@ -1,7 +1,5 @@
-import { Router, Response, Request } from "express";
-import { Channel, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 //TODO: implement integrations list
diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts
index b7534e31..c663df72 100644
--- a/src/api/routes/guilds/#guild_id/invites.ts
+++ b/src/api/routes/guilds/#guild_id/invites.ts
@@ -1,5 +1,5 @@
-import { getPermission, Invite, PublicInviteRelation } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Invite, PublicInviteRelation } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
 const router = Router();
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
index 794369d8..57152f9a 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts
@@ -1,8 +1,18 @@
-import { Request, Response, Router } from "express";
-import { Member, getPermission, getRights, Role, GuildMemberUpdateEvent, emitEvent, Sticker, Emoji, Rights, Guild, MemberChangeSchema } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import {
+	emitEvent,
+	Emoji,
+	getPermission,
+	getRights,
+	Guild,
+	GuildMemberUpdateEvent,
+	Member,
+	MemberChangeSchema,
+	OrmUtils,
+	Role,
+	Sticker
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
@@ -46,7 +56,6 @@ router.patch("/", route({ body: "MemberChangeSchema" }), async (req: Request, re
 });
 
 router.put("/", route({}), async (req: Request, res: Response) => {
-
 	// TODO: Lurker mode
 
 	const rights = await getRights(req.user_id);
@@ -56,7 +65,7 @@ router.put("/", route({}), async (req: Request, res: Response) => {
 		member_id = req.user_id;
 		rights.hasThrow("JOIN_GUILDS");
 	} else {
-		// TODO: join others by controller	
+		// TODO: join others by controller
 	}
 
 	let guild = await Guild.findOneOrFail({
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
index a6c71333..26411f97 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts
@@ -1,5 +1,5 @@
-import { getPermission, Member, PermissionResolvable } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { getPermission, Member, PermissionResolvable } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
 const router = Router();
diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
index 8f5ca7ba..0aa7a4dc 100644
--- a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts
@@ -1,5 +1,5 @@
-import { getPermission, Member } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Member } from "@fosscord/util";
 import { Request, Response, Router } from "express";
 
 const router = Router();
diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts
index 2ed28bda..08164626 100644
--- a/src/api/routes/guilds/#guild_id/members/index.ts
+++ b/src/api/routes/guilds/#guild_id/members/index.ts
@@ -1,8 +1,7 @@
-import { Request, Response, Router } from "express";
-import { Guild, Member, PublicMemberProjection } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { HTTPError, Member, PublicMemberProjection } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { MoreThan } from "typeorm";
-import { HTTPError } from "@fosscord/util";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/premium.ts b/src/api/routes/guilds/#guild_id/premium.ts
index 75361ac6..b7716378 100644
--- a/src/api/routes/guilds/#guild_id/premium.ts
+++ b/src/api/routes/guilds/#guild_id/premium.ts
@@ -1,5 +1,5 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 router.get("/subscriptions", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts
index 673f022f..3645721c 100644
--- a/src/api/routes/guilds/#guild_id/prune.ts
+++ b/src/api/routes/guilds/#guild_id/prune.ts
@@ -1,7 +1,7 @@
-import { Router, Request, Response } from "express";
-import { Guild, Member, Snowflake } from "@fosscord/util";
-import { LessThan, IsNull } from "typeorm";
 import { route } from "@fosscord/api";
+import { Guild, Member, Snowflake } from "@fosscord/util";
+import { Request, Response, Router } from "express";
+import { IsNull, LessThan } from "typeorm";
 const router = Router();
 
 //Returns all inactive members, respecting role hierarchy
diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts
index 308d5ee5..aa57ec65 100644
--- a/src/api/routes/guilds/#guild_id/regions.ts
+++ b/src/api/routes/guilds/#guild_id/regions.ts
@@ -1,7 +1,6 @@
-import { Config, Guild, Member } from "@fosscord/util";
+import { getIpAdress, getVoiceRegions, route } from "@fosscord/api";
+import { Guild } from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { getVoiceRegions, route } from "@fosscord/api";
-import { getIpAdress } from "@fosscord/api";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
index d4422a9c..7f9dbc6f 100644
--- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts
@@ -1,8 +1,16 @@
-import { Router, Request, Response } from "express";
-import { Role, Member, GuildRoleUpdateEvent, GuildRoleDeleteEvent, emitEvent, handleFile, RoleModifySchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { HTTPError } from "@fosscord/util";
-import { OrmUtils } from "@fosscord/util";
+import {
+	emitEvent,
+	GuildRoleDeleteEvent,
+	GuildRoleUpdateEvent,
+	handleFile,
+	HTTPError,
+	Member,
+	OrmUtils,
+	Role,
+	RoleModifySchema
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts
index 17f0b5e9..9791f7a9 100644
--- a/src/api/routes/guilds/#guild_id/roles/index.ts
+++ b/src/api/routes/guilds/#guild_id/roles/index.ts
@@ -1,21 +1,18 @@
-import { Request, Response, Router } from "express";
+import { route } from "@fosscord/api";
 import {
-	Role,
+	Config,
+	DiscordApiErrors,
+	emitEvent,
 	getPermission,
-	Member,
 	GuildRoleCreateEvent,
 	GuildRoleUpdateEvent,
-	GuildRoleDeleteEvent,
-	emitEvent,
-	Config,
-	DiscordApiErrors,
-	handleFile,
+	Member,
+	OrmUtils,
+	Role,
 	RoleModifySchema,
 	RolePositionUpdateSchema
 } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -38,7 +35,7 @@ router.post("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" })
 
 	if (role_count > maxRoles) throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles);
 
-	let role: Role = OrmUtils.mergeDeep(new Role(),{
+	let role: Role = OrmUtils.mergeDeep(new Role(), {
 		// values before ...body are default and can be overriden
 		position: 0,
 		hoist: false,
diff --git a/src/api/routes/guilds/#guild_id/stickers.ts b/src/api/routes/guilds/#guild_id/stickers.ts
index 71c9dfcd..15741780 100644
--- a/src/api/routes/guilds/#guild_id/stickers.ts
+++ b/src/api/routes/guilds/#guild_id/stickers.ts
@@ -1,20 +1,19 @@
+import { route } from "@fosscord/api";
 import {
 	emitEvent,
 	GuildStickersUpdateEvent,
-	handleFile,
+	HTTPError,
 	Member,
 	ModifyGuildStickerSchema,
+	OrmUtils,
 	Snowflake,
 	Sticker,
 	StickerFormatType,
 	StickerType,
 	uploadFile
 } from "@fosscord/util";
-import { Router, Request, Response } from "express";
-import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 import multer from "multer";
-import { HTTPError } from "@fosscord/util";
-import { OrmUtils } from "@fosscord/util";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts
index 9c79692d..448ee033 100644
--- a/src/api/routes/guilds/#guild_id/templates.ts
+++ b/src/api/routes/guilds/#guild_id/templates.ts
@@ -1,9 +1,6 @@
+import { generateCode, route } from "@fosscord/api";
+import { Guild, HTTPError, OrmUtils, Template } from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { Guild, Template } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { generateCode } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
 
 const router: Router = Router();
 
@@ -75,7 +72,12 @@ router.patch("/:code", route({ body: "TemplateModifySchema", permission: "MANAGE
 	const { code, guild_id } = req.params;
 	const { name, description } = req.body;
 
-	const template = await OrmUtils.mergeDeep(new Template(), { code, name: name, description: description, source_guild_id: guild_id }).save();
+	const template = await OrmUtils.mergeDeep(new Template(), {
+		code,
+		name: name,
+		description: description,
+		source_guild_id: guild_id
+	}).save();
 
 	res.json(template);
 });
diff --git a/src/api/routes/guilds/#guild_id/vanity-url.ts b/src/api/routes/guilds/#guild_id/vanity-url.ts
index ff92ce8d..bf2db134 100644
--- a/src/api/routes/guilds/#guild_id/vanity-url.ts
+++ b/src/api/routes/guilds/#guild_id/vanity-url.ts
@@ -1,8 +1,6 @@
-import { Channel, ChannelType, getPermission, Guild, Invite, trimSpecial, VanityUrlSchema } from "@fosscord/util";
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { HTTPError } from "@fosscord/util";
-import { OrmUtils } from "@fosscord/util";
+import { Channel, ChannelType, Guild, HTTPError, Invite, OrmUtils, VanityUrlSchema } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
index 28a9e8c1..797d348e 100644
--- a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
+++ b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts
@@ -1,7 +1,16 @@
-import { Channel, ChannelType, DiscordApiErrors, emitEvent, getPermission, VoiceState, VoiceStateUpdateEvent, VoiceStateUpdateSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import {
+	Channel,
+	ChannelType,
+	DiscordApiErrors,
+	emitEvent,
+	getPermission,
+	OrmUtils,
+	VoiceState,
+	VoiceStateUpdateEvent,
+	VoiceStateUpdateSchema
+} from "@fosscord/util";
 import { Request, Response, Router } from "express";
-import { OrmUtils } from "@fosscord/util";
 
 const router = Router();
 router.patch("/", route({ body: "VoiceStateUpdateSchema" }), async (req: Request, res: Response) => {
diff --git a/src/api/routes/guilds/#guild_id/webhooks.ts b/src/api/routes/guilds/#guild_id/webhooks.ts
index c8c1eb5c..80e6a59a 100644
--- a/src/api/routes/guilds/#guild_id/webhooks.ts
+++ b/src/api/routes/guilds/#guild_id/webhooks.ts
@@ -1,7 +1,5 @@
-import { Router, Response, Request } from "express";
-import { Channel, ChannelUpdateEvent, getPermission, emitEvent } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 //TODO: implement webhooks
diff --git a/src/api/routes/guilds/#guild_id/welcome_screen.ts b/src/api/routes/guilds/#guild_id/welcome_screen.ts
index d08300ba..85c22a19 100644
--- a/src/api/routes/guilds/#guild_id/welcome_screen.ts
+++ b/src/api/routes/guilds/#guild_id/welcome_screen.ts
@@ -1,7 +1,6 @@
-import { Request, Response, Router } from "express";
-import { Guild, getPermission, Snowflake, Member, GuildUpdateWelcomeScreenSchema } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Guild, GuildUpdateWelcomeScreenSchema, HTTPError, Member } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts
index 37739418..368fe46e 100644
--- a/src/api/routes/guilds/#guild_id/widget.json.ts
+++ b/src/api/routes/guilds/#guild_id/widget.json.ts
@@ -1,8 +1,6 @@
-import { Request, Response, Router } from "express";
-import { Config, Permissions, Guild, Invite, Channel, Member } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { random, route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import { Channel, Guild, HTTPError, Invite, Member, OrmUtils, Permissions } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts
index a61d938d..1c4ef29b 100644
--- a/src/api/routes/guilds/#guild_id/widget.png.ts
+++ b/src/api/routes/guilds/#guild_id/widget.png.ts
@@ -1,10 +1,19 @@
-import { Request, Response, Router } from "express";
-import { Guild } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Guild, HTTPError } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import fs from "fs";
 import path from "path";
 
+// Setup canvas
+let createCanvas: any, loadImage: any;
+try {
+	createCanvas = require("canvas").createCanvas;
+	loadImage = require("canvas").loadImage;
+} catch {
+	console.log("Canvas not found, disabling widgets!");
+}
+const sizeOf = require("image-size");
+
 const router: Router = Router();
 
 // TODO: use svg templates instead of node-canvas for improved performance and to change it easily
@@ -12,6 +21,7 @@ const router: Router = Router();
 // https://discord.com/developers/docs/resources/guild#get-guild-widget-image
 // TODO: Cache the response
 router.get("/", route({}), async (req: Request, res: Response) => {
+	if (!createCanvas) return res.status(404);
 	const { guild_id } = req.params;
 
 	const guild = await Guild.findOneOrFail({ where: { id: guild_id } });
@@ -28,11 +38,6 @@ router.get("/", route({}), async (req: Request, res: Response) => {
 		throw new HTTPError("Value must be one of ('shield', 'banner1', 'banner2', 'banner3', 'banner4').", 400);
 	}
 
-	// Setup canvas
-	const { createCanvas } = require("canvas");
-	const { loadImage } = require("canvas");
-	const sizeOf = require("image-size");
-
 	// TODO: Widget style templates need Fosscord branding
 	const source = path.join(__dirname, "..", "..", "..", "..", "..", "assets", "widget", `${style}.png`);
 	if (!fs.existsSync(source)) {
diff --git a/src/api/routes/guilds/#guild_id/widget.ts b/src/api/routes/guilds/#guild_id/widget.ts
index dbb4cc0c..d2369dd1 100644
--- a/src/api/routes/guilds/#guild_id/widget.ts
+++ b/src/api/routes/guilds/#guild_id/widget.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
-import { Guild, WidgetModifySchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Guild, WidgetModifySchema } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts
index e4d66192..6946e2f7 100644
--- a/src/api/routes/guilds/index.ts
+++ b/src/api/routes/guilds/index.ts
@@ -1,6 +1,6 @@
-import { Router, Request, Response } from "express";
-import { Role, Guild, Snowflake, Config, getRights, Member, Channel, DiscordApiErrors, handleFile, GuildCreateSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Config, DiscordApiErrors, getRights, Guild, GuildCreateSchema, Member } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -12,7 +12,7 @@ router.post("/", route({ body: "GuildCreateSchema", right: "CREATE_GUILDS" }), a
 	const { maxGuilds } = Config.get().limits.user;
 	const guild_count = await Member.count({ where: { id: req.user_id } });
 	const rights = await getRights(req.user_id);
-	if ((guild_count >= maxGuilds)&&!rights.has("MANAGE_GUILDS")) {
+	if (guild_count >= maxGuilds && !rights.has("MANAGE_GUILDS")) {
 		throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds);
 	}
 
diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts
index 3a0de9e8..467186a3 100644
--- a/src/api/routes/guilds/templates/index.ts
+++ b/src/api/routes/guilds/templates/index.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
-import { Template, Guild, Role, Snowflake, Config, User, Member, DiscordApiErrors, OrmUtils, GuildTemplateCreateSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Config, DiscordApiErrors, Guild, GuildTemplateCreateSchema, Member, OrmUtils, Role, Snowflake, Template } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import fetch from "node-fetch";
 const router: Router = Router();
 
@@ -9,9 +9,10 @@ router.get("/:code", route({}), async (req: Request, res: Response) => {
 	if (!enabled) res.json({ code: 403, message: "Template creation & usage is disabled on this instance." }).sendStatus(403);
 
 	const { code } = req.params;
-	
+
 	if (code.startsWith("discord:")) {
-		if (!allowDiscordTemplates)	return res.json({ code: 403, message: "Discord templates cannot be used on this instance." }).sendStatus(403);
+		if (!allowDiscordTemplates)
+			return res.json({ code: 403, message: "Discord templates cannot be used on this instance." }).sendStatus(403);
 		const discordTemplateID = code.split("discord:", 2)[1];
 
 		const discordTemplateData = await fetch(`https://discord.com/api/v9/guilds/templates/${discordTemplateID}`, {
@@ -22,7 +23,7 @@ router.get("/:code", route({}), async (req: Request, res: Response) => {
 	}
 
 	if (code.startsWith("external:")) {
-		if (!allowRaws)	return res.json({ code: 403, message: "Importing raws is disabled on this instance." }).sendStatus(403);
+		if (!allowRaws) return res.json({ code: 403, message: "Importing raws is disabled on this instance." }).sendStatus(403);
 
 		return res.json(code.split("external:", 2)[1]);
 	}
@@ -57,18 +58,20 @@ router.post("/:code", route({ body: "GuildTemplateCreateSchema" }), async (req:
 			id: guild_id,
 			owner_id: req.user_id
 		}).save(),
-		(OrmUtils.mergeDeep(new Role(), {
-			id: guild_id,
-			guild_id: guild_id,
-			color: 0,
-			hoist: false,
-			managed: true,
-			mentionable: true,
-			name: "@everyone",
-			permissions: BigInt("2251804225"),
-			position: 0,
-			tags: null
-		}) as Role).save()
+		(
+			OrmUtils.mergeDeep(new Role(), {
+				id: guild_id,
+				guild_id: guild_id,
+				color: 0,
+				hoist: false,
+				managed: true,
+				mentionable: true,
+				name: "@everyone",
+				permissions: BigInt("2251804225"),
+				position: 0,
+				tags: null
+			}) as Role
+		).save()
 	]);
 
 	await Member.addToGuild(req.user_id, guild_id);
diff --git a/src/api/routes/invites/index.ts b/src/api/routes/invites/index.ts
index 1b434505..73c9324c 100644
--- a/src/api/routes/invites/index.ts
+++ b/src/api/routes/invites/index.ts
@@ -1,7 +1,6 @@
-import { Router, Request, Response } from "express";
-import { emitEvent, getPermission, Guild, Invite, InviteDeleteEvent, User, PublicInviteRelation } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import { HTTPError } from "@fosscord/util";
+import { emitEvent, getPermission, Guild, HTTPError, Invite, InviteDeleteEvent, PublicInviteRelation, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -13,15 +12,16 @@ router.get("/:code", route({}), async (req: Request, res: Response) => {
 	res.status(200).send(invite);
 });
 
-router.post("/:code", route({right: "USE_MASS_INVITES"}), async (req: Request, res: Response) => {
+router.post("/:code", route({ right: "USE_MASS_INVITES" }), async (req: Request, res: Response) => {
 	const { code } = req.params;
-    const { guild_id } = await Invite.findOneOrFail({ where: { code } })
-	const { features } = await Guild.findOneOrFail({ where: { id: guild_id} });
+	const { guild_id } = await Invite.findOneOrFail({ where: { code } });
+	const { features } = await Guild.findOneOrFail({ where: { id: guild_id } });
 	const { public_flags } = await User.findOneOrFail({ where: { id: req.user_id } });
-	
-	if(features.includes("INTERNAL_EMPLOYEE_ONLY") && (public_flags & 1) !== 1) throw new HTTPError("Only intended for the staff of this server.", 401);
-	if(features.includes("INVITES_CLOSED")) throw new HTTPError("Sorry, this guild has joins closed.", 403);
-	
+
+	if (features.includes("INTERNAL_EMPLOYEE_ONLY") && (public_flags & 1) !== 1)
+		throw new HTTPError("Only intended for the staff of this server.", 401);
+	if (features.includes("INVITES_CLOSED")) throw new HTTPError("Sorry, this guild has joins closed.", 403);
+
 	const invite = await Invite.joinGuild(req.user_id, code);
 
 	res.json(invite);
diff --git a/src/api/routes/oauth2/tokens.ts b/src/api/routes/oauth2/tokens.ts
index bd284221..831dc7af 100644
--- a/src/api/routes/oauth2/tokens.ts
+++ b/src/api/routes/oauth2/tokens.ts
@@ -1,5 +1,5 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/outbound-promotions.ts b/src/api/routes/outbound-promotions.ts
index 411e95bf..8e407184 100644
--- a/src/api/routes/outbound-promotions.ts
+++ b/src/api/routes/outbound-promotions.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/partners/#guild_id/requirements.ts b/src/api/routes/partners/#guild_id/requirements.ts
index 545c5c78..c0260fe7 100644
--- a/src/api/routes/partners/#guild_id/requirements.ts
+++ b/src/api/routes/partners/#guild_id/requirements.ts
@@ -1,39 +1,36 @@
-
-import { Guild, Config } from "@fosscord/util";
-
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
-	const { guild_id } = req.params;	
-    // TODO:
-    // Load from database
-    // Admin control, but for now it allows anyone to be discoverable
+	const { guild_id } = req.params;
+	// TODO:
+	// Load from database
+	// Admin control, but for now it allows anyone to be discoverable
 
 	res.send({
 		guild_id: guild_id,
 		safe_environment: true,
-        healthy: true,
-        health_score_pending: false,
-        size: true,
-        nsfw_properties: {},
-        protected: true,
-        sufficient: true,
-        sufficient_without_grace_period: true,
-        valid_rules_channel: true,
-        retention_healthy: true,
-        engagement_healthy: true,
-        age: true,
-        minimum_age: 0,
-        health_score: {
-            avg_nonnew_participators: 0,
-            avg_nonnew_communicators: 0,
-            num_intentful_joiners: 0,
-            perc_ret_w1_intentful: 0
-        },
-        minimum_size: 0
+		healthy: true,
+		health_score_pending: false,
+		size: true,
+		nsfw_properties: {},
+		protected: true,
+		sufficient: true,
+		sufficient_without_grace_period: true,
+		valid_rules_channel: true,
+		retention_healthy: true,
+		engagement_healthy: true,
+		age: true,
+		minimum_age: 0,
+		health_score: {
+			avg_nonnew_participators: 0,
+			avg_nonnew_communicators: 0,
+			num_intentful_joiners: 0,
+			perc_ret_w1_intentful: 0
+		},
+		minimum_size: 0
 	});
 });
 
diff --git a/src/api/routes/ping.ts b/src/api/routes/ping.ts
index 3c1da2c3..5f1b0174 100644
--- a/src/api/routes/ping.ts
+++ b/src/api/routes/ping.ts
@@ -1,6 +1,6 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
@@ -18,8 +18,8 @@ router.get("/", route({}), (req: Request, res: Response) => {
 			correspondenceUserID: general.correspondenceUserID,
 
 			frontPage: general.frontPage,
-			tosPage: general.tosPage,
-		},
+			tosPage: general.tosPage
+		}
 	});
 });
 
diff --git a/src/api/routes/policies/instance/domains.ts b/src/api/routes/policies/instance/domains.ts
index 20cd07ba..fed0a627 100644
--- a/src/api/routes/policies/instance/domains.ts
+++ b/src/api/routes/policies/instance/domains.ts
@@ -1,16 +1,15 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
-import { config } from "dotenv"
+import { Request, Response, Router } from "express";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
-    const { cdn, gateway } = Config.get();
-    
-    const IdentityForm = {
-        cdn: cdn.endpointPublic || process.env.CDN || "http://localhost:3001",
-        gateway: gateway.endpointPublic || process.env.GATEWAY || "ws://localhost:3002"
-    };
+router.get("/", route({}), async (req: Request, res: Response) => {
+	const { cdn, gateway } = Config.get();
+
+	const IdentityForm = {
+		cdn: cdn.endpointPublic || process.env.CDN || "http://localhost:3001",
+		gateway: gateway.endpointPublic || process.env.GATEWAY || "ws://localhost:3002"
+	};
 
 	res.json(IdentityForm);
 });
diff --git a/src/api/routes/policies/instance/index.ts b/src/api/routes/policies/instance/index.ts
index e3da014f..a8ffd285 100644
--- a/src/api/routes/policies/instance/index.ts
+++ b/src/api/routes/policies/instance/index.ts
@@ -1,10 +1,9 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 const router = Router();
 
-
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
 	const { general } = Config.get();
 	res.json(general);
 });
diff --git a/src/api/routes/policies/instance/limits.ts b/src/api/routes/policies/instance/limits.ts
index 7de1476b..0d42fc7b 100644
--- a/src/api/routes/policies/instance/limits.ts
+++ b/src/api/routes/policies/instance/limits.ts
@@ -1,9 +1,9 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { Config } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 const router = Router();
 
-router.get("/",route({}), async (req: Request, res: Response) => {
+router.get("/", route({}), async (req: Request, res: Response) => {
 	const { limits } = Config.get();
 	res.json(limits);
 });
diff --git a/src/api/routes/scheduled-maintenances/upcoming_json.ts b/src/api/routes/scheduled-maintenances/upcoming_json.ts
index 83092e44..ec4ddc7c 100644
--- a/src/api/routes/scheduled-maintenances/upcoming_json.ts
+++ b/src/api/routes/scheduled-maintenances/upcoming_json.ts
@@ -1,12 +1,12 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 const router = Router();
 
-router.get("/scheduled-maintenances/upcoming.json",route({}), async (req: Request, res: Response) => {
+router.get("/scheduled-maintenances/upcoming.json", route({}), async (req: Request, res: Response) => {
 	res.json({
-  "page": {},
-  "scheduled_maintenances": {}
-  });
+		page: {},
+		scheduled_maintenances: {}
+	});
 });
 
 export default router;
diff --git a/src/api/routes/science.ts b/src/api/routes/science.ts
index 8556a3ad..cb01e576 100644
--- a/src/api/routes/science.ts
+++ b/src/api/routes/science.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/stage-instances.ts b/src/api/routes/stage-instances.ts
index 411e95bf..8e407184 100644
--- a/src/api/routes/stage-instances.ts
+++ b/src/api/routes/stage-instances.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/sticker-packs/index.ts b/src/api/routes/sticker-packs/index.ts
index e6560d12..dddc7f70 100644
--- a/src/api/routes/sticker-packs/index.ts
+++ b/src/api/routes/sticker-packs/index.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
 import { StickerPack } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/stickers/#sticker_id/index.ts b/src/api/routes/stickers/#sticker_id/index.ts
index b484a7a1..16eb2059 100644
--- a/src/api/routes/stickers/#sticker_id/index.ts
+++ b/src/api/routes/stickers/#sticker_id/index.ts
@@ -1,6 +1,6 @@
-import { Sticker } from "@fosscord/util";
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
+import { Sticker } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/src/api/routes/stop.ts b/src/api/routes/stop.ts
index 7f8b78ba..fb77b4f3 100644
--- a/src/api/routes/stop.ts
+++ b/src/api/routes/stop.ts
@@ -1,22 +1,21 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
 router.post("/", route({}), async (req: Request, res: Response) => {
 	//EXPERIMENTAL: have an "OPERATOR" platform permission implemented for this API route
 	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["rights"] });
-	if((Number(user.rights) << Number(0))%Number(2)==Number(1)) {
+	if ((Number(user.rights) << Number(0)) % Number(2) == Number(1)) {
 		console.log("user that POSTed to the API was ALLOWED");
 		console.log(user.rights);
-		res.sendStatus(200)
-		process.kill(process.pid, 'SIGTERM')
-	}
-	else {
+		res.sendStatus(200);
+		process.kill(process.pid, "SIGTERM");
+	} else {
 		console.log("operation failed");
 		console.log(user.rights);
-		res.sendStatus(403)
+		res.sendStatus(403);
 	}
 });
 
diff --git a/src/api/routes/store/published-listings/applications.ts b/src/api/routes/store/published-listings/applications.ts
index 060a4c3d..3d0f7998 100644
--- a/src/api/routes/store/published-listings/applications.ts
+++ b/src/api/routes/store/published-listings/applications.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts b/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
index 54151ae5..86fce75d 100644
--- a/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
+++ b/src/api/routes/store/published-listings/applications/#id/subscription-plans.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/store/published-listings/skus.ts b/src/api/routes/store/published-listings/skus.ts
index 060a4c3d..3d0f7998 100644
--- a/src/api/routes/store/published-listings/skus.ts
+++ b/src/api/routes/store/published-listings/skus.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts b/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
index e7f44ded..fdd775b7 100644
--- a/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
+++ b/src/api/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/teams.ts b/src/api/routes/teams.ts
index 7ce3abcb..9aa1c10e 100644
--- a/src/api/routes/teams.ts
+++ b/src/api/routes/teams.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/track.ts b/src/api/routes/track.ts
index 8556a3ad..cb01e576 100644
--- a/src/api/routes/track.ts
+++ b/src/api/routes/track.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/updates.ts b/src/api/routes/updates.ts
index a24e94c1..6019371e 100644
--- a/src/api/routes/updates.ts
+++ b/src/api/routes/updates.ts
@@ -1,20 +1,20 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
 import { Config, Release } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
 router.get("/", route({}), async (req: Request, res: Response) => {
 	const { client } = Config.get();
 
-    const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } })
+	const release = await Release.findOneOrFail({ where: { name: client.releases.upstreamVersion } });
 
 	res.json({
-        name: release.name,
-        pub_date: release.pub_date,
-        url: release.url,
-        notes: release.notes
-    });
+		name: release.name,
+		pub_date: release.pub_date,
+		url: release.url,
+		notes: release.notes
+	});
 });
 
 export default router;
diff --git a/src/api/routes/users/#id/index.ts b/src/api/routes/users/#id/index.ts
index bdb1060f..e33e5695 100644
--- a/src/api/routes/users/#id/index.ts
+++ b/src/api/routes/users/#id/index.ts
@@ -1,6 +1,6 @@
-import { Router, Request, Response } from "express";
-import { User } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
index 7a995a8c..27717c79 100644
--- a/src/api/routes/users/#id/profile.ts
+++ b/src/api/routes/users/#id/profile.ts
@@ -1,6 +1,6 @@
-import { Router, Request, Response } from "express";
-import { PublicConnectedAccount, PublicUser, User, UserPublic, Member } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Member, PublicConnectedAccount, User, UserPublic } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -17,22 +17,22 @@ router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }),
 
 	let mutual_guilds: object[] = [];
 	let premium_guild_since;
-	const requested_member = await Member.find( { where: { id: req.params.id, } })
-	const self_member = await Member.find( { where: { id: req.user_id, } })
+	const requested_member = await Member.find({ where: { id: req.params.id } });
+	const self_member = await Member.find({ where: { id: req.user_id } });
 
-	for(const rmem of requested_member) {
-		if(rmem.premium_since) {
-			if(premium_guild_since){
-				if(premium_guild_since > rmem.premium_since) {
+	for (const rmem of requested_member) {
+		if (rmem.premium_since) {
+			if (premium_guild_since) {
+				if (premium_guild_since > rmem.premium_since) {
 					premium_guild_since = rmem.premium_since;
 				}
 			} else {
 				premium_guild_since = rmem.premium_since;
 			}
 		}
-		for(const smem of self_member) {
+		for (const smem of self_member) {
 			if (smem.guild_id === rmem.guild_id) {
-				mutual_guilds.push({id: rmem.guild_id, nick: rmem.nick})
+				mutual_guilds.push({ id: rmem.guild_id, nick: rmem.nick });
 			}
 		}
 	}
diff --git a/src/api/routes/users/#id/relationships.ts b/src/api/routes/users/#id/relationships.ts
index 61655c25..9b7e3402 100644
--- a/src/api/routes/users/#id/relationships.ts
+++ b/src/api/routes/users/#id/relationships.ts
@@ -1,41 +1,46 @@
-import { Router, Request, Response } from "express";
-import { User } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
 export interface UserRelationsResponse {
 	object: {
-		id?: string,
-		username?: string,
-		avatar?: string, 
-		discriminator?: string, 
-		public_flags?: number
-	}
+		id?: string;
+		username?: string;
+		avatar?: string;
+		discriminator?: string;
+		public_flags?: number;
+	};
 }
 
-
 router.get("/", route({ test: { response: { body: "UserRelationsResponse" } } }), async (req: Request, res: Response) => {
 	let mutual_relations: object[] = [];
-    const requested_relations = await User.findOneOrFail({
+	const requested_relations = await User.findOneOrFail({
 		where: { id: req.params.id },
 		relations: ["relationships"]
 	});
-    const self_relations = await User.findOneOrFail({
+	const self_relations = await User.findOneOrFail({
 		where: { id: req.user_id },
 		relations: ["relationships"]
 	});
-	
-    for(const rmem of requested_relations.relationships) {
-		for(const smem of self_relations.relationships)
-		if (rmem.to_id === smem.to_id && rmem.type === 1 && rmem.to_id !== req.user_id) {
-			let relation_user = await User.getPublicUser(rmem.to_id)
 
-			mutual_relations.push({id: relation_user.id, username: relation_user.username, avatar: relation_user.avatar, discriminator: relation_user.discriminator, public_flags: relation_user.public_flags})
-		}
+	for (const rmem of requested_relations.relationships) {
+		for (const smem of self_relations.relationships)
+			if (rmem.to_id === smem.to_id && rmem.type === 1 && rmem.to_id !== req.user_id) {
+				let relation_user = await User.getPublicUser(rmem.to_id);
+
+				mutual_relations.push({
+					id: relation_user.id,
+					username: relation_user.username,
+					avatar: relation_user.avatar,
+					discriminator: relation_user.discriminator,
+					public_flags: relation_user.public_flags
+				});
+			}
 	}
 
-	res.json(mutual_relations)
+	res.json(mutual_relations);
 });
 
 export default router;
diff --git a/src/api/routes/users/@me/activities/statistics/applications.ts b/src/api/routes/users/@me/activities/statistics/applications.ts
index 014df8af..ba359b47 100644
--- a/src/api/routes/users/@me/activities/statistics/applications.ts
+++ b/src/api/routes/users/@me/activities/statistics/applications.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/affinities/guilds.ts b/src/api/routes/users/@me/affinities/guilds.ts
index 8d744744..e733910f 100644
--- a/src/api/routes/users/@me/affinities/guilds.ts
+++ b/src/api/routes/users/@me/affinities/guilds.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/affinities/users.ts b/src/api/routes/users/@me/affinities/users.ts
index 6d4e4991..758bedc3 100644
--- a/src/api/routes/users/@me/affinities/users.ts
+++ b/src/api/routes/users/@me/affinities/users.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/applications/#app_id/entitlements.ts b/src/api/routes/users/@me/applications/#app_id/entitlements.ts
index 411e95bf..8e407184 100644
--- a/src/api/routes/users/@me/applications/#app_id/entitlements.ts
+++ b/src/api/routes/users/@me/applications/#app_id/entitlements.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/billing/country-code.ts b/src/api/routes/users/@me/billing/country-code.ts
index 33d40796..72601f42 100644
--- a/src/api/routes/users/@me/billing/country-code.ts
+++ b/src/api/routes/users/@me/billing/country-code.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/billing/payment-sources.ts b/src/api/routes/users/@me/billing/payment-sources.ts
index 014df8af..ba359b47 100644
--- a/src/api/routes/users/@me/billing/payment-sources.ts
+++ b/src/api/routes/users/@me/billing/payment-sources.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/billing/subscriptions.ts b/src/api/routes/users/@me/billing/subscriptions.ts
index 411e95bf..8e407184 100644
--- a/src/api/routes/users/@me/billing/subscriptions.ts
+++ b/src/api/routes/users/@me/billing/subscriptions.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/channels.ts b/src/api/routes/users/@me/channels.ts
index ad483529..c17275ec 100644
--- a/src/api/routes/users/@me/channels.ts
+++ b/src/api/routes/users/@me/channels.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
-import { Recipient, DmChannelDTO, Channel, DmChannelCreateSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Channel, DmChannelCreateSchema, DmChannelDTO, Recipient } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/connections.ts b/src/api/routes/users/@me/connections.ts
index 411e95bf..8e407184 100644
--- a/src/api/routes/users/@me/connections.ts
+++ b/src/api/routes/users/@me/connections.ts
@@ -1,5 +1,5 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index 1d81c2b9..dfc6131b 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -1,8 +1,14 @@
-import { Router, Request, Response } from "express";
-import { Guild, Member, User } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import bcrypt from "bcrypt";
-import { HTTPError } from "@fosscord/util";
+import { HTTPError, Member, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/devices.ts b/src/api/routes/users/@me/devices.ts
index 8556a3ad..cb01e576 100644
--- a/src/api/routes/users/@me/devices.ts
+++ b/src/api/routes/users/@me/devices.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/disable.ts b/src/api/routes/users/@me/disable.ts
index 4aff3774..05976908 100644
--- a/src/api/routes/users/@me/disable.ts
+++ b/src/api/routes/users/@me/disable.ts
@@ -1,7 +1,14 @@
-import { User } from "@fosscord/util";
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
-import bcrypt from "bcrypt";
+import { User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/email-settings.ts b/src/api/routes/users/@me/email-settings.ts
index 3114984e..28d0864a 100644
--- a/src/api/routes/users/@me/email-settings.ts
+++ b/src/api/routes/users/@me/email-settings.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/entitlements.ts b/src/api/routes/users/@me/entitlements.ts
index 341e2b4c..7aaa5d7c 100644
--- a/src/api/routes/users/@me/entitlements.ts
+++ b/src/api/routes/users/@me/entitlements.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/guilds.ts b/src/api/routes/users/@me/guilds.ts
index 4d4fccd4..5141aa3d 100644
--- a/src/api/routes/users/@me/guilds.ts
+++ b/src/api/routes/users/@me/guilds.ts
@@ -1,7 +1,6 @@
-import { Router, Request, Response } from "express";
-import { Guild, Member, User, GuildDeleteEvent, GuildMemberRemoveEvent, emitEvent, Config } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { Config, emitEvent, Guild, GuildDeleteEvent, GuildMemberRemoveEvent, HTTPError, Member, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/routes/users/@me/guilds/premium/subscription-slots.ts b/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
index 014df8af..ba359b47 100644
--- a/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
+++ b/src/api/routes/users/@me/guilds/premium/subscription-slots.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index 7d095451..fcb0a9df 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -1,8 +1,24 @@
-import { Router, Request, Response } from "express";
-import { User, PrivateUserProjection, emitEvent, UserUpdateEvent, handleFile, FieldErrors, UserModifySchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import bcrypt from "bcrypt";
-import { OrmUtils, generateToken } from "@fosscord/util";
+import {
+	emitEvent,
+	FieldErrors,
+	generateToken,
+	handleFile,
+	OrmUtils,
+	PrivateUserProjection,
+	User,
+	UserModifySchema,
+	UserUpdateEvent
+} from "@fosscord/util";
+import { Request, Response, Router } from "express";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 
 const router: Router = Router();
 
@@ -37,17 +53,17 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res:
 		}
 		user.data.hash = await bcrypt.hash(body.new_password, 12);
 		user.data.valid_tokens_since = new Date();
-		token = await generateToken(user.id) as string;
+		token = (await generateToken(user.id)) as string;
 	}
 
-    if(body.username){
-        let check_username = body?.username?.replace(/\s/g, '');
-        if(!check_username) {
-            throw FieldErrors({
-                username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
-            });
-        }
-    }
+	if (body.username) {
+		let check_username = body?.username?.replace(/\s/g, "");
+		if (!check_username) {
+			throw FieldErrors({
+				username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
+			});
+		}
+	}
 
 	user = OrmUtils.mergeDeep(user, body);
 	await user.save();
@@ -61,7 +77,7 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res:
 		user_id: req.user_id,
 		data: user
 	} as UserUpdateEvent);
-	
+
 	res.json({
 		...user,
 		token
diff --git a/src/api/routes/users/@me/library.ts b/src/api/routes/users/@me/library.ts
index 7ac13bae..0aea02a0 100644
--- a/src/api/routes/users/@me/library.ts
+++ b/src/api/routes/users/@me/library.ts
@@ -1,5 +1,5 @@
-import { Router, Response, Request } from "express";
 import { route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts
index 4224a1c0..c62581cc 100644
--- a/src/api/routes/users/@me/mfa/codes.ts
+++ b/src/api/routes/users/@me/mfa/codes.ts
@@ -1,7 +1,14 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
 import { BackupCode, Config, FieldErrors, generateMfaBackupCodes, MfaCodesSchema, User } from "@fosscord/util";
-import bcrypt from "bcrypt";
+import { Request, Response, Router } from "express";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 
 const router = Router();
 
@@ -12,25 +19,21 @@ router.post("/", route({ body: "MfaCodesSchema" }), async (req: Request, res: Re
 
 	const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] });
 
-	if (!await bcrypt.compare(password, user.data.hash || "")) {
+	if (!(await bcrypt.compare(password, user.data.hash || ""))) {
 		throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
 	}
 
 	var codes: BackupCode[];
 	if (regenerate && Config.get().security.twoFactor.generateBackupCodes) {
-		await BackupCode.update(
-			{ user: { id: req.user_id } },
-			{ expired: true }
-		);
+		await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
 
 		codes = generateMfaBackupCodes(req.user_id);
-		await Promise.all(codes.map(x => x.save()));
-	}
-	else {
+		await Promise.all(codes.map((x) => x.save()));
+	} else {
 		codes = await BackupCode.find({
 			where: {
 				user: {
-					id: req.user_id,
+					id: req.user_id
 				},
 				expired: false
 			}
@@ -38,8 +41,8 @@ router.post("/", route({ body: "MfaCodesSchema" }), async (req: Request, res: Re
 	}
 
 	return res.json({
-		backup_codes: codes.map(x => ({ ...x, expired: undefined })),
-	})
+		backup_codes: codes.map((x) => ({ ...x, expired: undefined }))
+	});
 });
 
 export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts
index 2fe9355c..6bc9a5c7 100644
--- a/src/api/routes/users/@me/mfa/totp/disable.ts
+++ b/src/api/routes/users/@me/mfa/totp/disable.ts
@@ -1,8 +1,8 @@
-import { Router, Request, Response } from "express";
 import { route } from "@fosscord/api";
-import { verifyToken } from 'node-2fa';
+import { BackupCode, generateToken, TotpDisableSchema, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
-import { User, generateToken, BackupCode, TotpDisableSchema } from "@fosscord/util";
+import { verifyToken } from "node-2fa";
 
 const router = Router();
 
@@ -14,28 +14,27 @@ router.post("/", route({ body: "TotpDisableSchema" }), async (req: Request, res:
 	const backup = await BackupCode.findOne({ where: { code: body.code } });
 	if (!backup) {
 		const ret = verifyToken(user.totp_secret!, body.code);
-		if (!ret || ret.delta != 0)
-			throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+		if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
 	}
 
 	await User.update(
 		{ id: req.user_id },
 		{
 			mfa_enabled: false,
-			totp_secret: "",
-		},
+			totp_secret: ""
+		}
 	);
 
 	await BackupCode.update(
 		{ user: { id: req.user_id } },
 		{
-			expired: true,
+			expired: true
 		}
 	);
 
 	return res.json({
-		token: await generateToken(user.id),
+		token: await generateToken(user.id)
 	});
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index ac668d1d..f3a73c28 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -1,9 +1,16 @@
-import { Router, Request, Response } from "express";
-import { User, generateToken, BackupCode, generateMfaBackupCodes, Config, TotpEnableSchema } from "@fosscord/util";
 import { route } from "@fosscord/api";
-import bcrypt from "bcrypt";
+import { BackupCode, Config, generateMfaBackupCodes, generateToken, TotpEnableSchema, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
-import { verifyToken } from 'node-2fa';
+import { verifyToken } from "node-2fa";
+
+let bcrypt: any;
+try {
+	bcrypt = require("bcrypt");
+} catch {
+	bcrypt = require("bcryptjs");
+	console.log("Warning: using bcryptjs because bcrypt is not installed! Performance will be affected.");
+}
 
 const router = Router();
 
@@ -14,35 +21,29 @@ router.post("/", route({ body: "TotpEnableSchema" }), async (req: Request, res:
 
 	// TODO: Are guests allowed to enable 2fa?
 	if (user.data.hash) {
-		if (!await bcrypt.compare(body.password, user.data.hash)) {
+		if (!(await bcrypt.compare(body.password, user.data.hash))) {
 			throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
 		}
 	}
 
-	if (!body.secret)
-		throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
+	if (!body.secret) throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
 
-	if (!body.code)
-		throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+	if (!body.code) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
 
-	if (verifyToken(body.secret, body.code)?.delta != 0)
-		throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+	if (verifyToken(body.secret, body.code)?.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
 
 	let backup_codes: BackupCode[] = [];
 	if (Config.get().security.twoFactor.generateBackupCodes) {
 		backup_codes = generateMfaBackupCodes(req.user_id);
-		await Promise.all(backup_codes.map(x => x.save()));
+		await Promise.all(backup_codes.map((x) => x.save()));
 	}
 
-	await User.update(
-		{ id: req.user_id },
-		{ mfa_enabled: true, totp_secret: body.secret }
-	);
+	await User.update({ id: req.user_id }, { mfa_enabled: true, totp_secret: body.secret });
 
 	res.send({
 		token: await generateToken(user.id),
-		backup_codes: backup_codes.map(x => ({ ...x, expired: undefined })),
+		backup_codes: backup_codes.map((x) => ({ ...x, expired: undefined }))
 	});
 });
 
-export default router;
\ No newline at end of file
+export default router;
diff --git a/src/api/routes/users/@me/notes.ts b/src/api/routes/users/@me/notes.ts
index f938f088..fc207401 100644
--- a/src/api/routes/users/@me/notes.ts
+++ b/src/api/routes/users/@me/notes.ts
@@ -1,6 +1,6 @@
-import { Request, Response, Router } from "express";
 import { route } from "@fosscord/api";
-import { User, Note, emitEvent, Snowflake } from "@fosscord/util";
+import { emitEvent, Note, Snowflake, User } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
@@ -10,38 +10,31 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
 	const note = await Note.findOneOrFail({
 		where: {
 			owner: { id: req.user_id },
-			target: { id: id },
+			target: { id: id }
 		}
 	});
 
 	return res.json({
 		note: note?.content,
 		note_user_id: id,
-		user_id: req.user_id,
+		user_id: req.user_id
 	});
 });
 
 router.put("/:id", route({}), async (req: Request, res: Response) => {
 	const { id } = req.params;
 	const owner = await User.findOneOrFail({ where: { id: req.user_id } });
-	const target = await User.findOneOrFail({ where: { id: id } });		//if noted user does not exist throw
+	const target = await User.findOneOrFail({ where: { id: id } }); //if noted user does not exist throw
 	const { note } = req.body;
 
 	if (note && note.length) {
 		// upsert a note
 		if (await Note.findOne({ where: { owner: { id: owner.id }, target: { id: target.id } } })) {
-			Note.update(
-				{ owner: { id: owner.id }, target: { id: target.id } },
-				{ owner, target, content: note }
-			);
+			Note.update({ owner: { id: owner.id }, target: { id: target.id } }, { owner, target, content: note });
+		} else {
+			Note.insert({ id: Snowflake.generate(), owner, target, content: note });
 		}
-		else {
-			Note.insert(
-				{ id: Snowflake.generate(), owner, target, content: note }
-			);
-		}
-	}
-	else {
+	} else {
 		await Note.delete({ owner: { id: owner.id }, target: { id: target.id } });
 	}
 
@@ -51,7 +44,7 @@ router.put("/:id", route({}), async (req: Request, res: Response) => {
 			note: note,
 			id: target.id
 		},
-		user_id: owner.id,
+		user_id: owner.id
 	});
 
 	return res.status(204);
diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts
index f7464b99..8267c142 100644
--- a/src/api/routes/users/@me/relationships.ts
+++ b/src/api/routes/users/@me/relationships.ts
@@ -1,18 +1,18 @@
+import { route } from "@fosscord/api";
 import {
-	RelationshipAddEvent,
-	User,
-	PublicUserProjection,
-	RelationshipType,
-	RelationshipRemoveEvent,
+	Config,
+	DiscordApiErrors,
 	emitEvent,
+	HTTPError,
+	OrmUtils,
+	PublicUserProjection,
 	Relationship,
-	Config
+	RelationshipAddEvent,
+	RelationshipRemoveEvent,
+	RelationshipType,
+	User
 } from "@fosscord/util";
-import { Router, Response, Request } from "express";
-import { HTTPError } from "@fosscord/util";
-import { DiscordApiErrors } from "@fosscord/util";
-import { route } from "@fosscord/api";
-import { OrmUtils } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
@@ -42,7 +42,11 @@ router.put("/:id", route({ body: "RelationshipPutSchema" }), async (req: Request
 	return await updateRelationship(
 		req,
 		res,
-		await User.findOneOrFail({ where: { id: req.params.id }, relations: ["relationships", "relationships.to"], select: userProjection }),
+		await User.findOneOrFail({
+			where: { id: req.params.id },
+			relations: ["relationships", "relationships.to"],
+			select: userProjection
+		}),
 		req.body.type ?? RelationshipType.friends
 	);
 });
@@ -132,7 +136,9 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
 			relationship.type = RelationshipType.blocked;
 			await relationship.save();
 		} else {
-			relationship = await (OrmUtils.mergeDeep(new Relationship(), { to_id: id, type: RelationshipType.blocked, from_id: req.user_id }) as Relationship).save();
+			relationship = await (
+				OrmUtils.mergeDeep(new Relationship(), { to_id: id, type: RelationshipType.blocked, from_id: req.user_id }) as Relationship
+			).save();
 		}
 
 		if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
@@ -158,7 +164,12 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
 	const { maxFriends } = Config.get().limits.user;
 	if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
 
-	let incoming_relationship = OrmUtils.mergeDeep(new Relationship(), { nickname: undefined, type: RelationshipType.incoming, to: user, from: friend });
+	let incoming_relationship = OrmUtils.mergeDeep(new Relationship(), {
+		nickname: undefined,
+		type: RelationshipType.incoming,
+		to: user,
+		from: friend
+	});
 	let outgoing_relationship = OrmUtils.mergeDeep(new Relationship(), {
 		nickname: undefined,
 		type: RelationshipType.outgoing,
diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts
index 7578d36e..e276a22a 100644
--- a/src/api/routes/users/@me/settings.ts
+++ b/src/api/routes/users/@me/settings.ts
@@ -1,6 +1,6 @@
-import { Router, Response, Request } from "express";
-import { User, UserSettings } from "@fosscord/util";
 import { route } from "@fosscord/api";
+import { User, UserSettings } from "@fosscord/util";
+import { Request, Response, Router } from "express";
 
 const router = Router();
 
diff --git a/src/api/routes/voice/regions.ts b/src/api/routes/voice/regions.ts
index 4de304ee..eacdcf11 100644
--- a/src/api/routes/voice/regions.ts
+++ b/src/api/routes/voice/regions.ts
@@ -1,6 +1,5 @@
-import { Router, Request, Response } from "express";
-import { getIpAdress, route } from "@fosscord/api";
-import { getVoiceRegions } from "@fosscord/api";
+import { getIpAdress, getVoiceRegions, route } from "@fosscord/api";
+import { Request, Response, Router } from "express";
 
 const router: Router = Router();
 
diff --git a/src/api/start.ts b/src/api/start.ts
index 9ba198e7..c407484d 100644
--- a/src/api/start.ts
+++ b/src/api/start.ts
@@ -1,16 +1,16 @@
 process.on("uncaughtException", console.error);
 process.on("unhandledRejection", console.error);
 
-import { config } from "dotenv";
-config();
-import { FosscordServer } from "./Server";
 import cluster from "cluster";
+import { config } from "dotenv";
 import os from "os";
+import { FosscordServer } from "./Server";
+config();
 let cores = 1;
 try {
 	cores = Number(process.env.THREADS) || os.cpus().length;
 } catch {
-	console.log("[API] Failed to get thread count! Using 1...")
+	console.log("[API] Failed to get thread count! Using 1...");
 }
 
 if (cluster.isMaster && process.env.NODE_ENV == "production") {
diff --git a/src/api/util/entities/AssetCacheItem.ts b/src/api/util/entities/AssetCacheItem.ts
index 160dece6..958d5a61 100644
--- a/src/api/util/entities/AssetCacheItem.ts
+++ b/src/api/util/entities/AssetCacheItem.ts
@@ -1,3 +1,3 @@
 export class AssetCacheItem {
 	constructor(public Key: string, public FilePath: string = "", public Headers: any = null as any) {}
-}
\ No newline at end of file
+}
diff --git a/src/api/util/handlers/Instance.ts b/src/api/util/handlers/Instance.ts
index 7c337270..e03c9488 100644
--- a/src/api/util/handlers/Instance.ts
+++ b/src/api/util/handlers/Instance.ts
@@ -1,5 +1,4 @@
 import { Config, Guild, Session } from "@fosscord/util";
-import { createQueryBuilder } from "typeorm";
 
 export async function initInstance() {
 	// TODO: clean up database and delete tombstone data
@@ -10,7 +9,7 @@ export async function initInstance() {
 	const { autoJoin } = Config.get().guild;
 
 	if (autoJoin.enabled && !autoJoin.guilds?.length) {
-		let guild = await Guild.findOne({where: {}, order: {id: "ASC"}});
+		let guild = await Guild.findOne({ where: {}, order: { id: "ASC" } });
 		if (guild) {
 			// @ts-ignore
 			await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } });
diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts
index ff5ece75..d760d27c 100644
--- a/src/api/util/handlers/Message.ts
+++ b/src/api/util/handlers/Message.ts
@@ -1,32 +1,31 @@
 import {
+	Application,
+	Attachment,
 	Channel,
+	CHANNEL_MENTION,
+	Config,
 	Embed,
 	emitEvent,
+	EVERYONE_MENTION,
+	getPermission,
+	getRights,
 	Guild,
+	HERE_MENTION,
+	HTTPError,
 	Message,
 	MessageCreateEvent,
+	MessageCreateSchema,
+	MessageType,
 	MessageUpdateEvent,
-	getPermission,
-	getRights,
-	CHANNEL_MENTION,
-	Snowflake,
-	USER_MENTION,
-	ROLE_MENTION,
+	OrmUtils,
 	Role,
-	EVERYONE_MENTION,
-	HERE_MENTION,
-	MessageType,
+	ROLE_MENTION,
 	User,
-	Application,
-	Webhook,
-	Attachment,
-	Config,
-	MessageCreateSchema,
+	USER_MENTION,
+	Webhook
 } from "@fosscord/util";
-import { HTTPError } from "@fosscord/util";
-import fetch from "node-fetch";
 import cheerio from "cheerio";
-import { OrmUtils } from "@fosscord/util";
+import fetch from "node-fetch";
 
 const allow_empty = false;
 // TODO: check webhook, application, system author, stickers
@@ -61,21 +60,21 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	});
 
 	if (message.content && message.content.length > Config.get().limits.message.maxCharacters) {
-		throw new HTTPError("Content length over max character limit")
+		throw new HTTPError("Content length over max character limit");
 	}
 
 	if (opts.author_id) {
 		message.author = await User.getPublicUser(opts.author_id);
 		const rights = await getRights(opts.author_id);
 		rights.hasThrow("SEND_MESSAGES");
-	}	
+	}
 	if (opts.application_id) {
 		message.application = await Application.findOneOrFail({ where: { id: opts.application_id } });
 	}
 	if (opts.webhook_id) {
 		message.webhook = await Webhook.findOneOrFail({ where: { id: opts.webhook_id } });
 	}
-	
+
 	const permission = await getPermission(opts.author_id, channel.guild_id, opts.channel_id);
 	permission.hasThrow("SEND_MESSAGES");
 	if (permission.cache.member) {
@@ -89,8 +88,10 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		if (message.guild_id !== null) {
 			const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id } });
 			if (!guild.features.includes("CROSS_CHANNEL_REPLIES")) {
-				if (opts.message_reference.guild_id !== channel.guild_id) throw new HTTPError("You can only reference messages from this guild");
-				if (opts.message_reference.channel_id !== opts.channel_id) throw new HTTPError("You can only reference messages from this channel");
+				if (opts.message_reference.guild_id !== channel.guild_id)
+					throw new HTTPError("You can only reference messages from this guild");
+				if (opts.message_reference.channel_id !== opts.channel_id)
+					throw new HTTPError("You can only reference messages from this channel");
 			}
 		}
 		/** Q: should be checked if the referenced message exists? ANSWER: NO
@@ -100,7 +101,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	}
 
 	// TODO: stickers/activity
-	if (!allow_empty && (!opts.content && !opts.embeds?.length && !opts.attachments?.length && !opts.sticker_ids?.length)) {
+	if (!allow_empty && !opts.content && !opts.embeds?.length && !opts.attachments?.length && !opts.sticker_ids?.length) {
 		throw new HTTPError("Empty messages are not allowed", 50006);
 	}
 
@@ -110,7 +111,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 	let mention_user_ids = [] as string[];
 	let mention_everyone = false;
 
-	if (content) { // TODO: explicit-only mentions
+	if (content) {
+		// TODO: explicit-only mentions
 		message.content = content.trim();
 		for (const [_, mention] of content.matchAll(CHANNEL_MENTION)) {
 			if (!mention_channel_ids.includes(mention)) mention_channel_ids.push(mention);
@@ -158,7 +160,7 @@ export async function postHandleMessage(message: Message) {
 		try {
 			const request = await fetch(link, {
 				...DEFAULT_FETCH_OPTIONS,
-				size: Config.get().limits.message.maxEmbedDownloadSize,
+				size: Config.get().limits.message.maxEmbedDownloadSize
 			});
 
 			const text = await request.text();
diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
index 71e14955..d43ae103 100644
--- a/src/api/util/handlers/route.ts
+++ b/src/api/util/handlers/route.ts
@@ -1,8 +1,6 @@
 import {
 	DiscordApiErrors,
 	EVENT,
-	Event,
-	EventData,
 	FieldErrors,
 	FosscordApiErrors,
 	getPermission,
@@ -12,14 +10,14 @@ import {
 	RightResolvable,
 	Rights
 } from "@fosscord/util";
+import Ajv from "ajv";
+import addFormats from "ajv-formats";
+import { AnyValidateFunction } from "ajv/dist/core";
 import { NextFunction, Request, Response } from "express";
 import fs from "fs";
 import path from "path";
-import Ajv from "ajv";
-import { AnyValidateFunction } from "ajv/dist/core";
-import addFormats from "ajv-formats";
 
-const SchemaPath = path.join(__dirname, "..", "..", "..","..", "assets", "schemas.json");
+const SchemaPath = path.join(__dirname, "..", "..", "..", "..", "assets", "schemas.json");
 const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
 
 export const ajv = new Ajv({
@@ -117,10 +115,10 @@ export function route(opts: RouteOptions) {
 			const valid = validate(normalizeBody(req.body));
 			if (!valid) {
 				const fields: Record<string, { code?: string; message: string }> = {};
-				if(process.env.LOG_INVALID_BODY) {
-					console.log(`Got invalid request: ${req.method} ${req.originalUrl}`)
-					console.log(req.body)
-					validate.errors?.forEach(x => console.log(x.params))
+				if (process.env.LOG_INVALID_BODY) {
+					console.log(`Got invalid request: ${req.method} ${req.originalUrl}`);
+					console.log(req.body);
+					validate.errors?.forEach((x) => console.log(x.params));
 				}
 				validate.errors?.forEach((x) => (fields[x.instancePath.slice(1)] = { code: x.keyword, message: x.message || "" }));
 				throw FieldErrors(fields);
diff --git a/src/api/util/index.ts b/src/api/util/index.ts
index b3c7559f..31e75325 100644
--- a/src/api/util/index.ts
+++ b/src/api/util/index.ts
@@ -6,4 +6,5 @@ export * from "./utility/Base64";
 export * from "./utility/ipAddress";
 export * from "./utility/passwordStrength";
 export * from "./utility/RandomInviteID";
-export * from "./utility/String";
\ No newline at end of file
+export * from "./utility/String";
+export * from "./utility/captcha";
\ No newline at end of file
diff --git a/src/api/util/utility/RandomInviteID.ts b/src/api/util/utility/RandomInviteID.ts
index 7ea344e0..feebfd3d 100644
--- a/src/api/util/utility/RandomInviteID.ts
+++ b/src/api/util/utility/RandomInviteID.ts
@@ -22,11 +22,10 @@ export function snowflakeBasedInvite() {
 	// snowflakes hold ~10.75 characters worth of entropy;
 	// safe to generate a 8-char invite out of them
 	let str = "";
-	for (let i=0; i < 10; i++) {
-		
+	for (let i = 0; i < 10; i++) {
 		str.concat(chars.charAt(Number(snowflake % base)));
 		snowflake = snowflake / base;
 	}
-	
-	return str.substr(3,8).split("").reverse().join("");
+
+	return str.substr(3, 8).split("").reverse().join("");
 }
diff --git a/src/api/util/utility/String.ts b/src/api/util/utility/String.ts
index 982b7e11..a2e491e4 100644
--- a/src/api/util/utility/String.ts
+++ b/src/api/util/utility/String.ts
@@ -1,6 +1,6 @@
+import { FieldErrors } from "@fosscord/util";
 import { Request } from "express";
 import { ntob } from "./Base64";
-import { FieldErrors } from "@fosscord/util";
 
 export function checkLength(str: string, min: number, max: number, key: string, req: Request) {
 	if (str.length < min || str.length > max) {
diff --git a/src/api/util/utility/captcha.ts b/src/api/util/utility/captcha.ts
new file mode 100644
index 00000000..739647d2
--- /dev/null
+++ b/src/api/util/utility/captcha.ts
@@ -0,0 +1,46 @@
+import { Config } from "@fosscord/util";
+import fetch from "node-fetch";
+
+export interface hcaptchaResponse {
+	success: boolean;
+	challenge_ts: string;
+	hostname: string;
+	credit: boolean;
+	"error-codes": string[];
+	score: number;	// enterprise only
+	score_reason: string[];	// enterprise only
+}
+
+export interface recaptchaResponse {
+	success: boolean;
+	score: number; // between 0 - 1
+	action: string;
+	challenge_ts: string;
+	hostname: string;
+	"error-codes"?: string[];
+}
+
+const verifyEndpoints = {
+	hcaptcha: "https://hcaptcha.com/siteverify",
+	recaptcha: "https://www.google.com/recaptcha/api/siteverify",
+}
+
+export async function verifyCaptcha(response: string, ip?: string) {
+	const { security } = Config.get();
+	const { service, secret, sitekey } = security.captcha;
+
+	if (!service) throw new Error("Cannot verify captcha without service");
+
+	const res = await fetch(verifyEndpoints[service], {
+		method: "POST",
+		headers: {
+			"Content-Type": "application/x-www-form-urlencoded",
+		},
+		body: `response=${encodeURIComponent(response)}`
+			+ `&secret=${encodeURIComponent(secret!)}`
+			+ `&sitekey=${encodeURIComponent(sitekey!)}`
+			+ (ip ? `&remoteip=${encodeURIComponent(ip!)}` : ""),
+	});
+
+	return await res.json() as hcaptchaResponse | recaptchaResponse;
+}
\ No newline at end of file
diff --git a/src/api/util/utility/ipAddress.ts b/src/api/util/utility/ipAddress.ts
index 8d986b26..c96feb9e 100644
--- a/src/api/util/utility/ipAddress.ts
+++ b/src/api/util/utility/ipAddress.ts
@@ -78,7 +78,11 @@ export function isProxy(data: typeof exampleData) {
 
 export function getIpAdress(req: Request): string {
 	// @ts-ignore
-	return req.headers[Config.get().security.forwadedFor] || req.socket.remoteAddress;
+	return (
+		req.headers[Config.get().security.forwadedFor as string] ||
+		req.headers[Config.get().security.forwadedFor?.toLowerCase() as string] ||
+		req.socket.remoteAddress
+	);
 }
 
 export function distanceBetweenLocations(loc1: any, loc2: any): number {
diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts
index 8eca63b8..ff83d3df 100644
--- a/src/api/util/utility/passwordStrength.ts
+++ b/src/api/util/utility/passwordStrength.ts
@@ -44,16 +44,16 @@ export function checkPassword(password: string): number {
 	if (password.length == password.count(reNUMBER) || password.length === password.count(reUPPERCASELETTER)) {
 		strength = 0;
 	}
-	
+
 	let entropyMap: { [key: string]: number } = {};
 	for (let i = 0; i < password.length; i++) {
 		if (entropyMap[password[i]]) entropyMap[password[i]]++;
 		else entropyMap[password[i]] = 1;
 	}
-	
+
 	let entropies = Object.values(entropyMap);
-	
-	entropies.map(x => (x / entropyMap.length));
-	strength += entropies.reduceRight((a: number, x: number) => a - (x * Math.log2(x))) / Math.log2(password.length);	
+
+	entropies.map((x) => x / entropyMap.length);
+	strength += entropies.reduceRight((a: number, x: number) => a - x * Math.log2(x)) / Math.log2(password.length);
 	return strength;
 }