Development (#11)

We need this NOW.

---------

Co-authored-by: PineaFan <ash@pinea.dev>
Co-authored-by: pineafan <pineapplefanyt@gmail.com>
Co-authored-by: PineappleFan <PineaFan@users.noreply.github.com>
Co-authored-by: Skyler <skyler3665@gmail.com>
diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts
index 9761e4b..cf713e6 100644
--- a/src/reflex/scanners.ts
+++ b/src/reflex/scanners.ts
@@ -1,23 +1,27 @@
 import fetch from "node-fetch";
-import FormData from "form-data";
-import { writeFileSync, createReadStream } from "fs";
+import fs, { writeFileSync, createReadStream } from "fs";
 import generateFileName from "../utils/temp/generateFileName.js";
 import Tesseract from "node-tesseract-ocr";
 import type Discord from "discord.js";
 import client from "../utils/client.js";
+import { createHash } from "crypto";
 
 interface NSFWSchema {
     nsfw: boolean;
+    errored?: boolean;
 }
 interface MalwareSchema {
     safe: boolean;
+    errored?: boolean;
 }
 
 export async function testNSFW(link: string): Promise<NSFWSchema> {
-    const p = await saveAttachment(link);
-    const data = new FormData();
-    console.log(link);
-    data.append("file", createReadStream(p));
+    const [p, hash] = await saveAttachment(link);
+    const alreadyHaveCheck = await client.database.scanCache.read(hash)
+    if(alreadyHaveCheck) return { nsfw: alreadyHaveCheck.data };
+    const data = new URLSearchParams();
+    const r = createReadStream(p)
+    data.append("file", r.read(fs.statSync(p).size));
     const result = await fetch("https://unscan.p.rapidapi.com/", {
         method: "POST",
         headers: {
@@ -26,20 +30,24 @@
         },
         body: data
     })
-        .then((response) => response.json() as Promise<NSFWSchema>)
+        .then((response) => response.status === 200 ? response.json() as Promise<NSFWSchema> : { nsfw: false, errored: true })
         .catch((err) => {
             console.error(err);
-            return { nsfw: false };
+            return { nsfw: false, errored: true };
         });
-    console.log(result);
+    if(!result.errored) {
+        client.database.scanCache.write(hash, result.nsfw);
+    }
     return { nsfw: result.nsfw };
 }
 
 export async function testMalware(link: string): Promise<MalwareSchema> {
-    const p = await saveAttachment(link);
-    const data = new FormData();
-    data.append("file", createReadStream(p));
-    console.log(link);
+    const [p, hash] = await saveAttachment(link);
+    const alreadyHaveCheck = await client.database.scanCache.read(hash)
+    if(alreadyHaveCheck) return { safe: alreadyHaveCheck.data };
+    const data = new URLSearchParams();
+    const f = createReadStream(p);
+    data.append("file", f.read(fs.statSync(p).size));
     const result = await fetch("https://unscan.p.rapidapi.com/malware", {
         method: "POST",
         headers: {
@@ -48,18 +56,21 @@
         },
         body: data
     })
-        .then((response) => response.json() as Promise<MalwareSchema>)
+        .then((response) => response.status === 200 ? response.json() as Promise<MalwareSchema> : { safe: true, errored: true })
         .catch((err) => {
             console.error(err);
-            return { safe: true };
+            return { safe: true, errored: true };
         });
-    console.log(result);
+    if (!result.errored) {
+        client.database.scanCache.write(hash, result.safe);
+    }
     return { safe: result.safe };
 }
 
 export async function testLink(link: string): Promise<{ safe: boolean; tags: string[] }> {
-    console.log(link);
-    const scanned: { safe?: boolean; tags?: string[] } = await fetch("https://unscan.p.rapidapi.com/malware", {
+    const alreadyHaveCheck = await client.database.scanCache.read(link)
+    if(alreadyHaveCheck) return { safe: alreadyHaveCheck.data, tags: [] };
+    const scanned: { safe?: boolean; tags?: string[] } = await fetch("https://unscan.p.rapidapi.com/link", {
         method: "POST",
         headers: {
             "X-RapidAPI-Key": client.config.rapidApiKey,
@@ -72,18 +83,19 @@
             console.error(err);
             return { safe: true, tags: [] };
         });
-    console.log(scanned);
+    client.database.scanCache.write(link, scanned.safe ?? true, []);
     return {
         safe: scanned.safe ?? true,
         tags: scanned.tags ?? []
     };
 }
 
-export async function saveAttachment(link: string): Promise<string> {
-    const image = (await (await fetch(link)).buffer()).toString("base64");
+export async function saveAttachment(link: string): Promise<[string, string]> {
+    const image = await (await fetch(link)).arrayBuffer()
     const fileName = generateFileName(link.split("/").pop()!.split(".").pop()!);
-    writeFileSync(fileName, image, "base64");
-    return fileName;
+    const enc = new TextDecoder("utf-8");
+    writeFileSync(fileName, new DataView(image), "base64");
+    return [fileName, createHash('sha512').update(enc.decode(image), 'base64').digest('base64')];
 }
 
 const linkTypes = {
@@ -139,8 +151,7 @@
 
 export async function NSFWCheck(element: string): Promise<boolean> {
     try {
-        const test = await testNSFW(element);
-        return test.nsfw;
+        return (await testNSFW(element)).nsfw;
     } catch {
         return false;
     }