summary refs log tree commit diff
path: root/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/api')
-rw-r--r--src/api/Server.ts3
-rw-r--r--src/api/middlewares/TestClient.ts15
-rw-r--r--src/api/util/TestClientPatcher.ts107
-rw-r--r--src/api/util/index.ts2
4 files changed, 123 insertions, 4 deletions
diff --git a/src/api/Server.ts b/src/api/Server.ts
index e92335a5..560014d0 100644
--- a/src/api/Server.ts
+++ b/src/api/Server.ts
@@ -11,6 +11,7 @@ import { initRateLimits } from "./middlewares/RateLimit";
 import TestClient from "./middlewares/TestClient";
 import { initTranslation } from "./middlewares/Translation";
 import { initInstance } from "./util/handlers/Instance";
+import fs from "fs";
 
 export interface FosscordServerOptions extends ServerOptions {}
 
@@ -42,6 +43,8 @@ export class FosscordServer extends Server {
 			this.app.use(
 				morgan("combined", {
 					skip: (req, res) => {
+						if(req.path.endsWith(".map")) return true;
+						if(req.path.includes("/assets/") && !fs.existsSync(path.join(__dirname, "..", "..", "..", "assets", req.path.split("/")[0].split('?')[0]))) return true;
 						let skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false);
 						if (process.env["LOG_REQUESTS"]?.charAt(0) == "-") skip = !skip;
 						return skip;
diff --git a/src/api/middlewares/TestClient.ts b/src/api/middlewares/TestClient.ts
index 3afd0339..9090840e 100644
--- a/src/api/middlewares/TestClient.ts
+++ b/src/api/middlewares/TestClient.ts
@@ -6,7 +6,9 @@ import path from "path";
 import { green } from "picocolors";
 import ProxyAgent from "proxy-agent";
 import { AssetCacheItem } from "../util/entities/AssetCacheItem";
+import { patchFile } from "..";
 
+const prettier = require("prettier");
 const AssetsPath = path.join(__dirname, "..", "..", "..", "assets");
 
 export default function TestClient(app: Application) {
@@ -39,7 +41,7 @@ export default function TestClient(app: Application) {
 		let response: FetchResponse;
 		let buffer: Buffer;
 		let assetCacheItem: AssetCacheItem = new AssetCacheItem(req.params.file);
-		if (newAssetCache.has(req.params.file)) {
+		if (newAssetCache.has(req.params.file) && fs.existsSync(newAssetCache.get(req.params.file)!.FilePath)) {
 			assetCacheItem = newAssetCache.get(req.params.file)!;
 			assetCacheItem.Headers.forEach((value: any, name: any) => {
 				res.set(name, value);
@@ -56,16 +58,21 @@ export default function TestClient(app: Application) {
 					...req.headers
 				}
 			});
-
 			//set cache info
 			assetCacheItem.Headers = Object.fromEntries(stripHeaders(response.headers));
-			assetCacheItem.FilePath = path.join(assetCacheDir, req.params.file);
 			assetCacheItem.Key = req.params.file;
 			//add to cache and save
 			newAssetCache.set(req.params.file, assetCacheItem);
+
+			if(response.status != 200) {
+				return res.status(404).send("Not found");
+			}
+			assetCacheItem.FilePath = path.join(assetCacheDir, req.params.file);
+			if(!fs.existsSync(assetCacheDir))
+				fs.mkdirSync(assetCacheDir);
 			fs.writeFileSync(path.join(assetCacheDir, "index.json"), JSON.stringify(Object.fromEntries(newAssetCache), null, 4));
 			//download file
-			fs.writeFileSync(assetCacheItem.FilePath, await response.buffer());
+			fs.writeFileSync(assetCacheItem.FilePath, /.*\.(js|css)/.test(req.params.file) ? patchFile(assetCacheItem.FilePath, (await response.buffer()).toString()) : await response.buffer());
 		}
 
 		assetCacheItem.Headers.forEach((value: string, name: string) => {
diff --git a/src/api/util/TestClientPatcher.ts b/src/api/util/TestClientPatcher.ts
new file mode 100644
index 00000000..2e9bfafe
--- /dev/null
+++ b/src/api/util/TestClientPatcher.ts
@@ -0,0 +1,107 @@
+import path from "path";
+import fs from "fs";
+
+console.log('[TestClient] Loading private assets...');
+
+const privateAssetsRoot = path.join(__dirname, "..", "..", "..", "assets", "private");
+const iconsRoot = path.join(privateAssetsRoot, "icons");
+const icons = new Map<string, Buffer>();
+
+fs.readdirSync(iconsRoot).forEach(file => {
+    const fileName = path.basename(file);
+    //check if dir
+    if(fs.lstatSync(path.join(iconsRoot, file)).isDirectory()){
+        return;
+    }
+    icons.set(fileName,fs.readFileSync(path.join(iconsRoot,file)) as Buffer);
+});
+
+fs.readdirSync(path.join(iconsRoot, "custom")).forEach(file => {
+    const fileName = path.basename(file);
+    if(fs.lstatSync(path.join(iconsRoot,"custom", file)).isDirectory()){
+        return;
+    }
+    icons.set(fileName,fs.readFileSync(path.join(iconsRoot,"custom",file)) as Buffer);
+});
+
+console.log('[TestClient] Patcher ready!');
+
+export function patchFile(filePath: string, content: string): string {
+    console.log(`[TestClient] Patching ${filePath}`);
+    let startTime = Date.now();
+    
+    content = prettier(filePath, content);
+    content = autoPatch(filePath, content);
+
+    console.log(`[TestClient] Patched ${filePath} in ${Date.now() - startTime}ms`);
+    return content;
+}
+function prettier(filePath: string, content: string): string{
+    let prettier = require("prettier");
+    let parser;
+    filePath = filePath.toLowerCase().split('?')[0];
+    if(filePath.endsWith(".js")) {
+        parser = "babel";
+    } else if (filePath.endsWith(".ts")){
+        parser = "typescript";
+    } else if(filePath.endsWith(".css")){
+        parser = "css";
+    } else if(filePath.endsWith(".json")){
+        parser = "json";
+    }
+    else {
+        console.log(`[TestClient] Skipping prettier for ${filePath}, unknown file type!`);
+        return content;
+    }
+    content = prettier.format(content, {
+        tabWidth: 4,
+        useTabs: true,
+        printWidth: 140,
+        trailingComma: "none",
+        parser
+    });
+    console.log(`[TestClient] Prettified ${filePath}!`);
+    return content;
+}
+
+function autoPatch(filePath: string, content: string): string{
+    //remove nitro references
+    content = content.replace(/Discord Nitro/g, "Fosscord Premium");
+    content = content.replace(/"Nitro"/g, "\"Premium\"");
+    content = content.replace(/Nitro /g, "Premium ");
+    content = content.replace(/ Nitro/g, " Premium");
+    content = content.replace(/\[Nitro\]/g, "[Premium]");
+    content = content.replace(/\*Nitro\*/g, "*Premium*");
+    content = content.replace(/\"Nitro \. /g, "\"Premium. ");
+
+    //remove discord references
+    content = content.replace(/ Discord /g, " Fosscord ");
+    content = content.replace(/Discord /g, "Fosscord ");
+    content = content.replace(/ Discord/g, " Fosscord");
+    content = content.replace(/Discord Premium/g, "Fosscord Premium");
+    content = content.replace(/Discord Nitro/g, "Fosscord Premium");
+    content = content.replace(/Discord's/g, "Fosscord's");
+    //content = content.replace(/DiscordTag/g, "FosscordTag");
+    content = content.replace(/\*Discord\*/g, "*Fosscord*");
+
+    //change some vars
+    content = content.replace('dsn: "https://fa97a90475514c03a42f80cd36d147c4@sentry.io/140984"', "dsn: (/true/.test(localStorage.sentryOptIn)?'https://6bad92b0175d41a18a037a73d0cff282@sentry.thearcanebrony.net/12':'')");
+    content = content.replace('t.DSN = "https://fa97a90475514c03a42f80cd36d147c4@sentry.io/140984"', "t.DSN = (/true/.test(localStorage.sentryOptIn)?'https://6bad92b0175d41a18a037a73d0cff282@sentry.thearcanebrony.net/12':'')");
+    content = content.replace('--brand-experiment: hsl(235, calc(var(--saturation-factor, 1) * 85.6%), 64.7%);', '--brand-experiment: hsl(var(--brand-hue), calc(var(--saturation-factor, 1) * 85.6%), 50%);');
+    content = content.replaceAll(/--brand-experiment-(\d{1,4}): hsl\(235/g, '--brand-experiment-\$1: hsl(var(--brand-hue)')
+
+    //logos
+    content = content.replace(/d: "M23\.0212.*/, `d: "${icons.get("homeIcon.path")!.toString()}"`);
+    content = content.replace('width: n, height: o, viewBox: "0 0 28 20"', 'width: 48, height: 48, viewBox: "0 0 48 48"');
+
+    //undo webpacking
+    // - booleans
+    content = content.replace(/!0/g, "true");
+    content = content.replace(/!1/g, "false");
+    // - real esmodule defs
+    content = content.replace(/Object.defineProperty\((.), "__esModule", { value: (.*) }\);/g, '\$1.__esModule = \$2;');
+    
+
+    console.log(`[TestClient] Autopatched ${path.basename(filePath)}!`);
+    return content;
+}
\ No newline at end of file
diff --git a/src/api/util/index.ts b/src/api/util/index.ts
index d06860cd..f01c2f43 100644
--- a/src/api/util/index.ts
+++ b/src/api/util/index.ts
@@ -8,3 +8,5 @@ export * from "./utility/ipAddress";
 export * from "./utility/passwordStrength";
 export * from "./utility/RandomInviteID";
 export * from "./utility/String";
+export * from "./utility/captcha";
+export * from "./TestClientPatcher";
\ No newline at end of file