summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-28 21:19:19 +0200
committerFlam3rboy <34555296+Flam3rboy@users.noreply.github.com>2021-05-28 21:19:19 +0200
commit614d8f14fa2bac5c4f4357d51b4df527bea93c19 (patch)
tree31c97a8c2bc2c73a9cf35a2fe75a15535bde86e7
parentUpdate attachments.ts (diff)
downloadserver-614d8f14fa2bac5c4f4357d51b4df527bea93c19.tar.xz
:sparkles: attachments
-rw-r--r--.env.example1
-rw-r--r--.gitignore3
-rw-r--r--dist/Server.d.ts29
-rw-r--r--dist/Server.js92
-rw-r--r--dist/Snowflake.d.ts85
-rw-r--r--dist/Snowflake.js131
-rw-r--r--dist/Util.d.ts8
-rw-r--r--dist/Util.js45
-rw-r--r--dist/index.d.ts1
-rw-r--r--dist/index.js15
-rw-r--r--dist/routes/attachments.d.ts2
-rw-r--r--dist/routes/attachments.js48
-rw-r--r--dist/routes/external.d.ts2
-rw-r--r--dist/routes/external.js75
-rw-r--r--package-lock.json222
-rw-r--r--package.json3
-rw-r--r--src/Server.ts2
-rw-r--r--src/routes/attachments.ts42
-rw-r--r--src/routes/external.ts1
-rw-r--r--src/util/FileStorage.ts23
-rw-r--r--src/util/Storage.ts5
21 files changed, 269 insertions, 566 deletions
diff --git a/.env.example b/.env.example
index 0a91585c..b5e011f1 100644
--- a/.env.example
+++ b/.env.example
@@ -1,2 +1,3 @@
 STORAGE_LOCATION=files/
+STORAGE_PROVIDER=file
 PORT=3003
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 6054dfe8..7d04eaee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 .vscode/
 node_modules/
 .DS_Store
-.env
\ No newline at end of file
+.env
+dist/
\ No newline at end of file
diff --git a/dist/Server.d.ts b/dist/Server.d.ts
deleted file mode 100644
index f4d12c65..00000000
--- a/dist/Server.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/// <reference types="node" />
-import { Application, Router } from "express";
-import { Database } from "lambert-db";
-import { Server as HTTPServer } from "http";
-import "express-async-errors";
-export declare type ServerOptions = {
-    db: string;
-    port: number;
-    host: string;
-};
-declare global {
-    namespace Express {
-        interface Request {
-            server: Server;
-        }
-    }
-}
-export declare class Server {
-    app: Application;
-    http: HTTPServer;
-    db: Database;
-    routes: Router[];
-    options: ServerOptions;
-    constructor(options?: Partial<ServerOptions>);
-    init(): Promise<void>;
-    registerRoutes(root: string): Promise<any[]>;
-    registerRoute(root: string, file: string): any;
-    destroy(): Promise<void>;
-}
diff --git a/dist/Server.js b/dist/Server.js
deleted file mode 100644
index 72046dfc..00000000
--- a/dist/Server.js
+++ /dev/null
@@ -1,92 +0,0 @@
-"use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __importDefault = (this && this.__importDefault) || function (mod) {
-    return (mod && mod.__esModule) ? mod : { "default": mod };
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.Server = void 0;
-const express_1 = __importDefault(require("express"));
-const lambert_db_1 = require("lambert-db");
-const Util_1 = require("./Util");
-require("express-async-errors");
-const log = console.log;
-console.log = (content) => {
-    log(`[${new Date().toTimeString().split(" ")[0]}]`, content);
-};
-class Server {
-    constructor(options = { port: 3000, host: "0.0.0.0" }) {
-        this.app = express_1.default();
-        this.db = new lambert_db_1.MongoDatabase(options === null || options === void 0 ? void 0 : options.db);
-        this.options = options;
-    }
-    init() {
-        return __awaiter(this, void 0, void 0, function* () {
-            yield this.db.init();
-            console.log("[Database] connected...");
-            yield new Promise((res, rej) => {
-                this.http = this.app.listen(this.options.port, this.options.host, () => res(null));
-            });
-            this.routes = yield this.registerRoutes(__dirname + "/routes/");
-        });
-    }
-    registerRoutes(root) {
-        return __awaiter(this, void 0, void 0, function* () {
-            this.app.use((req, res, next) => {
-                req.server = this;
-                next();
-            });
-            const routes = yield Util_1.traverseDirectory({ dirname: root, recursive: true }, this.registerRoute.bind(this, root));
-            this.app.use((err, req, res, next) => {
-                res.status(400).send(err);
-                next(err);
-            });
-            return routes;
-        });
-    }
-    registerRoute(root, file) {
-        var _a, _b;
-        if (root.endsWith("/") || root.endsWith("\\"))
-            root = root.slice(0, -1); // removes slash at the end of the root dir
-        let path = file.replace(root, ""); // remove root from path and
-        path = path.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
-        if (path.endsWith("/index"))
-            path = path.slice(0, -6); // delete index from path
-        try {
-            var router = require(file);
-            if (router.router)
-                router = router.router;
-            if (router.default)
-                router = router.default;
-            if (!router || ((_b = (_a = router === null || router === void 0 ? void 0 : router.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name) !== "router")
-                throw `File doesn't export any default router`;
-            this.app.use(path, router);
-            console.log(`[Routes] ${path} registerd`);
-            return router;
-        }
-        catch (error) {
-            console.error(new Error(`[Server] ¯\\_(ツ)_/¯ Failed to register route ${path}: ${error}`));
-        }
-    }
-    destroy() {
-        return __awaiter(this, void 0, void 0, function* () {
-            yield this.db.destroy();
-            yield new Promise((res, rej) => {
-                this.http.close((err) => {
-                    if (err)
-                        return rej(err);
-                    return res("");
-                });
-            });
-        });
-    }
-}
-exports.Server = Server;
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSxzREFBd0Y7QUFDeEYsMkNBQXFEO0FBRXJELGlDQUEyQztBQUUzQyxnQ0FBOEI7QUFFOUIsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztBQUN4QixPQUFPLENBQUMsR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLEVBQUU7SUFDekIsR0FBRyxDQUFDLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUM5RCxDQUFDLENBQUM7QUFnQkYsTUFBYSxNQUFNO0lBT2xCLFlBQVksVUFBa0MsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUU7UUFDNUUsSUFBSSxDQUFDLEdBQUcsR0FBRyxpQkFBTyxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLDBCQUFhLENBQUMsT0FBTyxhQUFQLE9BQU8sdUJBQVAsT0FBTyxDQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBd0IsQ0FBQztJQUN6QyxDQUFDO0lBRUssSUFBSTs7WUFDVCxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxFQUFFLENBQUM7WUFFckIsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1lBQ3ZDLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUU7Z0JBQzlCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8s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
\ No newline at end of file
diff --git a/dist/Snowflake.d.ts b/dist/Snowflake.d.ts
deleted file mode 100644
index 17effce6..00000000
--- a/dist/Snowflake.d.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-export = SnowflakeUtil;
-/**
- * A container for useful snowflake-related methods.
- */
-declare class SnowflakeUtil {
-    /**
-     * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
-     * ```
-     * If we have a snowflake '266241948824764416' we can represent it as binary:
-     *
-     * 64                                          22     17     12          0
-     *  000000111011000111100001101001000101000000  00001  00000  000000000000
-     *       number of ms since Discord epoch       worker  pid    increment
-     * ```
-     * @typedef {string} Snowflake
-     */
-    /**
-     * Transforms a snowflake from a decimal string to a bit string.
-     * @param  {Snowflake} num Snowflake to be transformed
-     * @returns {string}
-     * @private
-     */
-    private static idToBinary;
-    /**
-     * Transforms a snowflake from a bit string to a decimal string.
-     * @param  {string} num Bit string to be transformed
-     * @returns {Snowflake}
-     * @private
-     */
-    private static binaryToID;
-    /**
-     * Generates a Discord snowflake.
-     * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info>
-     * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate
-     * @returns {Snowflake} The generated snowflake
-     */
-    static generate(timestamp?: number | Date | undefined): string;
-    /**
-     * A deconstructed snowflake.
-     * @typedef {Object} DeconstructedSnowflake
-     * @property {number} timestamp Timestamp the snowflake was created
-     * @property {Date} date Date the snowflake was created
-     * @property {number} workerID Worker ID in the snowflake
-     * @property {number} processID Process ID in the snowflake
-     * @property {number} increment Increment in the snowflake
-     * @property {string} binary Binary representation of the snowflake
-     */
-    /**
-     * Deconstructs a Discord snowflake.
-     * @param {Snowflake} snowflake Snowflake to deconstruct
-     * @returns {DeconstructedSnowflake} Deconstructed snowflake
-     */
-    static deconstruct(snowflake: string): {
-        /**
-         * Timestamp the snowflake was created
-         */
-        timestamp: number;
-        /**
-         * Date the snowflake was created
-         */
-        date: Date;
-        /**
-         * Worker ID in the snowflake
-         */
-        workerID: number;
-        /**
-         * Process ID in the snowflake
-         */
-        processID: number;
-        /**
-         * Increment in the snowflake
-         */
-        increment: number;
-        /**
-         * Binary representation of the snowflake
-         */
-        binary: string;
-    };
-    /**
-     * Discord's epoch value (2015-01-01T00:00:00.000Z).
-     * @type {number}
-     * @readonly
-     */
-    static readonly get EPOCH(): number;
-}
diff --git a/dist/Snowflake.js b/dist/Snowflake.js
deleted file mode 100644
index 4a50845e..00000000
--- a/dist/Snowflake.js
+++ /dev/null
@@ -1,131 +0,0 @@
-// @ts-nocheck
-// github.com/discordjs/discord.js/blob/master/src/util/Snowflake.js
-"use strict";
-// Discord epoch (2015-01-01T00:00:00.000Z)
-const EPOCH = 1420070400000;
-let INCREMENT = 0;
-/**
- * A container for useful snowflake-related methods.
- */
-class SnowflakeUtil {
-    constructor() {
-        throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
-    }
-    /**
-     * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
-     * ```
-     * If we have a snowflake '266241948824764416' we can represent it as binary:
-     *
-     * 64                                          22     17     12          0
-     *  000000111011000111100001101001000101000000  00001  00000  000000000000
-     *       number of ms since Discord epoch       worker  pid    increment
-     * ```
-     * @typedef {string} Snowflake
-     */
-    /**
-     * Transforms a snowflake from a decimal string to a bit string.
-     * @param  {Snowflake} num Snowflake to be transformed
-     * @returns {string}
-     * @private
-     */
-    static idToBinary(num) {
-        let bin = "";
-        let high = parseInt(num.slice(0, -10)) || 0;
-        let low = parseInt(num.slice(-10));
-        while (low > 0 || high > 0) {
-            bin = String(low & 1) + bin;
-            low = Math.floor(low / 2);
-            if (high > 0) {
-                low += 5000000000 * (high % 2);
-                high = Math.floor(high / 2);
-            }
-        }
-        return bin;
-    }
-    /**
-     * Transforms a snowflake from a bit string to a decimal string.
-     * @param  {string} num Bit string to be transformed
-     * @returns {Snowflake}
-     * @private
-     */
-    static binaryToID(num) {
-        let dec = "";
-        while (num.length > 50) {
-            const high = parseInt(num.slice(0, -32), 2);
-            const low = parseInt((high % 10).toString(2) + num.slice(-32), 2);
-            dec = (low % 10).toString() + dec;
-            num =
-                Math.floor(high / 10).toString(2) +
-                    Math.floor(low / 10)
-                        .toString(2)
-                        .padStart(32, "0");
-        }
-        num = parseInt(num, 2);
-        while (num > 0) {
-            dec = (num % 10).toString() + dec;
-            num = Math.floor(num / 10);
-        }
-        return dec;
-    }
-    /**
-     * Generates a Discord snowflake.
-     * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info>
-     * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate
-     * @returns {Snowflake} The generated snowflake
-     */
-    static generate(timestamp = Date.now()) {
-        if (timestamp instanceof Date)
-            timestamp = timestamp.getTime();
-        if (typeof timestamp !== "number" || isNaN(timestamp)) {
-            throw new TypeError(`"timestamp" argument must be a number (received ${isNaN(timestamp) ? "NaN" : typeof timestamp})`);
-        }
-        if (INCREMENT >= 4095)
-            INCREMENT = 0;
-        const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, "0")}0000100000${(INCREMENT++)
-            .toString(2)
-            .padStart(12, "0")}`;
-        return SnowflakeUtil.binaryToID(BINARY);
-    }
-    /**
-     * A deconstructed snowflake.
-     * @typedef {Object} DeconstructedSnowflake
-     * @property {number} timestamp Timestamp the snowflake was created
-     * @property {Date} date Date the snowflake was created
-     * @property {number} workerID Worker ID in the snowflake
-     * @property {number} processID Process ID in the snowflake
-     * @property {number} increment Increment in the snowflake
-     * @property {string} binary Binary representation of the snowflake
-     */
-    /**
-     * Deconstructs a Discord snowflake.
-     * @param {Snowflake} snowflake Snowflake to deconstruct
-     * @returns {DeconstructedSnowflake} Deconstructed snowflake
-     */
-    static deconstruct(snowflake) {
-        const BINARY = SnowflakeUtil.idToBinary(snowflake).toString(2).padStart(64, "0");
-        const res = {
-            timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
-            workerID: parseInt(BINARY.substring(42, 47), 2),
-            processID: parseInt(BINARY.substring(47, 52), 2),
-            increment: parseInt(BINARY.substring(52, 64), 2),
-            binary: BINARY,
-        };
-        Object.defineProperty(res, "date", {
-            get: function get() {
-                return new Date(this.timestamp);
-            },
-            enumerable: true,
-        });
-        return res;
-    }
-    /**
-     * Discord's epoch value (2015-01-01T00:00:00.000Z).
-     * @type {number}
-     * @readonly
-     */
-    static get EPOCH() {
-        return EPOCH;
-    }
-}
-module.exports = SnowflakeUtil;
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU25vd2ZsYWtlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1Nub3dmbGFrZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjO0FBRWQsb0VBQW9FO0FBQ3BFLFlBQVksQ0FBQztBQUViLDJDQUEyQztBQUMzQyxNQUFNLEtBQUssR0FBRyxhQUFhLENBQUM7QUFDNUIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO0FBRWxCOztHQUVHO0FBQ0gsTUFBTSxhQUFhO0lBQ2xCO1FBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxpQ0FBaUMsQ0FBQyxDQUFDO0lBQ2hGLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBRUg7Ozs7O09BS0c7SUFDSCxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUc7UUFDcEIsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxJQUFJLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsSUFBSSxHQUFHLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ25DLE9BQU8sR0FBRyxHQUFHLENBQUMsSUFBSSxJQUFJLEdBQUcsQ0FBQyxFQUFFO1lBQzNCLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQztZQUM1QixHQUFHLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDMUIsSUFBSSxJQUFJLEdBQUcsQ0FBQyxFQUFFO2dCQUNiLEdBQUcsSUFBSSxVQUFVLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQy9CLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElB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
\ No newline at end of file
diff --git a/dist/Util.d.ts b/dist/Util.d.ts
deleted file mode 100644
index c0a33362..00000000
--- a/dist/Util.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import "missing-native-js-functions";
-export interface traverseDirectoryOptions {
-    dirname: string;
-    filter?: RegExp;
-    excludeDirs?: RegExp;
-    recursive?: boolean;
-}
-export declare function traverseDirectory<T>(options: traverseDirectoryOptions, action: (path: string) => T): Promise<T[]>;
diff --git a/dist/Util.js b/dist/Util.js
deleted file mode 100644
index 45421484..00000000
--- a/dist/Util.js
+++ /dev/null
@@ -1,45 +0,0 @@
-"use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __importDefault = (this && this.__importDefault) || function (mod) {
-    return (mod && mod.__esModule) ? mod : { "default": mod };
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.traverseDirectory = void 0;
-const promises_1 = __importDefault(require("fs/promises"));
-require("missing-native-js-functions");
-const DEFAULT_EXCLUDE_DIR = /^\./;
-const DEFAULT_FILTER = /^([^\.].*)\.js$/;
-function traverseDirectory(options, action) {
-    return __awaiter(this, void 0, void 0, function* () {
-        if (!options.filter)
-            options.filter = DEFAULT_FILTER;
-        if (!options.excludeDirs)
-            options.excludeDirs = DEFAULT_EXCLUDE_DIR;
-        const routes = yield promises_1.default.readdir(options.dirname);
-        const promises = routes.map((file) => __awaiter(this, void 0, void 0, function* () {
-            const path = options.dirname + file;
-            const stat = yield promises_1.default.lstat(path);
-            if (path.match(options.excludeDirs))
-                return;
-            if (stat.isFile() && path.match(options.filter)) {
-                return action(path);
-            }
-            else if (options.recursive && stat.isDirectory()) {
-                return traverseDirectory(Object.assign(Object.assign({}, options), { dirname: path + "/" }), action);
-            }
-        }));
-        const result = yield Promise.all(promises);
-        const t = result.flat();
-        return t.filter((x) => x != undefined);
-    });
-}
-exports.traverseDirectory = traverseDirectory;
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9VdGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDJEQUE2QjtBQUM3Qix1Q0FBcUM7QUFTckMsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLENBQUM7QUFDbEMsTUFBTSxjQUFjLEdBQUcsaUJBQWlCLENBQUM7QUFFekMsU0FBc0IsaUJBQWlCLENBQ3RDLE9BQWlDLEVBQ2pDLE1BQTJCOztRQUUzQixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU07WUFBRSxPQUFPLENBQUMsTUFBTSxHQUFHLGNBQWMsQ0FBQztRQUNyRCxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVc7WUFBRSxPQUFPLENBQUMsV0FBVyxHQUFHLG1CQUFtQixDQUFDO1FBRXBFLE1BQU0sTUFBTSxHQUFHLE1BQU0sa0JBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2pELE1BQU0sUUFBUSxHQUFtQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQU8sSUFBSSxFQUFFLEVBQUU7WUFDMUUsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFDcEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxrQkFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNsQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQVMsT0FBTyxDQUFDLFdBQVcsQ0FBQztnQkFBRSxPQUFPO1lBRXBELElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQVMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUN4RCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQzthQUNwQjtpQkFBTSxJQUFJLE9BQU8sQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFO2dCQUNuRCxPQUFPLGlCQUFpQixpQ0FBTSxPQUFPLEtBQUUsT0FBTyxFQUFFLElBQUksR0FBRyxHQUFHLEtBQUksTUFBTSxDQUFDLENBQUM7YUFDdEU7UUFDRixDQUFDLENBQUEsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTNDLE1BQU0sQ0FBQyxHQUFzQixNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFM0MsT0FBWSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksU0FBUyxDQUFDLENBQUM7SUFDN0MsQ0FBQztDQUFBO0FBeEJELDhDQXdCQyJ9
\ No newline at end of file
diff --git a/dist/index.d.ts b/dist/index.d.ts
deleted file mode 100644
index cb0ff5c3..00000000
--- a/dist/index.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export {};
diff --git a/dist/index.js b/dist/index.js
deleted file mode 100644
index 792fcefd..00000000
--- a/dist/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-const Server_1 = require("./Server");
-const server = new Server_1.Server();
-server
-    .init()
-    .then(() => {
-    console.log("[Server] started on :" + server.options.port);
-})
-    .catch((e) => console.error("[Server] Error starting: ", e));
-//// server
-//// 	.destroy()
-//// 	.then(() => console.log("[Server] closed."))
-//// .catch((e) => console.log("[Server] Error closing: ", e));
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxxQ0FBa0M7QUFFbEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxlQUFNLEVBQUUsQ0FBQztBQUM1QixNQUFNO0tBQ0osSUFBSSxFQUFFO0tBQ04sSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUM1RCxDQUFDLENBQUM7S0FDRCxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUU5RCxXQUFXO0FBQ1gsZ0JBQWdCO0FBQ2hCLGtEQUFrRDtBQUNsRCwrREFBK0QifQ==
\ No newline at end of file
diff --git a/dist/routes/attachments.d.ts b/dist/routes/attachments.d.ts
deleted file mode 100644
index ae2ab413..00000000
--- a/dist/routes/attachments.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-declare const router: import("express-serve-static-core").Router;
-export default router;
diff --git a/dist/routes/attachments.js b/dist/routes/attachments.js
deleted file mode 100644
index 4b639448..00000000
--- a/dist/routes/attachments.js
+++ /dev/null
@@ -1,48 +0,0 @@
-"use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __importDefault = (this && this.__importDefault) || function (mod) {
-    return (mod && mod.__esModule) ? mod : { "default": mod };
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-const express_1 = require("express");
-const multer_1 = __importDefault(require("multer"));
-const Snowflake_1 = __importDefault(require("../Snowflake"));
-const multer_ = multer_1.default();
-const router = express_1.Router();
-router.post("/:filename", multer_.single("attachment"), (req, res) => __awaiter(void 0, void 0, void 0, function* () {
-    const { buffer, mimetype } = req.file;
-    const { filename } = req.params;
-    const { db } = req.server;
-    const File = {
-        filename,
-        file: buffer.toString("base64"),
-        id: Snowflake_1.default.generate(),
-        type: mimetype,
-    };
-    if (!(yield db.data.attachments.push(File)))
-        throw new Error("Error uploading file");
-    return res.status(201).send({ success: true, message: "attachment uploaded", id: File.id, filename });
-}));
-router.get("/:hash/:filename", (req, res) => __awaiter(void 0, void 0, void 0, function* () {
-    const { db } = req.server;
-    const { hash, filename } = req.params;
-    const File = yield db.data.attachments({ id: hash, filename: filename }).get();
-    res.set("Content-Type", File.type);
-    return res.send(Buffer.from(File.file, "base64"));
-}));
-router.delete("/:hash/:filename", (req, res) => __awaiter(void 0, void 0, void 0, function* () {
-    const { hash, filename } = req.params;
-    const { db } = req.server;
-    yield db.data.attachments({ id: hash, filename: filename }).delete();
-    return res.send({ success: true, message: "attachment deleted" });
-}));
-exports.default = router;
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXR0YWNobWVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcm91dGVzL2F0dGFjaG1lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQUEscUNBQWlDO0FBQ2pDLG9EQUE0QjtBQUM1Qiw2REFBcUM7QUFFckMsTUFBTSxPQUFPLEdBQUcsZ0JBQU0sRUFBRSxDQUFDO0FBQ3pCLE1BQU0sTUFBTSxHQUFHLGdCQUFNLEVBQUUsQ0FBQztBQVN4QixNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQU8sR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO0lBQzFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztJQUN0QyxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUNoQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUUxQixNQUFNLElBQUksR0FBZTtRQUN4QixRQUFRO1FBQ1IsSUFBSSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO1FBQy9CLEVBQUUsRUFBRSxtQkFBUyxDQUFDLFFBQVEsRUFBRTtRQUN4QixJQUFJLEVBQUUsUUFBUTtLQUNkLENBQUM7SUFFRixJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUVyRixPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztBQUN2RyxDQUFDLENBQUEsQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxDQUFPLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRTtJQUNqRCxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUMxQixNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFFdEMsTUFBTSxJQUFJLEdBQWUsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7SUFFM0YsR0FBRyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25DLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztBQUNuRCxDQUFDLENBQUEsQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxDQUFPLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRTtJQUNwRCxNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFDdEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFFMUIsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDckUsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO0FBQ25FLENBQUMsQ0FBQSxDQUFDLENBQUM7QUFFSCxrQkFBZSxNQUFNLENBQUMifQ==
\ No newline at end of file
diff --git a/dist/routes/external.d.ts b/dist/routes/external.d.ts
deleted file mode 100644
index ae2ab413..00000000
--- a/dist/routes/external.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-declare const router: import("express-serve-static-core").Router;
-export default router;
diff --git a/dist/routes/external.js b/dist/routes/external.js
deleted file mode 100644
index 751388f1..00000000
--- a/dist/routes/external.js
+++ /dev/null
@@ -1,75 +0,0 @@
-"use strict";
-var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-    return new (P || (P = Promise))(function (resolve, reject) {
-        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-        step((generator = generator.apply(thisArg, _arguments || [])).next());
-    });
-};
-var __importDefault = (this && this.__importDefault) || function (mod) {
-    return (mod && mod.__esModule) ? mod : { "default": mod };
-};
-Object.defineProperty(exports, "__esModule", { value: true });
-const body_parser_1 = __importDefault(require("body-parser"));
-const express_1 = require("express");
-const node_fetch_1 = __importDefault(require("node-fetch"));
-const cheerio_1 = __importDefault(require("cheerio"));
-const btoa_1 = __importDefault(require("btoa"));
-const url_1 = require("url");
-const router = express_1.Router();
-const DEFAULT_FETCH_OPTIONS = {
-    redirect: "follow",
-    follow: 1,
-    headers: {
-        "user-agent": "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)",
-    },
-    size: 1024 * 1024 * 8,
-    compress: true,
-    method: "GET",
-};
-router.post("/", body_parser_1.default.json(), (req, res) => __awaiter(void 0, void 0, void 0, function* () {
-    if (!req.body)
-        throw new Error("Invalid Body (url missing) \nExample: url:https://discord.com");
-    const { db } = req.server;
-    const { url } = req.body;
-    const ID = btoa_1.default(url);
-    const cache = yield db.data.crawler({ id: ID }).get();
-    if (cache)
-        return res.send(cache);
-    try {
-        const request = yield node_fetch_1.default(url, DEFAULT_FETCH_OPTIONS);
-        const text = yield request.text();
-        const ツ = cheerio_1.default.load(text);
-        const ogTitle = ツ('meta[property="og:title"]').attr("content");
-        const ogDescription = ツ('meta[property="og:description"]').attr("content");
-        const ogImage = ツ('meta[property="og:image"]').attr("content");
-        const ogUrl = ツ('meta[property="og:url"]').attr("content");
-        const ogType = ツ('meta[property="og:type"]').attr("content");
-        const filename = new url_1.URL(url).host.split(".")[0];
-        const ImageResponse = yield node_fetch_1.default(ogImage, DEFAULT_FETCH_OPTIONS);
-        const ImageType = ImageResponse.headers.get("content-type");
-        const ImageExtension = ImageType === null || ImageType === void 0 ? void 0 : ImageType.split("/")[1];
-        const ImageResponseBuffer = (yield ImageResponse.buffer()).toString("base64");
-        const cachedImage = `/external/${ID}/${filename}.${ImageExtension}`;
-        yield db.data.externals.push({ image: ImageResponseBuffer, id: ID, type: ImageType });
-        const new_cache_entry = { id: ID, ogTitle, ogDescription, cachedImage, ogUrl, ogType };
-        yield db.data.crawler.push(new_cache_entry);
-        res.send(new_cache_entry);
-    }
-    catch (error) {
-        console.log(error);
-        throw new Error("Couldn't fetch website");
-    }
-}));
-router.get("/:id/:filename", (req, res) => __awaiter(void 0, void 0, void 0, function* () {
-    const { db } = req.server;
-    const { id, filename } = req.params;
-    const { image, type } = yield db.data.externals({ id: id }).get();
-    const imageBuffer = Buffer.from(image, "base64");
-    res.set("Content-Type", type);
-    res.send(imageBuffer);
-}));
-exports.default = router;
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0ZXJuYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcm91dGVzL2V4dGVybmFsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQUEsOERBQXFDO0FBQ3JDLHFDQUFpQztBQUNqQyw0REFBK0I7QUFDL0Isc0RBQThCO0FBQzlCLGdEQUF3QjtBQUN4Qiw2QkFBMEI7QUFFMUIsTUFBTSxNQUFNLEdBQUcsZ0JBQU0sRUFBRSxDQUFDO0FBV3hCLE1BQU0scUJBQXFCLEdBQVE7SUFDbEMsUUFBUSxFQUFFLFFBQVE7SUFDbEIsTUFBTSxFQUFFLENBQUM7SUFDVCxPQUFPLEVBQUU7UUFDUixZQUFZLEVBQUUsbUVBQW1FO0tBQ2pGO0lBQ0QsSUFBSSxFQUFFLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNyQixRQUFRLEVBQUUsSUFBSTtJQUNkLE1BQU0sRUFBRSxLQUFLO0NBQ2IsQ0FBQztBQUVGLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLHFCQUFVLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBTyxHQUFHLEVBQUUsR0FBRyxFQUFFLEVBQUU7SUFDdEQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQywrREFBK0QsQ0FBQyxDQUFDO0lBRWhHLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDO0lBQzFCLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBRXpCLE1BQU0sRUFBRSxHQUFHLGNBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUVyQixNQUFNLEtBQUssR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDdEQsSUFBSSxLQUFLO1FBQUUsT0FBTyxHQUFHLENBQUMsSUFB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
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 623e59c1..c51b11e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,13 +9,14 @@
 			"version": "1.0.0",
 			"license": "ISC",
 			"dependencies": {
-				"@fosscord/server-util": "^1.3.3",
+				"@fosscord/server-util": "^1.3.8",
 				"body-parser": "^1.19.0",
 				"btoa": "^1.2.1",
 				"cheerio": "^1.0.0-rc.5",
 				"dotenv": "^10.0.0",
 				"express": "^4.17.1",
 				"express-async-errors": "^3.1.1",
+				"file-type": "^16.5.0",
 				"lambert-db": "^1.2.3",
 				"lambert-server": "^1.2.1",
 				"missing-native-js-functions": "^1.0.8",
@@ -34,9 +35,9 @@
 			}
 		},
 		"node_modules/@fosscord/server-util": {
-			"version": "1.3.3",
-			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.3.tgz",
-			"integrity": "sha512-fiEQQ93kOLXSTQBOW6PB5Th6ZHH1ozMP1nWeTjdnmr32g7X8BWJkmDMXWfKuR2PNuNr0eNJG4j1lbhIqefDqUA==",
+			"version": "1.3.8",
+			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.8.tgz",
+			"integrity": "sha512-bqCoCcuXRCDvloWcmQDSGVEAeHTgme4idBquL93Q/AxVe0l8J2hv+qm6bJ9mtK+TYPJhUlzku4H+jnMbH9msGg==",
 			"dependencies": {
 				"@types/jsonwebtoken": "^8.5.0",
 				"@types/mongoose-autopopulate": "^0.10.1",
@@ -53,6 +54,11 @@
 				"typescript": "^4.1.3"
 			}
 		},
+		"node_modules/@tokenizer/token": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz",
+			"integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w=="
+		},
 		"node_modules/@types/body-parser": {
 			"version": "1.19.0",
 			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
@@ -89,6 +95,11 @@
 				"@types/node": "*"
 			}
 		},
+		"node_modules/@types/debug": {
+			"version": "4.1.5",
+			"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
+			"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
+		},
 		"node_modules/@types/express": {
 			"version": "4.17.12",
 			"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz",
@@ -196,6 +207,15 @@
 			"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
 			"dev": true
 		},
+		"node_modules/@types/readable-stream": {
+			"version": "2.3.10",
+			"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.10.tgz",
+			"integrity": "sha512-xwSXvAv9x4B9Vj88AMZnFyEVLilz1EBxKvRUhGqIF4nJpRQBSTm7jS236X4Y9Y2qPsVvaMxwrGJlNhLHEahlFQ==",
+			"dependencies": {
+				"@types/node": "*",
+				"safe-buffer": "*"
+			}
+		},
 		"node_modules/@types/serve-static": {
 			"version": "1.13.8",
 			"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
@@ -702,6 +722,22 @@
 			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
 		},
+		"node_modules/file-type": {
+			"version": "16.5.0",
+			"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.0.tgz",
+			"integrity": "sha512-OxgWA9tbL8N/WP00GD1z8O0MiwQKFyWRs1q+3FhjdvcGgKqwxcejyGWso3n4/IMU6DdwV+ARZ4A7TTnPkDcSiw==",
+			"dependencies": {
+				"readable-web-to-node-stream": "^3.0.0",
+				"strtok3": "^6.0.3",
+				"token-types": "^2.0.0"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"url": "https://github.com/sindresorhus/file-type?sponsor=1"
+			}
+		},
 		"node_modules/finalhandler": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -794,6 +830,25 @@
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/ieee754": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+			"funding": [
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/feross"
+				},
+				{
+					"type": "patreon",
+					"url": "https://www.patreon.com/feross"
+				},
+				{
+					"type": "consulting",
+					"url": "https://feross.org/support"
+				}
+			]
+		},
 		"node_modules/inherits": {
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
@@ -1229,6 +1284,18 @@
 			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 			"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
 		},
+		"node_modules/peek-readable": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.3.tgz",
+			"integrity": "sha512-mpAcysyRJxmICBcBa5IXH7SZPvWkcghm6Fk8RekoS3v+BpbSzlZzuWbMx+GXrlUwESi9qHar4nVEZNMKylIHvg==",
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/process-nextick-args": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -1298,6 +1365,35 @@
 				"util-deprecate": "~1.0.1"
 			}
 		},
+		"node_modules/readable-web-to-node-stream": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.1.tgz",
+			"integrity": "sha512-4zDC6CvjUyusN7V0QLsXVB7pJCD9+vtrM9bYDRv6uBQ+SKfx36rp5AFNPRgh9auKRul/a1iFZJYXcCbwRL+SaA==",
+			"dependencies": {
+				"@types/readable-stream": "^2.3.9",
+				"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/regexp-clone": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
@@ -1436,6 +1532,23 @@
 				"safe-buffer": "~5.1.0"
 			}
 		},
+		"node_modules/strtok3": {
+			"version": "6.0.8",
+			"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.8.tgz",
+			"integrity": "sha512-QLgv+oiXwXgCgp2PdPPa+Jpp4D9imK9e/0BsyfeFMr6QL6wMVqoVn9+OXQ9I7MZbmUzN6lmitTJ09uwS2OmGcw==",
+			"dependencies": {
+				"@tokenizer/token": "^0.1.1",
+				"@types/debug": "^4.1.5",
+				"peek-readable": "^3.1.3"
+			},
+			"engines": {
+				"node": ">=8"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/toidentifier": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -1444,6 +1557,22 @@
 				"node": ">=0.6"
 			}
 		},
+		"node_modules/token-types": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/token-types/-/token-types-2.1.1.tgz",
+			"integrity": "sha512-wnQcqlreS6VjthyHO3Y/kpK/emflxDBNhlNUPfh7wE39KnuDdOituXomIbyI79vBtF0Ninpkh72mcuRHo+RG3Q==",
+			"dependencies": {
+				"@tokenizer/token": "^0.1.1",
+				"ieee754": "^1.2.1"
+			},
+			"engines": {
+				"node": ">=0.1.98"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/Borewit"
+			}
+		},
 		"node_modules/type-is": {
 			"version": "1.6.18",
 			"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -1529,9 +1658,9 @@
 	},
 	"dependencies": {
 		"@fosscord/server-util": {
-			"version": "1.3.3",
-			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.3.tgz",
-			"integrity": "sha512-fiEQQ93kOLXSTQBOW6PB5Th6ZHH1ozMP1nWeTjdnmr32g7X8BWJkmDMXWfKuR2PNuNr0eNJG4j1lbhIqefDqUA==",
+			"version": "1.3.8",
+			"resolved": "https://registry.npmjs.org/@fosscord/server-util/-/server-util-1.3.8.tgz",
+			"integrity": "sha512-bqCoCcuXRCDvloWcmQDSGVEAeHTgme4idBquL93Q/AxVe0l8J2hv+qm6bJ9mtK+TYPJhUlzku4H+jnMbH9msGg==",
 			"requires": {
 				"@types/jsonwebtoken": "^8.5.0",
 				"@types/mongoose-autopopulate": "^0.10.1",
@@ -1548,6 +1677,11 @@
 				"typescript": "^4.1.3"
 			}
 		},
+		"@tokenizer/token": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz",
+			"integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w=="
+		},
 		"@types/body-parser": {
 			"version": "1.19.0",
 			"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
@@ -1584,6 +1718,11 @@
 				"@types/node": "*"
 			}
 		},
+		"@types/debug": {
+			"version": "4.1.5",
+			"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
+			"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
+		},
 		"@types/express": {
 			"version": "4.17.12",
 			"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz",
@@ -1691,6 +1830,15 @@
 			"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
 			"dev": true
 		},
+		"@types/readable-stream": {
+			"version": "2.3.10",
+			"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.10.tgz",
+			"integrity": "sha512-xwSXvAv9x4B9Vj88AMZnFyEVLilz1EBxKvRUhGqIF4nJpRQBSTm7jS236X4Y9Y2qPsVvaMxwrGJlNhLHEahlFQ==",
+			"requires": {
+				"@types/node": "*",
+				"safe-buffer": "*"
+			}
+		},
 		"@types/serve-static": {
 			"version": "1.13.8",
 			"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
@@ -2119,6 +2267,16 @@
 			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
 		},
+		"file-type": {
+			"version": "16.5.0",
+			"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.0.tgz",
+			"integrity": "sha512-OxgWA9tbL8N/WP00GD1z8O0MiwQKFyWRs1q+3FhjdvcGgKqwxcejyGWso3n4/IMU6DdwV+ARZ4A7TTnPkDcSiw==",
+			"requires": {
+				"readable-web-to-node-stream": "^3.0.0",
+				"strtok3": "^6.0.3",
+				"token-types": "^2.0.0"
+			}
+		},
 		"finalhandler": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -2190,6 +2348,11 @@
 				"safer-buffer": ">= 2.1.2 < 3"
 			}
 		},
+		"ieee754": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+			"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+		},
 		"inherits": {
 			"version": "2.0.3",
 			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
@@ -2541,6 +2704,11 @@
 			"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
 			"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
 		},
+		"peek-readable": {
+			"version": "3.1.3",
+			"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.3.tgz",
+			"integrity": "sha512-mpAcysyRJxmICBcBa5IXH7SZPvWkcghm6Fk8RekoS3v+BpbSzlZzuWbMx+GXrlUwESi9qHar4nVEZNMKylIHvg=="
+		},
 		"process-nextick-args": {
 			"version": "2.0.1",
 			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -2595,6 +2763,27 @@
 				"util-deprecate": "~1.0.1"
 			}
 		},
+		"readable-web-to-node-stream": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.1.tgz",
+			"integrity": "sha512-4zDC6CvjUyusN7V0QLsXVB7pJCD9+vtrM9bYDRv6uBQ+SKfx36rp5AFNPRgh9auKRul/a1iFZJYXcCbwRL+SaA==",
+			"requires": {
+				"@types/readable-stream": "^2.3.9",
+				"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"
+					}
+				}
+			}
+		},
 		"regexp-clone": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
@@ -2714,11 +2903,30 @@
 				"safe-buffer": "~5.1.0"
 			}
 		},
+		"strtok3": {
+			"version": "6.0.8",
+			"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.8.tgz",
+			"integrity": "sha512-QLgv+oiXwXgCgp2PdPPa+Jpp4D9imK9e/0BsyfeFMr6QL6wMVqoVn9+OXQ9I7MZbmUzN6lmitTJ09uwS2OmGcw==",
+			"requires": {
+				"@tokenizer/token": "^0.1.1",
+				"@types/debug": "^4.1.5",
+				"peek-readable": "^3.1.3"
+			}
+		},
 		"toidentifier": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
 			"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
 		},
+		"token-types": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/token-types/-/token-types-2.1.1.tgz",
+			"integrity": "sha512-wnQcqlreS6VjthyHO3Y/kpK/emflxDBNhlNUPfh7wE39KnuDdOituXomIbyI79vBtF0Ninpkh72mcuRHo+RG3Q==",
+			"requires": {
+				"@tokenizer/token": "^0.1.1",
+				"ieee754": "^1.2.1"
+			}
+		},
 		"type-is": {
 			"version": "1.6.18",
 			"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
diff --git a/package.json b/package.json
index 35599d84..da374117 100644
--- a/package.json
+++ b/package.json
@@ -20,13 +20,14 @@
 	},
 	"homepage": "https://github.com/discord-open-source/discord-cdn#readme",
 	"dependencies": {
-		"@fosscord/server-util": "^1.3.3",
+		"@fosscord/server-util": "^1.3.8",
 		"body-parser": "^1.19.0",
 		"btoa": "^1.2.1",
 		"cheerio": "^1.0.0-rc.5",
 		"dotenv": "^10.0.0",
 		"express": "^4.17.1",
 		"express-async-errors": "^3.1.1",
+		"file-type": "^16.5.0",
 		"lambert-db": "^1.2.3",
 		"lambert-server": "^1.2.1",
 		"missing-native-js-functions": "^1.0.8",
diff --git a/src/Server.ts b/src/Server.ts
index 3ad794be..de02a585 100644
--- a/src/Server.ts
+++ b/src/Server.ts
@@ -18,7 +18,7 @@ export class CDNServer extends Server {
 		await Config.init();
 		console.log("[Database] connected");
 
-		await this.registerRoutes(path.join(__dirname, "routes"));
+		await this.registerRoutes(path.join(__dirname, "routes/"));
 		return super.start();
 	}
 
diff --git a/src/routes/attachments.ts b/src/routes/attachments.ts
index 730d2bb1..f477d1b2 100644
--- a/src/routes/attachments.ts
+++ b/src/routes/attachments.ts
@@ -2,6 +2,8 @@ import { Router } from "express";
 import multer from "multer";
 import { Config, Snowflake } from "@fosscord/server-util";
 import { storage } from "../util/Storage";
+import FileType from "file-type";
+import { HTTPError } from "lambert-server";
 
 const multer_ = multer({
 	storage: multer.memoryStorage(),
@@ -13,42 +15,46 @@ const multer_ = multer({
 });
 const router = Router();
 
-router.post("/:channel_id", multer_.single("attachment"), async (req, res) => {
-	const { buffer, mimetype, stream, size, originalname, fieldname } = req.file;
+router.post("/:channel_id", multer_.single("file"), async (req, res) => {
+	const { buffer, mimetype, size, originalname, fieldname } = req.file;
 	const { channel_id } = req.params;
-	const filename = originalname.replaceAll(" ", "_").replace(/\W+/g, "");
-	
-	const endpoint = Config.get().cdn.endpoint || "http://localhost:3003";
+	const filename = originalname.replaceAll(" ", "_").replace(/[^a-zA-Z0-9._]+/g, "");
+	const id = Snowflake.generate();
+	const path = `attachments/${channel_id}/${id}/${filename}`;
 
-	await storage.set(originalname, buffer);
+	const endpoint = Config.get().cdn.endpoint || "http://localhost:3003";
 
-	const id = Snowflake.generate();
+	await storage.set(path, buffer);
 
 	const file = {
 		id,
-		type: mimetype,
 		content_type: mimetype,
-		filename: originalname,
+		filename: filename,
 		size,
-		url: `${endpoint}/attachments/${channel_id}/${id}/`,
+		url: `${endpoint}/attachments/${channel_id}/${id}/${filename}`,
 	};
 
 	return res.json(file);
 });
 
-router.get("/:hash/:filename", async (req, res) => {
-	const { hash, filename } = req.params;
+router.get("/:channel_id/:id/:filename", async (req, res) => {
+	const { channel_id, id, filename } = req.params;
+
+	const file = await storage.get(`attachments/${channel_id}/${id}/${filename}`);
+	if (!file) throw new HTTPError("File not found");
+	const result = await FileType.fromBuffer(file);
 
-	const File = await db.data.attachments({ id: hash, filename: filename }).get();
+	res.set("Content-Type", result?.mime);
 
-	res.set("Content-Type", File.type);
-	return res.send(Buffer.from(File.file, "base64"));
+	return res.send(file);
 });
 
-router.delete("/:hash/:filename", async (req, res) => {
-	const { hash, filename } = req.params;
+router.delete("/:channel_id/:id/:filename", async (req, res) => {
+	const { channel_id, id, filename } = req.params;
+	const path = `attachments/${channel_id}/${id}/${filename}`;
+
+	storage.delete(path);
 
-	await db.data.attachments({ id: hash, filename: filename }).delete();
 	return res.send({ success: true, message: "attachment deleted" });
 });
 
diff --git a/src/routes/external.ts b/src/routes/external.ts
index 045eb7da..3bcb39b0 100644
--- a/src/routes/external.ts
+++ b/src/routes/external.ts
@@ -1,3 +1,4 @@
+// @ts-nocheck
 import bodyParser from "body-parser";
 import { Router } from "express";
 import fetch from "node-fetch";
diff --git a/src/util/FileStorage.ts b/src/util/FileStorage.ts
index b4d00213..9c9911f3 100644
--- a/src/util/FileStorage.ts
+++ b/src/util/FileStorage.ts
@@ -1,13 +1,30 @@
 import { Storage } from "./Storage";
 import fs from "fs/promises";
 import { join } from "path";
+import "missing-native-js-functions";
 
 export class FileStorage implements Storage {
-	async get(path: string) {
-		return fs.readFile(join(process.env.STORAGE_LOCATION || "", path), { encoding: "binary" });
+	async get(path: string): Promise<Buffer | null> {
+		path = join(process.env.STORAGE_LOCATION || "", path);
+		try {
+			const file = await fs.readFile(path);
+			// @ts-ignore
+			return file;
+		} catch (error) {
+			return null;
+		}
 	}
 
 	async set(path: string, value: any) {
-		return fs.writeFile(join(process.env.STORAGE_LOCATION || "", path), value, { encoding: "binary" });
+		path = join(process.env.STORAGE_LOCATION || "", path);
+		const dir = path.split("/").slice(0, -1).join("/");
+		await fs.mkdir(dir, { recursive: true }).caught();
+
+		return fs.writeFile(path, value, { encoding: "binary" });
+	}
+
+	async delete(path: string) {
+		path = join(process.env.STORAGE_LOCATION || "", path);
+		await fs.unlink(path);
 	}
 }
diff --git a/src/util/Storage.ts b/src/util/Storage.ts
index 391afa83..f8b09e71 100644
--- a/src/util/Storage.ts
+++ b/src/util/Storage.ts
@@ -1,8 +1,9 @@
 import { FileStorage } from "./FileStorage";
 
 export interface Storage {
-	set(path: string, data: any): Promise<void>;
-	get(path: string): Promise<any>;
+	set(path: string, data: Buffer): Promise<void>;
+	get(path: string): Promise<Buffer | null>;
+	delete(path: string): Promise<void>;
 }
 
 var storage: Storage;