summary refs log tree commit diff
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-21 17:35:04 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-21 17:35:04 +1000
commit7ce8543510f586d5d1bde0103591267d9a87549e (patch)
tree0dc7f58b9d7b625f259bedb4dba5f67710fb7bc8
parentadd more default rights (diff)
downloadserver-7ce8543510f586d5d1bde0103591267d9a87549e.tar.xz
fosscord-server/pulls/858
-rw-r--r--api/src/routes/channels/#channel_id/messages/#message_id/index.ts2
-rw-r--r--api/src/routes/channels/#channel_id/messages/index.ts23
-rw-r--r--api/src/routes/users/@me/settings.ts8
-rw-r--r--api/src/util/handlers/Message.ts5
-rw-r--r--bundle/.vscode/launch.json1
-rw-r--r--bundle/package-lock.json37
-rw-r--r--bundle/package.json5
-rw-r--r--gateway/package.json3
-rw-r--r--gateway/src/events/Close.ts1
-rw-r--r--gateway/src/events/Connection.ts7
-rw-r--r--gateway/src/events/Message.ts19
-rw-r--r--gateway/src/opcodes/Identify.ts9
-rw-r--r--gateway/src/schema/Identify.ts17
-rw-r--r--gateway/src/util/Send.ts4
-rw-r--r--gateway/src/util/WebSocket.ts3
-rw-r--r--package-lock.json333
-rw-r--r--util/src/entities/Channel.ts5
-rw-r--r--util/src/entities/Config.ts36
-rw-r--r--util/src/entities/Guild.ts6
-rw-r--r--util/src/entities/Message.ts2
-rw-r--r--util/src/entities/User.ts21
-rw-r--r--util/src/interfaces/Event.ts1
-rw-r--r--util/src/migrations/1660678870706-opencordFixes.ts53
-rw-r--r--util/src/migrations/1660689892073-mobileFixes2.ts31
-rw-r--r--util/src/util/Database.ts2
25 files changed, 411 insertions, 223 deletions
diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
index 63fee9b9..37734397 100644
--- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -135,7 +135,7 @@ router.put(
 			embeds,
 			channel_id,
 			attachments,
-			edited_timestamp: undefined,
+			edited_timestamp: null,
 			timestamp: new Date(snowflake.timestamp),
 		});
 
diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts
index 849968f9..f3c3503f 100644
--- a/api/src/routes/channels/#channel_id/messages/index.ts
+++ b/api/src/routes/channels/#channel_id/messages/index.ts
@@ -13,7 +13,8 @@ import {
 	MessageCreateEvent,
 	Snowflake,
 	uploadFile,
-	Member
+	Member,
+	Role,
 } from "@fosscord/util";
 import { HTTPError } from "lambert-server";
 import { handleMessage, postHandleMessage, route } from "@fosscord/api";
@@ -146,11 +147,11 @@ router.get("/", async (req: Request, res: Response) => {
 			Some clients ( discord.js ) only check if a property exists within the response,
 			which causes erorrs when, say, the `application` property is `null`.
 			**/
-			
-			for (var curr in x) {
-				if (x[curr] === null)
-					delete x[curr];
-			}
+
+			// for (var curr in x) {
+			// 	if (x[curr] === null)
+			// 		delete x[curr];
+			// }
 
 			return x;
 		})
@@ -217,7 +218,7 @@ router.post(
 			embeds,
 			channel_id,
 			attachments,
-			edited_timestamp: undefined,
+			edited_timestamp: null,
 			timestamp: new Date()
 		});
 
@@ -244,8 +245,12 @@ router.post(
 			);
 		}
 	
-		//Fix for the client bug
-		delete message.member
+		const member = await Member.findOneOrFail({ where: { id: req.user_id }, relations: ["roles"] });
+		member.roles = member.roles.filter((role: Role) => {
+			return role.id !== role.guild_id;
+		}).map((role: Role) => {
+			return role.id;
+		}) as any;
 		
 		await Promise.all([
 			message.save(),
diff --git a/api/src/routes/users/@me/settings.ts b/api/src/routes/users/@me/settings.ts
index b22b72fb..50a00cac 100644
--- a/api/src/routes/users/@me/settings.ts
+++ b/api/src/routes/users/@me/settings.ts
@@ -6,6 +6,14 @@ const router = Router();
 
 export interface UserSettingsSchema extends Partial<UserSettings> {}
 
+router.get("/", route({}), async (req: Request, res: Response) => {
+	const user = await User.findOneOrFail(
+		{ id: req.user_id },
+		{ relations: ["settings"] }
+	)
+	return res.json(user.settings);
+});
+
 router.patch("/", route({ body: "UserSettingsSchema" }), async (req: Request, res: Response) => {
 	const body = req.body as UserSettings;
 	if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale
diff --git a/api/src/util/handlers/Message.ts b/api/src/util/handlers/Message.ts
index a6754bd1..8980b4cc 100644
--- a/api/src/util/handlers/Message.ts
+++ b/api/src/util/handlers/Message.ts
@@ -55,7 +55,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> {
 		attachments: opts.attachments || [],
 		embeds: opts.embeds || [],
 		reactions: /*opts.reactions ||*/[],
-		type: opts.type ?? 0
+		type: opts.type ?? 0,
+		edited_timestamp: null
 	});
 
 	if (message.content && message.content.length > Config.get().limits.message.maxCharacters) {
@@ -278,6 +279,6 @@ interface MessageOptions extends MessageCreateSchema {
 	embeds?: Embed[];
 	channel_id?: string;
 	attachments?: Attachment[];
-	edited_timestamp?: Date;
+	edited_timestamp: Date | null;
 	timestamp?: Date;
 }
diff --git a/bundle/.vscode/launch.json b/bundle/.vscode/launch.json
index d7129ed8..6e1a34b2 100644
--- a/bundle/.vscode/launch.json
+++ b/bundle/.vscode/launch.json
@@ -23,6 +23,7 @@
 		},

 		{

 			"sourceMaps": true,

+			"resolveSourceMapLocations": null, /* allow breakpoints in modules other than bundle */

 			"type": "node",

 			"request": "launch",

 			"name": "Launch Server",

diff --git a/bundle/package-lock.json b/bundle/package-lock.json
index 14b94933..4046e7b6 100644
--- a/bundle/package-lock.json
+++ b/bundle/package-lock.json
@@ -32,6 +32,7 @@
 				"exif-be-gone": "^1.2.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
+				"fast-zlib": "^2.0.1",
 				"file-type": "^16.5.4",
 				"form-data": "^4.0.0",
 				"fs-extra": "^10.0.0",
@@ -82,7 +83,7 @@
 				"@types/jsonwebtoken": "^8.5.0",
 				"@types/morgan": "^1.9.3",
 				"@types/multer": "^1.4.7",
-				"@types/node": "^14.17.9",
+				"@types/node": "^14.18.24",
 				"@types/node-fetch": "^2.5.12",
 				"@types/node-os-utils": "^1.2.0",
 				"@types/sharp": "^0.30.4",
@@ -178,7 +179,7 @@
 				"exif-be-gone": "^1.2.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
-				"file-type": "^16.5.0",
+				"file-type": "^16.5.4",
 				"form-data": "^4.0.0",
 				"fs-extra": "^10.0.0",
 				"image-size": "^1.0.0",
@@ -218,6 +219,7 @@
 				"@fosscord/util": "file:../util",
 				"amqplib": "^0.8.0",
 				"dotenv": "^8.2.0",
+				"fast-zlib": "^2.0.1",
 				"jsonwebtoken": "^8.5.1",
 				"lambert-server": "^1.2.11",
 				"missing-native-js-functions": "^1.2.18",
@@ -229,7 +231,7 @@
 			"devDependencies": {
 				"@types/amqplib": "^0.8.1",
 				"@types/jsonwebtoken": "^8.5.0",
-				"@types/node": "^14.17.9",
+				"@types/node": "^14.18.24",
 				"@types/node-fetch": "^2.5.12",
 				"@types/ws": "^7.4.0",
 				"@zerollup/ts-transform-paths": "^1.7.18",
@@ -3653,8 +3655,9 @@
 			}
 		},
 		"node_modules/@types/node": {
-			"version": "14.17.21",
-			"integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA=="
+			"version": "14.18.24",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.24.tgz",
+			"integrity": "sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w=="
 		},
 		"node_modules/@types/node-fetch": {
 			"version": "2.5.12",
@@ -5437,6 +5440,15 @@
 				"url": "https://paypal.me/naturalintelligence"
 			}
 		},
+		"node_modules/fast-zlib": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/fast-zlib/-/fast-zlib-2.0.1.tgz",
+			"integrity": "sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw==",
+			"funding": {
+				"type": "patreon",
+				"url": "https://patreon.com/timotejroiko"
+			}
+		},
 		"node_modules/fb-watchman": {
 			"version": "2.0.1",
 			"integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==",
@@ -13214,7 +13226,7 @@
 				"exif-be-gone": "^1.2.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
-				"file-type": "^16.5.0",
+				"file-type": "^16.5.4",
 				"form-data": "^4.0.0",
 				"fs-extra": "^10.0.0",
 				"image-size": "^1.0.0",
@@ -13237,13 +13249,14 @@
 				"@fosscord/util": "file:../util",
 				"@types/amqplib": "^0.8.1",
 				"@types/jsonwebtoken": "^8.5.0",
-				"@types/node": "^14.17.9",
+				"@types/node": "^14.18.24",
 				"@types/node-fetch": "^2.5.12",
 				"@types/ws": "^7.4.0",
 				"@yukikaze-bot/erlpack": "^1.0.1",
 				"@zerollup/ts-transform-paths": "^1.7.18",
 				"amqplib": "^0.8.0",
 				"dotenv": "^8.2.0",
+				"fast-zlib": "^2.0.1",
 				"jsonwebtoken": "^8.5.1",
 				"lambert-server": "^1.2.11",
 				"missing-native-js-functions": "^1.2.18",
@@ -13946,8 +13959,9 @@
 			}
 		},
 		"@types/node": {
-			"version": "14.17.21",
-			"integrity": "sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA=="
+			"version": "14.18.24",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.24.tgz",
+			"integrity": "sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w=="
 		},
 		"@types/node-fetch": {
 			"version": "2.5.12",
@@ -15313,6 +15327,11 @@
 			"version": "3.19.0",
 			"integrity": "sha512-4pXwmBplsCPv8FOY1WRakF970TjNGnGnfbOnLqjlYvMiF1SR3yOHyxMR/YCXpPTOspNF5gwudqktIP4VsWkvBg=="
 		},
+		"fast-zlib": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/fast-zlib/-/fast-zlib-2.0.1.tgz",
+			"integrity": "sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw=="
+		},
 		"fb-watchman": {
 			"version": "2.0.1",
 			"integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==",
diff --git a/bundle/package.json b/bundle/package.json
index 3b79962d..b8678f81 100644
--- a/bundle/package.json
+++ b/bundle/package.json
@@ -40,7 +40,7 @@
 		"@types/jsonwebtoken": "^8.5.0",
 		"@types/morgan": "^1.9.3",
 		"@types/multer": "^1.4.7",
-		"@types/node": "^14.17.9",
+		"@types/node": "^14.18.24",
 		"@types/node-fetch": "^2.5.12",
 		"@types/node-os-utils": "^1.2.0",
 		"@types/supertest": "^2.0.11",
@@ -112,6 +112,7 @@
 		"typescript-cached-transpile": "^0.0.6",
 		"typescript-json-schema": "^0.50.1",
 		"ws": "^7.4.2",
-		"sharp": "^0.30.7"
+		"sharp": "^0.30.7",
+		"fast-zlib": "^2.0.1"
 	}
 }
\ No newline at end of file
diff --git a/gateway/package.json b/gateway/package.json
index 0524cc40..205cd9c1 100644
--- a/gateway/package.json
+++ b/gateway/package.json
@@ -17,7 +17,7 @@
 	"devDependencies": {
 		"@types/amqplib": "^0.8.1",
 		"@types/jsonwebtoken": "^8.5.0",
-		"@types/node": "^14.17.9",
+		"@types/node": "^14.18.24",
 		"@types/node-fetch": "^2.5.12",
 		"@types/ws": "^7.4.0",
 		"@zerollup/ts-transform-paths": "^1.7.18",
@@ -29,6 +29,7 @@
 		"@fosscord/util": "file:../util",
 		"amqplib": "^0.8.0",
 		"dotenv": "^8.2.0",
+		"fast-zlib": "^2.0.1",
 		"jsonwebtoken": "^8.5.1",
 		"lambert-server": "^1.2.11",
 		"missing-native-js-functions": "^1.2.18",
diff --git a/gateway/src/events/Close.ts b/gateway/src/events/Close.ts
index 5b7c512c..40d9a6f7 100644
--- a/gateway/src/events/Close.ts
+++ b/gateway/src/events/Close.ts
@@ -13,6 +13,7 @@ export async function Close(this: WebSocket, code: number, reason: string) {
 	if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout);
 	if (this.readyTimeout) clearTimeout(this.readyTimeout);
 	this.deflate?.close();
+	this.inflate?.close();
 	this.removeAllListeners();
 
 	if (this.session_id) {
diff --git a/gateway/src/events/Connection.ts b/gateway/src/events/Connection.ts
index 2d41b7a3..af897ed7 100644
--- a/gateway/src/events/Connection.ts
+++ b/gateway/src/events/Connection.ts
@@ -6,7 +6,7 @@ import { setHeartbeat } from "../util/Heartbeat";
 import { IncomingMessage } from "http";
 import { Close } from "./Close";
 import { Message } from "./Message";
-import { createDeflate } from "zlib";
+import { Deflate, Inflate } from "fast-zlib";
 import { URL } from "url";
 import { Config } from "@fosscord/util";
 var erlpack: any;
@@ -45,7 +45,6 @@ export async function Connection(
 			return socket.close(CLOSECODES.Decode_error);
 		}
 
-		// @ts-ignore
 		socket.version = Number(searchParams.get("version")) || 8;
 		if (socket.version != 8)
 			return socket.close(CLOSECODES.Invalid_API_version);
@@ -55,8 +54,8 @@ export async function Connection(
 		if (socket.compress) {
 			if (socket.compress !== "zlib-stream")
 				return socket.close(CLOSECODES.Decode_error);
-			socket.deflate = createDeflate({ chunkSize: 65535 });
-			socket.deflate.on("data", (chunk) => socket.send(chunk));
+			socket.deflate = new Deflate();
+			socket.inflate = new Inflate();
 		}
 
 		socket.events = {};
diff --git a/gateway/src/events/Message.ts b/gateway/src/events/Message.ts
index b675afcd..83917690 100644
--- a/gateway/src/events/Message.ts
+++ b/gateway/src/events/Message.ts
@@ -3,7 +3,7 @@ import { WebSocket, Payload } from "@fosscord/gateway";
 var erlpack: any;
 try {
 	erlpack = require("@yukikaze-bot/erlpack");
-} catch (error) {}
+} catch (error) { }
 import OPCodeHandlers from "../opcodes";
 import { Tuple } from "lambert-server";
 import { check } from "../opcodes/instanceOf";
@@ -22,8 +22,19 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 
 	if (this.encoding === "etf" && buffer instanceof Buffer)
 		data = erlpack.unpack(buffer);
-	else if (this.encoding === "json" && typeof buffer === "string")
-		data = JSON.parse(buffer);
+	else if (this.encoding === "json" && buffer instanceof Buffer) {
+		if (this.inflate) {
+			try {
+				buffer = this.inflate.process(buffer) as any;
+			} catch {
+				buffer = buffer.toString() as any;
+			}
+		}
+		data = JSON.parse(buffer as string);
+	}
+	else if (typeof buffer == "string") {
+		data = JSON.parse(buffer as string);
+	}
 	else return;
 
 	check.call(this, PayloadSchema, data);
@@ -42,6 +53,6 @@ export async function Message(this: WebSocket, buffer: WS.Data) {
 	} catch (error) {
 		console.error(error);
 		// if (!this.CLOSED && this.CLOSING)
-			return this.close(CLOSECODES.Unknown_error);
+		return this.close(CLOSECODES.Unknown_error);
 	}
 }
diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts
index 301f714d..041512c5 100644
--- a/gateway/src/opcodes/Identify.ts
+++ b/gateway/src/opcodes/Identify.ts
@@ -175,7 +175,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 			avatar: related_user.avatar,
 			bot: related_user.bot,
 			bio: related_user.bio,
-			premium_since: user.premium_since
+			premium_since: user.premium_since,
+			accent_color: related_user.accent_color,
 		};
 		users.push(public_related_user);
 	}
@@ -222,10 +223,12 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		premium: user.premium,
 		premium_type: user.premium_type,
 		public_flags: user.public_flags,
+		premium_usage_flags: user.premium_usage_flags,
+		purchased_flags: user.purchased_flags,
 		username: user.username,
 		verified: user.verified,
 		bot: user.bot,
-		accent_color: user.accent_color || 0,
+		accent_color: user.accent_color,
 		banner: user.banner,
 		bio: user.bio,
 		premium_since: user.premium_since
@@ -274,6 +277,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
 		users: users.filter((x) => x).unique(),
 		merged_members: merged_members,
 		// shard // TODO: only for user sharding
+		sessions: [], // TODO:
+		presences: [], // TODO:
 	};
 
 	// TODO: send real proper data structure
diff --git a/gateway/src/schema/Identify.ts b/gateway/src/schema/Identify.ts
index 6aa93ce7..6f68b515 100644
--- a/gateway/src/schema/Identify.ts
+++ b/gateway/src/schema/Identify.ts
@@ -42,7 +42,14 @@ export const IdentifySchema = {
 		$read_state_version: Number,
 		$user_guild_settings_version: Number,
 		$user_settings_version: undefined,
-		$useruser_guild_settings_version: Number,
+		$useruser_guild_settings_version: undefined,
+	},
+	$clientState: {
+		$guildHashes: Object,
+		$highestLastMessageId: String || Number,
+		$readStateVersion: Number,
+		$useruserGuildSettingsVersion: undefined,
+		$userGuildSettingsVersion: undefined,
 	},
 	$v: Number,
 	$version: Number,
@@ -76,6 +83,7 @@ export interface IdentifySchema {
 	presence?: ActivitySchema;
 	compress?: boolean;
 	large_threshold?: number;
+	largeThreshold?: number;
 	shard?: [bigint, bigint];
 	guild_subscriptions?: boolean;
 	capabilities?: number;
@@ -87,5 +95,12 @@ export interface IdentifySchema {
 		user_settings_version?: number;
 		useruser_guild_settings_version?: number;
 	};
+	clientState?: {
+		guildHashes?: any;
+		highestLastMessageId?: string | number;
+		readStateVersion?: number;
+		userGuildSettingsVersion?: number;
+		useruserGuildSettingsVersion?: number;
+	};
 	v?: number;
 }
diff --git a/gateway/src/util/Send.ts b/gateway/src/util/Send.ts
index c4202b21..2a4aa5ef 100644
--- a/gateway/src/util/Send.ts
+++ b/gateway/src/util/Send.ts
@@ -14,9 +14,7 @@ export function Send(socket: WebSocket, data: Payload) {
 	else return;
 	// TODO: compression
 	if (socket.deflate) {
-		socket.deflate.write(buffer);
-		socket.deflate.flush();
-		return;
+		buffer = socket.deflate.process(buffer) as Buffer;
 	}
 
 	return new Promise((res, rej) => {
diff --git a/gateway/src/util/WebSocket.ts b/gateway/src/util/WebSocket.ts
index e3313f40..1ca90340 100644
--- a/gateway/src/util/WebSocket.ts
+++ b/gateway/src/util/WebSocket.ts
@@ -1,6 +1,6 @@
 import { Intents, Permissions } from "@fosscord/util";
 import WS from "ws";
-import { Deflate } from "zlib";
+import { Deflate, Inflate } from "fast-zlib";
 
 export interface WebSocket extends WS {
 	version: number;
@@ -11,6 +11,7 @@ export interface WebSocket extends WS {
 	shard_count?: bigint;
 	shard_id?: bigint;
 	deflate?: Deflate;
+	inflate?: Inflate;
 	heartbeatTimeout: NodeJS.Timeout;
 	readyTimeout: NodeJS.Timeout;
 	intents: Intents;
diff --git a/package-lock.json b/package-lock.json
index 9a887d06..ad152edd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -92,7 +92,7 @@
 				"exif-be-gone": "^1.2.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
-				"file-type": "^16.5.0",
+				"file-type": "^16.5.4",
 				"form-data": "^4.0.0",
 				"fs-extra": "^10.0.0",
 				"image-size": "^1.0.0",
@@ -1145,10 +1145,6 @@
 				"xtend": "^4.0.0"
 			}
 		},
-		"cdn/node_modules/@tokenizer/token": {
-			"version": "0.3.0",
-			"license": "MIT"
-		},
 		"cdn/node_modules/@types/bson": {
 			"version": "4.0.5",
 			"license": "MIT",
@@ -1603,21 +1599,6 @@
 			"license": "CC0-1.0",
 			"peer": true
 		},
-		"cdn/node_modules/file-type": {
-			"version": "16.5.3",
-			"license": "MIT",
-			"dependencies": {
-				"readable-web-to-node-stream": "^3.0.0",
-				"strtok3": "^6.2.4",
-				"token-types": "^4.1.1"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sindresorhus/file-type?sponsor=1"
-			}
-		},
 		"cdn/node_modules/follow-redirects": {
 			"version": "1.14.8",
 			"funding": [
@@ -2092,17 +2073,6 @@
 				"node": ">=0.10.0"
 			}
 		},
-		"cdn/node_modules/peek-readable": {
-			"version": "4.0.2",
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/Borewit"
-			}
-		},
 		"cdn/node_modules/readable-stream": {
 			"version": "2.3.7",
 			"license": "MIT",
@@ -2120,32 +2090,6 @@
 			"version": "5.1.2",
 			"license": "MIT"
 		},
-		"cdn/node_modules/readable-web-to-node-stream": {
-			"version": "3.0.2",
-			"license": "MIT",
-			"dependencies": {
-				"readable-stream": "^3.6.0"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/Borewit"
-			}
-		},
-		"cdn/node_modules/readable-web-to-node-stream/node_modules/readable-stream": {
-			"version": "3.6.0",
-			"license": "MIT",
-			"dependencies": {
-				"inherits": "^2.0.3",
-				"string_decoder": "^1.1.1",
-				"util-deprecate": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 6"
-			}
-		},
 		"cdn/node_modules/regexp-clone": {
 			"version": "1.0.0",
 			"license": "MIT"
@@ -2283,36 +2227,6 @@
 				"node": ">=0.10.0"
 			}
 		},
-		"cdn/node_modules/strtok3": {
-			"version": "6.2.4",
-			"license": "MIT",
-			"dependencies": {
-				"@tokenizer/token": "^0.3.0",
-				"peek-readable": "^4.0.1"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/Borewit"
-			}
-		},
-		"cdn/node_modules/token-types": {
-			"version": "4.1.1",
-			"license": "MIT",
-			"dependencies": {
-				"@tokenizer/token": "^0.3.0",
-				"ieee754": "^1.2.1"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/Borewit"
-			}
-		},
 		"cdn/node_modules/traverse": {
 			"version": "0.3.9",
 			"license": "MIT/X11",
@@ -2468,6 +2382,7 @@
 				"@fosscord/util": "file:../util",
 				"amqplib": "^0.8.0",
 				"dotenv": "^8.2.0",
+				"fast-zlib": "^2.0.1",
 				"jsonwebtoken": "^8.5.1",
 				"lambert-server": "^1.2.11",
 				"missing-native-js-functions": "^1.2.18",
@@ -2479,7 +2394,7 @@
 			"devDependencies": {
 				"@types/amqplib": "^0.8.1",
 				"@types/jsonwebtoken": "^8.5.0",
-				"@types/node": "^14.17.9",
+				"@types/node": "^14.18.24",
 				"@types/node-fetch": "^2.5.12",
 				"@types/ws": "^7.4.0",
 				"@zerollup/ts-transform-paths": "^1.7.18",
@@ -4938,6 +4853,11 @@
 			"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz",
 			"integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg=="
 		},
+		"node_modules/@tokenizer/token": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
+			"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
+		},
 		"node_modules/@tootallnate/once": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -5176,9 +5096,9 @@
 			}
 		},
 		"node_modules/@types/node": {
-			"version": "14.18.21",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz",
-			"integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q=="
+			"version": "14.18.24",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.24.tgz",
+			"integrity": "sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w=="
 		},
 		"node_modules/@types/node-fetch": {
 			"version": "2.6.2",
@@ -7270,6 +7190,15 @@
 			"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
 			"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
 		},
+		"node_modules/fast-zlib": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/fast-zlib/-/fast-zlib-2.0.1.tgz",
+			"integrity": "sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw==",
+			"funding": {
+				"type": "patreon",
+				"url": "https://patreon.com/timotejroiko"
+			}
+		},
 		"node_modules/fb-watchman": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -7278,6 +7207,22 @@
 				"bser": "2.1.1"
 			}
 		},
+		"node_modules/file-type": {
+			"version": "16.5.4",
+			"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
+			"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
+			"dependencies": {
+				"readable-web-to-node-stream": "^3.0.0",
+				"strtok3": "^6.2.4",
+				"token-types": "^4.1.1"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/file-type?sponsor=1"
+			}
+		},
 		"node_modules/file-uri-to-path": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
@@ -10939,6 +10884,18 @@
 			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 			"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
 		},
+		"node_modules/peek-readable": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
+			"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/pg": {
 			"version": "8.7.3",
 			"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz",
@@ -11301,6 +11258,42 @@
 				"string_decoder": "~0.10.x"
 			}
 		},
+		"node_modules/readable-web-to-node-stream": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
+			"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
+			"dependencies": {
+				"readable-stream": "^3.6.0"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
+		"node_modules/readable-web-to-node-stream/node_modules/readable-stream": {
+			"version": "3.6.0",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+			"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+			"dependencies": {
+				"inherits": "^2.0.3",
+				"string_decoder": "^1.1.1",
+				"util-deprecate": "^1.0.1"
+			},
+			"engines": {
+				"node": ">= 6"
+			}
+		},
+		"node_modules/readable-web-to-node-stream/node_modules/string_decoder": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+			"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+			"dependencies": {
+				"safe-buffer": "~5.2.0"
+			}
+		},
 		"node_modules/readdirp": {
 			"version": "3.6.0",
 			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -11957,6 +11950,22 @@
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
+		"node_modules/strtok3": {
+			"version": "6.3.0",
+			"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
+			"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
+			"dependencies": {
+				"@tokenizer/token": "^0.3.0",
+				"peek-readable": "^4.1.0"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/superagent": {
 			"version": "8.0.0",
 			"resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz",
@@ -12302,6 +12311,22 @@
 				"node": ">=0.6"
 			}
 		},
+		"node_modules/token-types": {
+			"version": "4.2.1",
+			"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
+			"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
+			"dependencies": {
+				"@tokenizer/token": "^0.3.0",
+				"ieee754": "^1.2.1"
+			},
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/tough-cookie": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
@@ -14650,7 +14675,7 @@
 				"@types/multer": "^1.4.7",
 				"@types/node": "^14.17.0",
 				"@types/node-fetch": "^2.5.7",
-				"@types/sharp": "*",
+				"@types/sharp": "^0.30.4",
 				"@zerollup/ts-transform-paths": "^1.7.18",
 				"body-parser": "^1.19.0",
 				"btoa": "^1.2.1",
@@ -14658,7 +14683,7 @@
 				"exif-be-gone": "^1.2.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
-				"file-type": "^16.5.0",
+				"file-type": "^16.5.4",
 				"form-data": "^4.0.0",
 				"fs-extra": "^10.0.0",
 				"image-size": "^1.0.0",
@@ -15441,9 +15466,6 @@
 						"xtend": "^4.0.0"
 					}
 				},
-				"@tokenizer/token": {
-					"version": "0.3.0"
-				},
 				"@types/bson": {
 					"version": "4.0.5",
 					"requires": {
@@ -15772,14 +15794,6 @@
 					"version": "1.0.22",
 					"peer": true
 				},
-				"file-type": {
-					"version": "16.5.3",
-					"requires": {
-						"readable-web-to-node-stream": "^3.0.0",
-						"strtok3": "^6.2.4",
-						"token-types": "^4.1.1"
-					}
-				},
 				"follow-redirects": {
 					"version": "1.14.8",
 					"peer": true
@@ -16113,9 +16127,6 @@
 						"lcid": "^1.0.0"
 					}
 				},
-				"peek-readable": {
-					"version": "4.0.2"
-				},
 				"readable-stream": {
 					"version": "2.3.7",
 					"requires": {
@@ -16133,22 +16144,6 @@
 						}
 					}
 				},
-				"readable-web-to-node-stream": {
-					"version": "3.0.2",
-					"requires": {
-						"readable-stream": "^3.6.0"
-					},
-					"dependencies": {
-						"readable-stream": {
-							"version": "3.6.0",
-							"requires": {
-								"inherits": "^2.0.3",
-								"string_decoder": "^1.1.1",
-								"util-deprecate": "^1.0.1"
-							}
-						}
-					}
-				},
 				"regexp-clone": {
 					"version": "1.0.0"
 				},
@@ -16249,20 +16244,6 @@
 						}
 					}
 				},
-				"strtok3": {
-					"version": "6.2.4",
-					"requires": {
-						"@tokenizer/token": "^0.3.0",
-						"peek-readable": "^4.0.1"
-					}
-				},
-				"token-types": {
-					"version": "4.1.1",
-					"requires": {
-						"@tokenizer/token": "^0.3.0",
-						"ieee754": "^1.2.1"
-					}
-				},
 				"traverse": {
 					"version": "0.3.9",
 					"peer": true
@@ -16389,6 +16370,7 @@
 				"@zerollup/ts-transform-paths": "^1.7.18",
 				"amqplib": "^0.8.0",
 				"dotenv": "^8.2.0",
+				"fast-zlib": "^2.0.1",
 				"jsonwebtoken": "^8.5.1",
 				"lambert-server": "^1.2.11",
 				"missing-native-js-functions": "^1.2.18",
@@ -17055,6 +17037,11 @@
 			"resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz",
 			"integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg=="
 		},
+		"@tokenizer/token": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
+			"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
+		},
 		"@tootallnate/once": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -17290,9 +17277,9 @@
 			}
 		},
 		"@types/node": {
-			"version": "14.18.21",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz",
-			"integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q=="
+			"version": "14.18.24",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.24.tgz",
+			"integrity": "sha512-aJdn8XErcSrfr7k8ZDDfU6/2OgjZcB2Fu9d+ESK8D7Oa5mtsv8Fa8GpcwTA0v60kuZBaalKPzuzun4Ov1YWO/w=="
 		},
 		"@types/node-fetch": {
 			"version": "2.6.2",
@@ -18917,6 +18904,11 @@
 			"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
 			"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
 		},
+		"fast-zlib": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/fast-zlib/-/fast-zlib-2.0.1.tgz",
+			"integrity": "sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw=="
+		},
 		"fb-watchman": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -18925,6 +18917,16 @@
 				"bser": "2.1.1"
 			}
 		},
+		"file-type": {
+			"version": "16.5.4",
+			"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
+			"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
+			"requires": {
+				"readable-web-to-node-stream": "^3.0.0",
+				"strtok3": "^6.2.4",
+				"token-types": "^4.1.1"
+			}
+		},
 		"file-uri-to-path": {
 			"version": "2.0.0",
 			"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
@@ -21652,6 +21654,11 @@
 			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 			"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
 		},
+		"peek-readable": {
+			"version": "4.1.0",
+			"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
+			"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="
+		},
 		"pg": {
 			"version": "8.7.3",
 			"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz",
@@ -21927,6 +21934,34 @@
 				"string_decoder": "~0.10.x"
 			}
 		},
+		"readable-web-to-node-stream": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
+			"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
+			"requires": {
+				"readable-stream": "^3.6.0"
+			},
+			"dependencies": {
+				"readable-stream": {
+					"version": "3.6.0",
+					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+					"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+					"requires": {
+						"inherits": "^2.0.3",
+						"string_decoder": "^1.1.1",
+						"util-deprecate": "^1.0.1"
+					}
+				},
+				"string_decoder": {
+					"version": "1.3.0",
+					"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+					"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+					"requires": {
+						"safe-buffer": "~5.2.0"
+					}
+				}
+			}
+		},
 		"readdirp": {
 			"version": "3.6.0",
 			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -22409,6 +22444,15 @@
 			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
 			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
 		},
+		"strtok3": {
+			"version": "6.3.0",
+			"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
+			"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
+			"requires": {
+				"@tokenizer/token": "^0.3.0",
+				"peek-readable": "^4.1.0"
+			}
+		},
 		"superagent": {
 			"version": "8.0.0",
 			"resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.0.tgz",
@@ -22680,6 +22724,15 @@
 			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
 			"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
 		},
+		"token-types": {
+			"version": "4.2.1",
+			"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
+			"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
+			"requires": {
+				"@tokenizer/token": "^0.3.0",
+				"ieee754": "^1.2.1"
+			}
+		},
 		"tough-cookie": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts
index 3e8cd5ef..10fa03ff 100644
--- a/util/src/entities/Channel.ts
+++ b/util/src/entities/Channel.ts
@@ -108,8 +108,8 @@ export class Channel extends BaseClass {
 	@Column({ nullable: true })

 	user_limit?: number;

 

-	@Column({ nullable: true })

-	nsfw?: boolean;

+	@Column()

+	nsfw: boolean = false;

 

 	@Column({ nullable: true })

 	rate_limit_per_user?: number;

@@ -291,6 +291,7 @@ export class Channel extends BaseClass {
 					(x) =>

 						new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) })

 				),

+				nsfw: false,

 			}).save();

 		}

 

diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts
index a1fef058..ac1af7f3 100644
--- a/util/src/entities/Config.ts
+++ b/util/src/entities/Config.ts
@@ -444,38 +444,4 @@ export const DefaultConfigOptions: ConfigValue = {
 		traceSampleRate: 1.0,
 		environment: hostname()
 	}
-};
-
-
-console.log((
-	Rights.FLAGS.MANAGE_GUILDS +
-	Rights.FLAGS.MANAGE_MESSAGES +
-	Rights.FLAGS.MANAGE_TICKETS +
-	Rights.FLAGS.MANAGE_USERS +
-	Rights.FLAGS.CREATE_CHANNELS +
-	Rights.FLAGS.CREATE_DMS +
-	Rights.FLAGS.CREATE_DM_GROUPS +
-	Rights.FLAGS.CREATE_GUILDS +
-	Rights.FLAGS.CREATE_INVITES +
-	Rights.FLAGS.CREATE_ROLES +
-	Rights.FLAGS.CREATE_TEMPLATES +
-	Rights.FLAGS.CREATE_WEBHOOKS +
-	Rights.FLAGS.JOIN_GUILDS +
-	Rights.FLAGS.PIN_MESSAGES +
-	Rights.FLAGS.SELF_ADD_REACTIONS +
-	Rights.FLAGS.SELF_DELETE_MESSAGES +
-	Rights.FLAGS.SELF_EDIT_MESSAGES +
-	Rights.FLAGS.SELF_EDIT_NAME +
-	Rights.FLAGS.SEND_MESSAGES +
-	Rights.FLAGS.USE_ACTIVITIES +
-	Rights.FLAGS.USE_VIDEO +
-	Rights.FLAGS.USE_VOICE +
-	Rights.FLAGS.INVITE_USERS +
-	Rights.FLAGS.SELF_DELETE_DISABLE +
-	Rights.FLAGS.DEBTABLE +
-	Rights.FLAGS.KICK_BAN_MEMBERS +
-	Rights.FLAGS.SELF_LEAVE_GROUPS +
-	Rights.FLAGS.SELF_ADD_DISCOVERABLE +
-	Rights.FLAGS.USE_ACHIEVEMENTS +
-	Rights.FLAGS.USE_MASS_INVITES
-).toString())
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts
index a5b732e8..143cb542 100644
--- a/util/src/entities/Guild.ts
+++ b/util/src/entities/Guild.ts
@@ -267,8 +267,8 @@ export class Guild extends BaseClass {
 	@Column({ nullable: true })
 	nsfw_level?: number;
 
-	@Column({ nullable: true })
-	nsfw?: boolean;
+	@Column()
+	nsfw: boolean;
 	
 	// TODO: nested guilds
 	@Column({ nullable: true })
@@ -335,7 +335,7 @@ export class Guild extends BaseClass {
 			unicode_emoji: null
 		}).save();
 
-		if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general" }];
+		if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general", nsfw: false }];
 
 		const ids = new Map();
 
diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts
index 013e92a9..83607ed4 100644
--- a/util/src/entities/Message.ts
+++ b/util/src/entities/Message.ts
@@ -122,7 +122,7 @@ export class Message extends BaseClass {
 	timestamp: Date;
 
 	@Column({ nullable: true })
-	edited_timestamp?: Date;
+	edited_timestamp: Date;
 
 	@Column({ nullable: true })
 	tts?: boolean;
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index a8f7f0c3..cac2784a 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -30,6 +30,8 @@ export enum PrivateUserEnum {
 	nsfw_allowed,
 	premium,
 	premium_type,
+	purchased_flags,
+	premium_usage_flags,
 	disabled,
 	settings,
 	// locale
@@ -53,8 +55,6 @@ export interface UserPrivate extends Pick<User, PrivateUserKeys> {
 	locale: string;
 }
 
-// TODO: add purchased_flags, premium_usage_flags
-
 @Entity("users")
 export class User extends BaseClass {
 	@Column()
@@ -139,6 +139,12 @@ export class User extends BaseClass {
 	@Column()
 	public_flags: number;
 
+	@Column()
+	purchased_flags: number;
+
+	@Column()
+	premium_usage_flags: number;
+
 	@Column({ type: "bigint" })
 	rights: string; // Rights
 
@@ -281,6 +287,8 @@ export class User extends BaseClass {
 				valid_tokens_since: new Date(),
 			},
 			settings: { ...defaultSettings, locale: language },
+			purchased_flags: 5, // TODO: idk what the values for this are
+			premium_usage_flags: 2,  // TODO: idk what the values for this are
 			extended_settings: {},
 			fingerprints: [],
 			notes: {},
@@ -332,6 +340,11 @@ export const defaultSettings: UserSettings = {
 	stream_notifications_enabled: false,
 	theme: "dark",
 	timezone_offset: 0, // TODO: timezone from request
+
+	banner_color: null,
+	friend_discovery_flags: 0,
+	view_nsfw_guilds: true,
+	passwordless: false,
 };
 
 export interface UserSettings {
@@ -377,6 +390,10 @@ export interface UserSettings {
 	stream_notifications_enabled: boolean;
 	theme: "dark" | "white"; // dark
 	timezone_offset: number; // e.g -60
+	banner_color: string | null;
+	friend_discovery_flags: number;
+	view_nsfw_guilds: boolean;
+	passwordless: boolean;
 }
 
 export const CUSTOM_USER_FLAG_OFFSET = BigInt(1) << BigInt(32);
diff --git a/util/src/interfaces/Event.ts b/util/src/interfaces/Event.ts
index 416082ed..59f995db 100644
--- a/util/src/interfaces/Event.ts
+++ b/util/src/interfaces/Event.ts
@@ -98,6 +98,7 @@ export interface ReadyEventData {
 	merged_members?: PublicMember[][];
 	// probably all users who the user is in contact with
 	users?: PublicUser[];
+	sessions: any[];
 }
 
 export interface ReadyEvent extends Event {
diff --git a/util/src/migrations/1660678870706-opencordFixes.ts b/util/src/migrations/1660678870706-opencordFixes.ts
new file mode 100644
index 00000000..1f10c212
--- /dev/null
+++ b/util/src/migrations/1660678870706-opencordFixes.ts
@@ -0,0 +1,53 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class opencordFixes1660678870706 implements MigrationInterface {
+    name = 'opencordFixes1660678870706'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD \`purchased_flags\` int NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\`
+            ADD \`premium_usage_flags\` int NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\`
+            ADD \`friend_discovery_flags\` int NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\`
+            ADD \`view_nsfw_guilds\` tinyint NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\`
+            ADD \`passwordless\` tinyint NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NOT NULL
+        `);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`users\` CHANGE \`mfa_enabled\` \`mfa_enabled\` tinyint NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\` DROP COLUMN \`passwordless\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\` DROP COLUMN \`view_nsfw_guilds\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\` DROP COLUMN \`friend_discovery_flags\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP COLUMN \`premium_usage_flags\`
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`users\` DROP COLUMN \`purchased_flags\`
+        `);
+    }
+
+}
\ No newline at end of file
diff --git a/util/src/migrations/1660689892073-mobileFixes2.ts b/util/src/migrations/1660689892073-mobileFixes2.ts
new file mode 100644
index 00000000..34328966
--- /dev/null
+++ b/util/src/migrations/1660689892073-mobileFixes2.ts
@@ -0,0 +1,31 @@
+import { MigrationInterface, QueryRunner } from "typeorm";
+
+export class mobileFixes21660689892073 implements MigrationInterface {
+    name = 'mobileFixes21660689892073'
+
+    public async up(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\`
+            ADD \`banner_color\` varchar(255) NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NOT NULL
+        `);
+    }
+
+    public async down(queryRunner: QueryRunner): Promise<void> {
+        await queryRunner.query(`
+            ALTER TABLE \`guilds\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`channels\` CHANGE \`nsfw\` \`nsfw\` tinyint NULL
+        `);
+        await queryRunner.query(`
+            ALTER TABLE \`user_settings\` DROP COLUMN \`banner_color\`
+        `);
+    }
+
+}
\ No newline at end of file
diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts
index 9ab5d14c..2973e114 100644
--- a/util/src/util/Database.ts
+++ b/util/src/util/Database.ts
@@ -29,7 +29,7 @@ export function initDatabase(): Promise<Connection> {
 		url: isSqlite ? undefined : dbConnectionString,
 		database: isSqlite ? dbConnectionString : undefined,
 		// @ts-ignore
-		entities: Object.values(Models).filter((x) => x.constructor.name !== "Object" && x.name),
+		entities: Object.values(Models).filter((x) => x?.constructor?.name !== "Object" && x?.name),
 		synchronize: type !== "mongodb",
 		logging: false,
 		cache: {