diff --git a/cdn/src/Server.ts b/cdn/src/Server.ts
index b8d71fa9..5b395589 100644
--- a/cdn/src/Server.ts
+++ b/cdn/src/Server.ts
@@ -5,7 +5,7 @@ import avatarsRoute from "./routes/avatars";
import iconsRoute from "./routes/role-icons";
import bodyParser from "body-parser";
-export interface CDNServerOptions extends ServerOptions {}
+export interface CDNServerOptions extends ServerOptions { }
export class CDNServer extends Server {
public declare options: CDNServerOptions;
diff --git a/cdn/src/routes/avatars.ts b/cdn/src/routes/avatars.ts
index 2a4a0ffe..e5e25a4c 100644
--- a/cdn/src/routes/avatars.ts
+++ b/cdn/src/routes/avatars.ts
@@ -73,7 +73,7 @@ router.get("/:user_id", async (req: Request, res: Response) => {
return res.send(file);
});
-router.get("/:user_id/:hash", async (req: Request, res: Response) => {
+export const getAvatar = async (req: Request, res: Response) => {
var { user_id, hash } = req.params;
hash = hash.split(".")[0]; // remove .file extension
const path = `avatars/${user_id}/${hash}`;
@@ -86,7 +86,9 @@ router.get("/:user_id/:hash", async (req: Request, res: Response) => {
res.set("Cache-Control", "public, max-age=31536000");
return res.send(file);
-});
+}
+
+router.get("/:user_id/:hash", getAvatar);
router.delete("/:user_id/:id", async (req: Request, res: Response) => {
if (req.headers.signature !== Config.get().security.requestSignature)
diff --git a/cdn/src/routes/external.ts b/cdn/src/routes/external.ts
index dc90e3c8..fc12c017 100644
--- a/cdn/src/routes/external.ts
+++ b/cdn/src/routes/external.ts
@@ -3,8 +3,9 @@ import fetch from "node-fetch";
import { HTTPError } from "lambert-server";
import { Snowflake } from "@fosscord/util";
import { storage } from "../util/Storage";
-import FileType from "file-type";
+import FileType, { stream } from "file-type";
import { Config } from "@fosscord/util";
+import sharp from "sharp";
// TODO: somehow handle the deletion of images posted to the /external route
@@ -56,4 +57,35 @@ router.get("/:id", async (req: Request, res: Response) => {
return res.send(file);
});
+// this method is gross lol don't care
+router.get("/resize/:url", async (req: Request, res: Response) => {
+ const url = decodeURIComponent(req.params.url);
+ const { width, height } = req.query;
+ if (!width || !height) throw new HTTPError("Must provide width and height");
+
+ const { resizeHeightMax, resizeWidthMax } = Config.get().cdn;
+ const w = Math.min(parseInt(width as string), resizeWidthMax ?? 100);
+ const h = Math.min(parseInt(height as string), resizeHeightMax ?? 100);
+ if (w < 1 || h < 1) throw new HTTPError("Width and height must be greater than 0");
+
+ let buffer, response;
+ try {
+ response = await fetch(url, DEFAULT_FETCH_OPTIONS);
+ buffer = await response.buffer();
+ }
+ catch (e) {
+ throw new HTTPError("Couldn't fetch website");
+ }
+
+ const resizedBuffer = await sharp(buffer)
+ .resize(parseInt(width as string), parseInt(height as string), {
+ fit: "inside",
+ })
+ .toBuffer();
+
+ res.setHeader("Content-Disposition", "attachment");
+ res.setHeader("Content-Type", response.headers.get("content-type") ?? "image/png");
+ return res.end(resizedBuffer);
+});
+
export default router;
diff --git a/cdn/src/routes/guilds.ts b/cdn/src/routes/guilds.ts
new file mode 100644
index 00000000..3c4b646c
--- /dev/null
+++ b/cdn/src/routes/guilds.ts
@@ -0,0 +1,10 @@
+import { Router } from "express";
+import { getAvatar } from "./avatars";
+
+const router = Router();
+
+// TODO: handle guild profiles
+router.get("/:guild_id/users/:user_id/avatars/:hash", getAvatar);
+router.get("/:guild_id/users/:user_id/banners/:hash", getAvatar);
+
+export default router;
\ No newline at end of file
|