From 4adf2bdc54645f185c87d25cc355fb38ab8cfdf0 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 29 Aug 2021 17:11:01 +0200 Subject: [PATCH 1/5] added /avatars unittests [cdn] --- cdn/tests/server.test.js | 57 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/cdn/tests/server.test.js b/cdn/tests/server.test.js index 13046034..6f06c2b6 100644 --- a/cdn/tests/server.test.js +++ b/cdn/tests/server.test.js @@ -67,7 +67,6 @@ describe("/attachments", () => { expect(response.statusCode).toBe(200); expect(response.headers["content-type"]).toEqual(expect.stringContaining("json")); expect(response.body.url).toBeDefined(); - attachment_url = response.body.url; }); }); }); @@ -98,3 +97,59 @@ describe("/attachments", () => { }); }); }); + +describe("/avatars", () => { + describe("POST", () => { + describe("without signature specified", () => { + test("route should respond with 400", async () => { + const response = await request.post("/avatars/123456789"); + expect(response.statusCode).toBe(400); + }); + }); + describe("with signature specified, without file specified", () => { + test("route should respond with 400", async () => { + const response = await request + .post("/avatars/123456789") + .set({ signature: Config.get().security.requestSignature }); + expect(response.statusCode).toBe(400); + }); + }); + describe("with signature specified, with file specified ", () => { + test("route should respond with Content-type: application/json, 200 and res.body.url", async () => { + const response = await request + .post("/avatars/123456789") + .set({ signature: Config.get().security.requestSignature }) + .attach("file", __dirname + "/antman.jpg"); + expect(response.statusCode).toBe(200); + expect(response.headers["content-type"]).toEqual(expect.stringContaining("json")); + expect(response.body.url).toBeDefined(); + }); + }); + }); + describe("GET", () => { + describe("getting uploaded image by url returned by POST /avatars", () => { + test("route should respond with 200", async () => { + let response = await request + .post("/avatars/123456789") + .set({ signature: Config.get().security.requestSignature }) + .attach("file", __dirname + "/antman.jpg"); + request.get(response.body.url.replace("http://localhost:3003", "")).then((x) => { + expect(x.statusCode).toBe(200); + }); + }); + }); + }); + describe("DELETE", () => { + describe("deleting uploaded image by url returned by POST /avatars", () => { + test("route should respond with res.body.success", async () => { + let response = await request + .post("/avatars/123456789") + .set({ signature: Config.get().security.requestSignature }) + .attach("file", __dirname + "/antman.jpg"); + request.delete(response.body.url.replace("http://localhost:3003", "")).then((x) => { + expect(x.body.success).toBeDefined(); + }); + }); + }); + }); +}); From aa340d0a3be99442508f064eb056aebdf9047e46 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 29 Aug 2021 17:11:27 +0200 Subject: [PATCH 2/5] added todo to fileStorage [cdn] --- cdn/src/util/FileStorage.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cdn/src/util/FileStorage.ts b/cdn/src/util/FileStorage.ts index 6e74788f..fae6eb1a 100644 --- a/cdn/src/util/FileStorage.ts +++ b/cdn/src/util/FileStorage.ts @@ -6,6 +6,8 @@ import "missing-native-js-functions"; import { Readable } from "stream"; import ExifTransformer = require("exif-be-gone"); +// TODO: split stored files into separate folders named after cloned route + function getPath(path: string) { // STORAGE_LOCATION has a default value in start.ts const root = process.env.STORAGE_LOCATION || "../"; From 498475c50173c2e16440a9f90cb0aa4a73aebea3 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 29 Aug 2021 17:29:05 +0200 Subject: [PATCH 3/5] fixed missing imports and programming issues [cdn] --- cdn/src/routes/external.ts | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/cdn/src/routes/external.ts b/cdn/src/routes/external.ts index 625b6bbd..10bb0f7d 100644 --- a/cdn/src/routes/external.ts +++ b/cdn/src/routes/external.ts @@ -1,45 +1,38 @@ -// @ts-nocheck -import bodyParser from "body-parser"; import { Router, Response, Request } from "express"; import fetch from "node-fetch"; -import crypto from "crypto"; import { HTTPError } from "lambert-server"; import { Snowflake } from "@fosscord/util"; import { storage } from "../util/Storage"; +import FileType from "file-type"; +import { Config } from "@fosscord/util"; + +// TODO: somehow handle the deletion of images posted to the /external route const router = Router(); - -type crawled = { - id: string; - ogTitle: string; - ogType: string; - ogDescription: string; - ogUrl: string; - cachedImage: string; -}; - const DEFAULT_FETCH_OPTIONS: any = { redirect: "follow", follow: 1, headers: { - "user-agent": "Mozilla/5.0 (compatible; Discordbot/2.0; +https://discordapp.com)", + "user-agent": "Mozilla/5.0 (compatible Fosscordbot/0.1; +https://fosscord.com)", }, size: 1024 * 1024 * 8, compress: true, method: "GET", }; -router.post("/", bodyParser.json(), async (req: Request, res: Response) => { +router.post("/", async (req: Request, res: Response) => { if (req.headers.signature !== Config.get().security.requestSignature) throw new HTTPError("Invalid request signature"); + if (!req.body) throw new HTTPError("Invalid Body"); + const { url } = req.body; if (!url || typeof url !== "string") throw new HTTPError("Invalid url"); const id = Snowflake.generate(); try { - const response = await fetch(ogImage, DEFAULT_FETCH_OPTIONS); + const response = await fetch(url, DEFAULT_FETCH_OPTIONS); const buffer = await response.buffer(); await storage.set(`/external/${id}`, buffer); @@ -50,7 +43,7 @@ router.post("/", bodyParser.json(), async (req: Request, res: Response) => { } }); -router.get("/:id/", async (req: Request, res: Response) => { +router.get("/:id", async (req: Request, res: Response) => { const { id } = req.params; const file = await storage.get(`/external/${id}`); From 9b29209361569d61cff28d95578108c32ac31b56 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 29 Aug 2021 18:05:46 +0200 Subject: [PATCH 4/5] added /external unit tests [cdn] --- .../{server.test.js => cdn_endpoints.test.js} | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) rename cdn/tests/{server.test.js => cdn_endpoints.test.js} (72%) diff --git a/cdn/tests/server.test.js b/cdn/tests/cdn_endpoints.test.js similarity index 72% rename from cdn/tests/server.test.js rename to cdn/tests/cdn_endpoints.test.js index 6f06c2b6..a133d0dd 100644 --- a/cdn/tests/server.test.js +++ b/cdn/tests/cdn_endpoints.test.js @@ -3,6 +3,9 @@ const path = require("path"); const fse = require("fs-extra"); dotenv.config(); +// TODO: write unittest to check if FileStorage.ts is working +// TODO: write unitest to check if env vars are defined + if (!process.env.STORAGE_PROVIDER) process.env.STORAGE_PROVIDER = "file"; // TODO:nodejs path.join trailing slash windows compatible if (process.env.STORAGE_PROVIDER === "file") { @@ -15,7 +18,6 @@ if (process.env.STORAGE_PROVIDER === "file") { } fse.ensureDirSync(process.env.STORAGE_LOCATION); } - const { CDNServer } = require("../dist/Server"); const { Config } = require("@fosscord/util"); const supertest = require("supertest"); @@ -153,3 +155,57 @@ describe("/avatars", () => { }); }); }); + +describe("/external", () => { + describe("POST", () => { + describe("without signature specified", () => { + test("route should respond with 400", async () => { + const response = await request.post("/external"); + expect(response.statusCode).toBe(400); + }); + }); + describe("with signature specified, without file specified", () => { + test("route should respond with 400", async () => { + const response = await request + .post("/external") + .set({ signature: Config.get().security.requestSignature }); + expect(response.statusCode).toBe(400); + }); + }); + describe("with signature specified, with file specified ", () => { + test("route should respond with Content-type: application/json, 200 and res.body.url", async () => { + const response = await request + .post("/external") + .set({ signature: Config.get().security.requestSignature }) + .send({ url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp" }); + expect(response.statusCode).toBe(200); + expect(response.headers["content-type"]).toEqual(expect.stringContaining("json")); + expect(response.body.id).toBeDefined(); + }); + }); + describe("with signature specified, with falsy url specified ", () => { + test("route should respond with 400", async () => { + const response = await request + .post("/external") + .set({ signature: Config.get().security.requestSignature }) + .send({ + url: "notavalidurl.123", + }); + expect(response.statusCode).toBe(400); + }); + }); + }); + describe("GET", () => { + describe("getting uploaded image by url returned by POST /avatars", () => { + test("route should respond with 200", async () => { + let response = await request + .post("/external") + .set({ signature: Config.get().security.requestSignature }) + .send({ url: "https://i.ytimg.com/vi_webp/TiXzhQr5AUc/mqdefault.webp" }); + request.get(`external/${response.body.id}`).then((x) => { + expect(x.statusCode).toBe(200); + }); + }); + }); + }); +}); From 088a97092b575563c8286ee194bdd3cd72219014 Mon Sep 17 00:00:00 2001 From: xnacly Date: Sun, 29 Aug 2021 18:34:20 +0200 Subject: [PATCH 5/5] added unittests for filestorage [cdn] --- cdn/package.json | 3 ++- cdn/tests/filestorage.test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 cdn/tests/filestorage.test.js diff --git a/cdn/package.json b/cdn/package.json index 7e69b65d..1eb6b1a8 100644 --- a/cdn/package.json +++ b/cdn/package.json @@ -61,6 +61,7 @@ "jest": { "setupFilesAfterEnv": [ "/jest/setup.js" - ] + ], + "verbose": true } } diff --git a/cdn/tests/filestorage.test.js b/cdn/tests/filestorage.test.js new file mode 100644 index 00000000..78036602 --- /dev/null +++ b/cdn/tests/filestorage.test.js @@ -0,0 +1,27 @@ +const path = require("path"); +process.env.STORAGE_LOCATION = path.join(__dirname, "..", "files", "/"); + +const { FileStorage } = require("../dist/util/FileStorage"); +const storage = new FileStorage(); +const fs = require("fs"); + +const file = fs.readFileSync(path.join(__dirname, "antman.jpg")); + +describe("FileStorage", () => { + describe("saving a file", () => { + test("saving a buffer", async () => { + await storage.set("test_saving_file", file); + }); + }); + describe("getting a file", () => { + test("getting buffer with given name", async () => { + const buffer2 = await storage.get("test_saving_file"); + expect(Buffer.compare(file, buffer2)).toBeTruthy(); + }); + }); + describe("deleting a file", () => { + test("deleting buffer with given name", async () => { + await storage.delete("test_saving_file"); + }); + }); +});