From 018afaf0e23d05fb833466ca20f391a433dd3dac Mon Sep 17 00:00:00 2001
From: Sam Therapy <sam@samtherapy.net>
Date: Sat, 27 Aug 2022 01:46:03 +0200
Subject: [PATCH] upload correct version

Signed-off-by: Sam Therapy <sam@samtherapy.net>
---
 .yarn/sdks/eslint/bin/eslint.js  |  20 ++++++
 .yarn/sdks/eslint/lib/api.js     |  20 ++++++
 .yarn/sdks/eslint/package.json   |   6 ++
 .yarn/sdks/prettier/index.js     |  20 ++++++
 .yarn/sdks/prettier/package.json |   6 ++
 README.md                        |   6 +-
 package.json                     |   8 +--
 src/app.ts                       |  49 ++++++++++++++
 src/helpers/contentType.ts       | 108 +++++++++++++++++++++++++++++++
 src/helpers/parse.ts             |  34 ++++++++++
 src/helpers/search.ts            |  36 +++++++++++
 src/index.ts                     |  40 +-----------
 waifurudor.de.service            |   6 +-
 yarn.lock                        |   4 +-
 14 files changed, 312 insertions(+), 51 deletions(-)
 create mode 100644 .yarn/sdks/eslint/bin/eslint.js
 create mode 100644 .yarn/sdks/eslint/lib/api.js
 create mode 100644 .yarn/sdks/eslint/package.json
 create mode 100644 .yarn/sdks/prettier/index.js
 create mode 100644 .yarn/sdks/prettier/package.json
 create mode 100644 src/app.ts
 create mode 100644 src/helpers/contentType.ts
 create mode 100644 src/helpers/parse.ts
 create mode 100644 src/helpers/search.ts

diff --git a/.yarn/sdks/eslint/bin/eslint.js b/.yarn/sdks/eslint/bin/eslint.js
new file mode 100644
index 0000000..4d327a4
--- /dev/null
+++ b/.yarn/sdks/eslint/bin/eslint.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+const {existsSync} = require(`fs`);
+const {createRequire, createRequireFromPath} = require(`module`);
+const {resolve} = require(`path`);
+
+const relPnpApiPath = "../../../../.pnp.cjs";
+
+const absPnpApiPath = resolve(__dirname, relPnpApiPath);
+const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
+
+if (existsSync(absPnpApiPath)) {
+  if (!process.versions.pnp) {
+    // Setup the environment to be able to require eslint/bin/eslint.js
+    require(absPnpApiPath).setup();
+  }
+}
+
+// Defer to the real eslint/bin/eslint.js your application uses
+module.exports = absRequire(`eslint/bin/eslint.js`);
diff --git a/.yarn/sdks/eslint/lib/api.js b/.yarn/sdks/eslint/lib/api.js
new file mode 100644
index 0000000..fc728d9
--- /dev/null
+++ b/.yarn/sdks/eslint/lib/api.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+const {existsSync} = require(`fs`);
+const {createRequire, createRequireFromPath} = require(`module`);
+const {resolve} = require(`path`);
+
+const relPnpApiPath = "../../../../.pnp.cjs";
+
+const absPnpApiPath = resolve(__dirname, relPnpApiPath);
+const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
+
+if (existsSync(absPnpApiPath)) {
+  if (!process.versions.pnp) {
+    // Setup the environment to be able to require eslint
+    require(absPnpApiPath).setup();
+  }
+}
+
+// Defer to the real eslint your application uses
+module.exports = absRequire(`eslint`);
diff --git a/.yarn/sdks/eslint/package.json b/.yarn/sdks/eslint/package.json
new file mode 100644
index 0000000..08d53c0
--- /dev/null
+++ b/.yarn/sdks/eslint/package.json
@@ -0,0 +1,6 @@
+{
+  "name": "eslint",
+  "version": "8.22.0-sdk",
+  "main": "./lib/api.js",
+  "type": "commonjs"
+}
diff --git a/.yarn/sdks/prettier/index.js b/.yarn/sdks/prettier/index.js
new file mode 100644
index 0000000..f6882d8
--- /dev/null
+++ b/.yarn/sdks/prettier/index.js
@@ -0,0 +1,20 @@
+#!/usr/bin/env node
+
+const {existsSync} = require(`fs`);
+const {createRequire, createRequireFromPath} = require(`module`);
+const {resolve} = require(`path`);
+
+const relPnpApiPath = "../../../.pnp.cjs";
+
+const absPnpApiPath = resolve(__dirname, relPnpApiPath);
+const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
+
+if (existsSync(absPnpApiPath)) {
+  if (!process.versions.pnp) {
+    // Setup the environment to be able to require prettier/index.js
+    require(absPnpApiPath).setup();
+  }
+}
+
+// Defer to the real prettier/index.js your application uses
+module.exports = absRequire(`prettier/index.js`);
diff --git a/.yarn/sdks/prettier/package.json b/.yarn/sdks/prettier/package.json
new file mode 100644
index 0000000..b61805c
--- /dev/null
+++ b/.yarn/sdks/prettier/package.json
@@ -0,0 +1,6 @@
+{
+  "name": "prettier",
+  "version": "2.7.1-sdk",
+  "main": "./index.js",
+  "type": "commonjs"
+}
diff --git a/README.md b/README.md
index 24d1332..bfb38c6 100644
--- a/README.md
+++ b/README.md
@@ -12,11 +12,11 @@ https://waifurudor.de/?tags=tohsaka_rin,-feet,-underwear,rating:safe
 
 Clone the repo to where ever you will be hosting this and run the following command to install the dependencies.
 
-```sh
-yarn
+```
+npm install
 ```
 
-Now that the dependencies are taken care of you can verify it runs with `yarn build && yarn start` in the root directory of the project. If it tells you it is listening on a port you're probably good to go.
+Now that the dependencies are taken care of you can verify it runs with `npm start` in the root directory of the project. If it tells you it is listening on a port you're probably good to go.
 
 ## Running as a service
 
diff --git a/package.json b/package.json
index 2af4d99..43b7619 100644
--- a/package.json
+++ b/package.json
@@ -7,10 +7,10 @@
   },
   "name": "waifurudor.de",
   "version": "1.0.0",
-  "main": "index.js",
   "type": "module",
   "scripts": {
-    "build": "tsc",
+    "build": "tsc --build",
+    "clean": "tsc --build --clean",
     "start": "node ./dist/index.js"
   },
   "repository": {
@@ -20,10 +20,10 @@
   "keywords": [],
   "author": "",
   "license": "GPL-3.0-or-later",
-  "description": "",
+  "private": true,
   "devDependencies": {
     "@types/express": "4.17.13",
-    "@types/morgan": "1",
+    "@types/morgan": "1.9.3",
     "typescript": "4.7.4"
   }
 }
diff --git a/src/app.ts b/src/app.ts
new file mode 100644
index 0000000..d1d8e35
--- /dev/null
+++ b/src/app.ts
@@ -0,0 +1,49 @@
+import express, { NextFunction, Request, Response } from "express";
+import helmet from "helmet";
+import morgan from "morgan";
+
+import { ParseGet, ParsePost } from "./helpers/parse.js";
+import Search from "./helpers/search.js";
+
+const app = express();
+
+app.use(helmet());
+app.use(morgan("combined"));
+// app.use(morgan(process.env.NODE_ENV === "production" ? "tiny" : "dev"));
+
+app.use(express.json());
+
+// Errors
+app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
+  console.error(err.stack);
+  res.status(500).json({ msg: "Wife machine broke", error: err });
+});
+
+app
+  .route("/")
+  .get(ParseGet, Search)
+  .post(ParsePost, Search)
+  // Also have a fallback for anyone who tries to be silly :)
+  .all((_req, res) => {
+    res.set("ALLOW", "GET, POST");
+    res.status(405).json({ msg: "Method not allowed." });
+  });
+
+// Politely tell all crawlers to go away since there's nothing here.
+app.get("/robots.txt", (_req, res) => {
+  res.setHeader("content-type", "text/plain");
+  res.status(200).send(`User-agent: *
+Disallow: /`);
+});
+
+app.get("/source", (_req, res) => {
+  res.redirect(301, "https://git.freecumextremist.com/grumbulon/waifurudor.de");
+});
+
+// For 404s
+app.use((_req, res) => {
+  res.setHeader("content-type", "text/plain");
+  res.status(404).send("Nothing beside remains.");
+});
+
+export default app;
diff --git a/src/helpers/contentType.ts b/src/helpers/contentType.ts
new file mode 100644
index 0000000..7c0b4fb
--- /dev/null
+++ b/src/helpers/contentType.ts
@@ -0,0 +1,108 @@
+// TODO: many of these are probably redundant and should be removed.
+/**
+ * Helper function to allow adding content types because XSS bad.
+ * Hopefully this works as it should.
+ * @param extension File extension, without any additional faff
+ * @returns Content type that should be used
+ */
+export default function ContentType(extension: string): string {
+  switch (
+    extension.toLowerCase()?.replace("jpg", "jpeg").replace("svg", "svg+xml")
+  ) {
+    case "aces":
+    case "avci":
+    case "avcs":
+    case "avif":
+    case "bmp":
+    case "cgm":
+    case "dpx":
+    case "emf":
+    case "fits":
+    case "g3fax":
+    case "gif":
+    case "heic":
+    case "heif":
+    case "hej2k":
+    case "hsj2":
+    case "ief":
+    case "jls":
+    case "jp2":
+    case "jpeg":
+    case "jph":
+    case "jphc":
+    case "jpm":
+    case "jpx":
+    case "jxr":
+    case "jxra":
+    case "jxrs":
+    case "jxs":
+    case "jxsc":
+    case "jxsi":
+    case "jxss":
+    case "ktx":
+    case "ktx2":
+    case "naplps":
+    case "png":
+    case "prs.btif":
+    case "prs.pti":
+    case "pwg-raster":
+    case "t38":
+    case "tiff":
+    case "tiff-fx":
+    case "wmf":
+      return `image/${extension}`;
+
+    case "1d-interleaved-parityfec":
+    case "3gpp":
+    case "3gpp2":
+    case "3gpp-tt":
+    case "av1":
+    case "bmpeg":
+    case "bt656":
+    case "celb":
+    case "dv":
+    case "encaprtp":
+    case "ffv1":
+    case "flexfec":
+    case "h261":
+    case "h263":
+    case "h263-1998":
+    case "h263-2000":
+    case "h264":
+    case "h264-rcdo":
+    case "h264-svc":
+    case "h265":
+    case "iso.segment":
+    case "jxsv":
+    case "mj2":
+    case "mp1s":
+    case "mp2p":
+    case "mp2t":
+    case "mp4":
+    case "mp4v-es":
+    case "mpv":
+    case "mpeg":
+    case "mpeg4-generic":
+    case "nv":
+    case "ogg":
+    case "parityfec":
+    case "pointer":
+    case "quicktime":
+    case "raptorfec":
+    case "raw":
+    case "rtp-enc-aescm128":
+    case "rtploopback":
+    case "rtx":
+    case "scip":
+    case "smpte291":
+    case "smpte292m":
+    case "ulpfec":
+    case "vc1":
+    case "vc2":
+    case "vp8":
+    case "vp9":
+      return `video/${extension}`;
+    default:
+      return "";
+  }
+}
diff --git a/src/helpers/parse.ts b/src/helpers/parse.ts
new file mode 100644
index 0000000..2b431c8
--- /dev/null
+++ b/src/helpers/parse.ts
@@ -0,0 +1,34 @@
+import { Request, Response, NextFunction } from "express";
+
+/**
+ * Middleware for extracting the options from a GET.
+ *
+ * Why not just support JSON for both GET and POST requests?
+ * Don't wanna.
+ */
+export function ParseGet(
+  req: Request,
+  res: Response,
+  next: NextFunction
+): void {
+  if (req.query.tags && typeof req.query.tags === "string") {
+    res.locals.tags = req.query.tags.split(",");
+  }
+  res.locals.booru = (req.query.booru as string) ?? "sb";
+  next();
+}
+
+/**
+ * Middleware for extracting the options from a POST.
+ *
+ * Accepts from the body only because.
+ */
+export function ParsePost(
+  req: Request,
+  res: Response,
+  next: NextFunction
+): void {
+  res.locals.tags = req.body.tags;
+  res.locals.booru = (req.body.booru as string) ?? "sb";
+  next();
+}
diff --git a/src/helpers/search.ts b/src/helpers/search.ts
new file mode 100644
index 0000000..81da8f2
--- /dev/null
+++ b/src/helpers/search.ts
@@ -0,0 +1,36 @@
+import { Request, Response } from "express";
+import booru from "booru";
+import ContentType from "./contentType.js";
+
+/**
+ * Searches the booru for an image to return.
+ * @param _req Express request (not used)
+ * @param res Node Response
+ */
+export default function Search(_req: Request, res: Response) {
+  booru
+    .search(res.locals.booru, res.locals.tags, { random: true, limit: 1 })
+    .then(async (post) => {
+      const imageURL = post[0]?.fileUrl as string;
+
+      const type = imageURL.split(".").pop() as string;
+      res.setHeader("content-type", ContentType(type));
+
+      const img = await fetch(imageURL)
+        // Turn the image into an ArrayBuffer (which is also a Promise)
+        .then(async (fetchRes) => {
+          return fetchRes?.arrayBuffer();
+        })
+        .catch((err: Error) => {
+          console.error(err);
+          res.status(500).json({ msg: "Wife machine broke", error: err });
+        });
+
+      // deepcode ignore XSS: nmp
+      res.status(200).end(Buffer.from(img as ArrayBuffer), "binary");
+    })
+    .catch((err: Error) => {
+      res.status(400).json({ msg: "WaaS Error", error: err });
+      console.error(err);
+    });
+}
diff --git a/src/index.ts b/src/index.ts
index 2b2ea69..bb1b18b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,45 +1,7 @@
-import express, { NextFunction, Request, Response } from "express";
-import helmet from "helmet";
-import morgan from "morgan";
+import app from "./app.js";
 
-import { ParseGet, ParsePost, Search } from "./helpers/booruSearch.js";
-
-const app = express();
 const port = process.env.PORT || 3000;
 
-app.use(helmet());
-app.use(morgan(process.env.NODE_ENV === "production" ? "tiny" : "dev"));
-
-app.use(express.json());
-
-app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
-  console.error(err.stack);
-  res.status(500).json({ msg: "Wife machine broke", error: err });
-});
-
-app
-  .route("/")
-  .get(ParseGet, Search)
-  .post(ParsePost, Search)
-  // Also have a fallback for anyone who tries to be silly :)
-  .all((_req, res) => {
-    res.set("ALLOW", "GET, POST");
-    res.status(405).json({ msg: "Method not allowed." });
-  });
-
-// Politely tell all crawlers to go away since there's nothing here.
-app.get("/robots.txt", (_req, res) => {
-  res.setHeader("content-type", "text/plain");
-  res.status(200).send(`User-agent: *
-Disallow: /`);
-});
-
-// For 404s
-app.use((_req, res) => {
-  res.setHeader("content-type", "text/plain");
-  res.status(404).send("Nothing beside remains.");
-});
-
 app.listen(port, () => {
   console.log(`listening on port ${port}`);
 });
diff --git a/waifurudor.de.service b/waifurudor.de.service
index 16492d2..2d034df 100644
--- a/waifurudor.de.service
+++ b/waifurudor.de.service
@@ -1,14 +1,14 @@
 [Unit]
-Description=waifurudor.de
+Description=waifurudor.de - Anime as a Service (AaaS)
 
 [Service]
-ExecStart=npm start
+ExecStart=yarn start
 Restart=always
 User=none
 Group=nogroup
 Environment=PATH=/usr/bin:/usr/local/bin
 Environment=NODE_ENV=production
-WorkingDirectory=/whatever/user/waifurudor.de/src/
+WorkingDirectory=/whatever/user/waifurudor.de/
 
 [Install]
 WantedBy=multi-user.target
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 9d8706e..b8f05db 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,7 +54,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/morgan@npm:1":
+"@types/morgan@npm:1.9.3":
   version: 1.9.3
   resolution: "@types/morgan@npm:1.9.3"
   dependencies:
@@ -677,7 +677,7 @@ __metadata:
   resolution: "waifurudor.de@workspace:."
   dependencies:
     "@types/express": 4.17.13
-    "@types/morgan": 1
+    "@types/morgan": 1.9.3
     booru: 2.6.2
     express: ">=5.0.0-beta.1"
     helmet: 5.1.1
