summary refs log tree commit diff
path: root/ReferenceClientProxyImplementation/Controllers
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs72
-rw-r--r--ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs.bak124
-rw-r--r--ReferenceClientProxyImplementation/Controllers/ErrorReportingProxy.cs34
-rw-r--r--ReferenceClientProxyImplementation/Controllers/FrontendController.cs77
-rw-r--r--ReferenceClientProxyImplementation/Controllers/StaticController.cs15
5 files changed, 322 insertions, 0 deletions
diff --git a/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs b/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs
new file mode 100644

index 0000000..8bd78bc --- /dev/null +++ b/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs
@@ -0,0 +1,72 @@ +//#define MEMCACHE +using System.Collections.Frozen; +using ArcaneLibs.Extensions.Streams; +using Microsoft.AspNetCore.Mvc; +using ReferenceClientProxyImplementation.Configuration; +using ReferenceClientProxyImplementation.Services; + +namespace ReferenceClientProxyImplementation.Controllers; + +[Controller] +[Route("/")] +public class AssetsController(ProxyConfiguration proxyConfiguration, ClientStoreService clientStore) : Controller { +#if MEMCACHE + private static FrozenDictionary<string, ReadOnlyMemory<byte>> memCache = new Dictionary<string, ReadOnlyMemory<byte>>().ToFrozenDictionary(); +#endif + + [HttpGet("/assets/{*res:required}")] + public async Task<IActionResult> Asset(string res) { + if (res is "version.staging.json" or "version.internal.json") + res = $"version.{proxyConfiguration.TestClient.Revision}.json"; + else if (res.EndsWith(".map")) { + return NotFound(); + } + + var ext = res.Split(".").Last(); + var contentType = ext switch { + //text types + "html" => "text/html", + "js" => "text/javascript", + "css" => "text/css", + "txt" => "text/plain", + "csv" => "text/csv", + "json" => "application/json", + //image types + "apng" => "image/apng", + "gif" => "image/gif", + "jpg" => "image/jpeg", + "png" => "image/png", + "svg" => "image/svg+xml", + "webp" => "image/webp", + "ico" => "image/x-icon", + //script types + "wasm" => "application/wasm", + _ => "application/octet-stream" + }; + // Response.Headers.ContentType = contentType; +#if MEMCACHE + if (memCache.TryGetValue(res, out var value)) { + // value.Position = 0; + var cms = new MemoryStream(value.ToArray()); + // await value.CopyToAsync(cms); + // ms.Position = 0; + + return new FileStreamResult(cms, contentType); + } +#endif + +#if MEMCACHE + var stream = await clientStore.GetPatchedClientAsset("assets/" + res); + stream.Position = 0; + // var ms = new MemoryStream(stream.ReadToEnd().ToArray(), false); + // memCache = memCache.Append(new KeyValuePair<string, MemoryStream>(res, ms)).ToFrozenDictionary(); + // return new FileStreamResult(ms, contentType); + var mem = new ReadOnlyMemory<byte>(stream.ReadToEnd().ToArray()); + memCache = memCache.Append(new KeyValuePair<string, ReadOnlyMemory<byte>>(res, mem)).ToFrozenDictionary(); + return new FileStreamResult(new MemoryStream(mem.ToArray()), contentType); +#else + return new FileStreamResult(await clientStore.GetPatchedClientAsset("assets/" + res), contentType); +#endif + // return ; + } +} \ No newline at end of file diff --git a/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs.bak b/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs.bak new file mode 100644
index 0000000..ea5909a --- /dev/null +++ b/ReferenceClientProxyImplementation/Controllers/AssetsControllers.cs.bak
@@ -0,0 +1,124 @@ +//using System.Collections.Concurrent; +//using System.Text; +//using Microsoft.AspNetCore.Mvc; +//using ReferenceClientProxyImplementation.Configuration; +//using ReferenceClientProxyImplementation.Services; +//using Spacebar.API.Helpers; +// +//namespace ReferenceClientProxyImplementation.Controllers; +// +//[Controller] +//[Route("/")] +//public class AssetsController(ProxyConfiguration proxyConfiguration, ClientStoreService clientStore) : Controller { +// private static readonly ConcurrentDictionary<string, byte[]> cache = new(); +// +// [HttpGet("/assets/{*res:required}")] +// public async Task<object> Asset(string res) { +// var ext = res.Split(".").Last(); +// var contentType = ext switch { +// //text types +// "html" => "text/html", +// "js" => "text/javascript", +// "css" => "text/css", +// "txt" => "text/plain", +// "csv" => "text/csv", +// //image types +// "apng" => "image/apng", +// "gif" => "image/gif", +// "jpg" => "image/jpeg", +// "png" => "image/png", +// "svg" => "image/svg+xml", +// "webp" => "image/webp", +// "ico" => "image/x-icon", +// _ => "application/octet-stream" +// }; +// if (cache.ContainsKey(res)) +// return File(cache[res], contentType); +// +// if (System.IO.File.Exists("./Resources/Assets/" + res)) +// cache.TryAdd(res, await System.IO.File.ReadAllBytesAsync("./Resources/Assets/" + res)); +// else if (System.IO.File.Exists("./cache_formatted/" + res)) +// cache.TryAdd(res, await System.IO.File.ReadAllBytesAsync("./cache_formatted/" + res)); +// else if (System.IO.File.Exists("./cache/" + res)) +// cache.TryAdd(res, await System.IO.File.ReadAllBytesAsync($"{proxyConfiguration.AssetCache.DiskCachePath}/{res}")); +// else { +// if (!Directory.Exists(proxyConfiguration.AssetCache.DiskCachePath)) Directory.CreateDirectory(proxyConfiguration.AssetCache.DiskCachePath); +// if (res.EndsWith(".map")) return NotFound(); +// Console.WriteLine($"[Asset cache] Downloading {"https://discord.com/assets/" + res} -> {proxyConfiguration.AssetCache.DiskCachePath}/{res}"); +// try { +// using (var hc = new HttpClient()) { +// var resp = await hc.GetAsync("https://discord.com/assets/" + res); +// +// if (!resp.IsSuccessStatusCode) return NotFound(); +// //save to file +// var bytes = await resp.Content.ReadAsByteArrayAsync(); +// //check if cloudflare +// if (bytes.Length == 0) { +// Console.WriteLine( +// $"[Asset cache] Cloudflare detected, retrying {"https://discord.com/assets/" + res} -> {proxyConfiguration.AssetCache.DiskCachePath}/{res}"); +// await Task.Delay(1000); +// resp = await hc.GetAsync("https://discord.com/assets/" + res); +// if (!resp.IsSuccessStatusCode) return NotFound(); +// bytes = await resp.Content.ReadAsByteArrayAsync(); +// } +// +// //check if cloudflare html +// /*if (bytes.Length < 1000 && bytes.ToList().Contains<byte[]>(Encoding.UTF8.GetBytes("Cloudflare"))) +// { +// Console.WriteLine($"[Asset cache] Cloudflare detected, retrying {"https://discord.com/assets/" + res} -> ./cache/{res}"); +// await Task.Delay(1000); +// resp = await hc.GetAsync("https://discord.com/assets/" + res); +// if (!resp.IsSuccessStatusCode) return NotFound(); +// bytes = await resp.Content.ReadAsByteArrayAsync(); +// }*/ +// if (res.EndsWith(".js") || res.EndsWith(".css")) { +// //remove sourcemap +// var str = Encoding.UTF8.GetString(bytes); +// str = PatchClient(str); +// bytes = Encoding.UTF8.GetBytes(str); +// } +// +// if (proxyConfiguration.AssetCache.DiskCache) await System.IO.File.WriteAllBytesAsync($"{proxyConfiguration.AssetCache.DiskCachePath}/{res}", bytes); +// cache.TryAdd(res, bytes); +// } +// //await new WebClient().DownloadFileTaskAsync("https://discord.com/assets/" + res, "./cache/" + res); +// //cache.TryAdd(res, await System.IO.File.ReadAllBytesAsync("./cache/" + res)); +// } +// catch (Exception e) { +// Console.WriteLine(e); +// return NotFound(); +// } +// } +// +// if (cache.ContainsKey(res)) { +// var result = cache[res]; +// if (!proxyConfiguration.AssetCache.MemoryCache) cache.TryRemove(res, out _); +// return File(result, contentType); +// } +// +// return NotFound(); +// } +// +// public string PatchClient(string str) { +// var patchOptions = proxyConfiguration.TestClient.DebugOptions.PatchOptions; +// str = str.Replace("//# sourceMappingURL=", "//# disabledSourceMappingURL="); +// str = str.Replace("https://fa97a90475514c03a42f80cd36d147c4@sentry.io/140984", "https://6bad92b0175d41a18a037a73d0cff282@sentry.thearcanebrony.net/12"); +// if (patchOptions.GatewayPlaintext) +// str = str.Replace("e.isDiscordGatewayPlaintextSet=function(){0;return!1};", "e.isDiscordGatewayPlaintextSet = function() { return true };"); +// +// if (patchOptions.NoXssWarning) { +// str = str.Replace("console.log(\"%c\"+n.SELF_XSS_", "console.valueOf(n.SELF_XSS_"); +// str = str.Replace("console.log(\"%c\".concat(n.SELF_XSS_", "console.valueOf(console.valueOf(n.SELF_XSS_"); +// } +// +// if (patchOptions.GatewayImmediateReconnect) str = str.Replace("nextReconnectIsImmediate=!1", "nextReconnectIsImmediate = true"); +// +// return str; +// } +// +// [HttpGet("/robots.txt")] +// public object Robots() => Resolvers.ReturnFile("./Resources/robots.txt"); +// +// [HttpGet("/favicon.ico")] +// public object Favicon() => Resolvers.ReturnFile("./Resources/RunData/favicon.png"); +//} \ No newline at end of file diff --git a/ReferenceClientProxyImplementation/Controllers/ErrorReportingProxy.cs b/ReferenceClientProxyImplementation/Controllers/ErrorReportingProxy.cs new file mode 100644
index 0000000..acc186b --- /dev/null +++ b/ReferenceClientProxyImplementation/Controllers/ErrorReportingProxy.cs
@@ -0,0 +1,34 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using Microsoft.AspNetCore.Mvc; + +namespace ReferenceClientProxyImplementation.Controllers; + +[Controller] +[Route("/")] +public class ErrorReportingProxy : Controller { + [HttpPost("/error-reporting-proxy/web")] + public async Task<ActionResult> HandleErrorReport() { + // read body as string + var body = await new StreamReader(Request.Body).ReadToEndAsync(); + var lines = body.Split('\n'); + var data = new JsonObject() { + ["eventInfo"] = JsonSerializer.Deserialize<JsonObject>(lines[0]), + ["typeInfo"] = JsonSerializer.Deserialize<JsonObject>(lines[1]), + ["stackTrace"] = JsonSerializer.Deserialize<JsonObject>(lines[2]), + }; + + if (lines.Length > 3) + for (var i = 3; i < lines.Length; i++) { + data[$"unk_line_{i}"] = JsonSerializer.Deserialize<JsonValue>(lines[i]); + } + + if (!System.IO.Directory.Exists("error_reports")) + System.IO.Directory.CreateDirectory("error_reports"); + await System.IO.File.WriteAllTextAsync($"error_reports/web_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}.json", data.ToJsonString(new JsonSerializerOptions { + WriteIndented = true + })); + + return NoContent(); + } +} \ No newline at end of file diff --git a/ReferenceClientProxyImplementation/Controllers/FrontendController.cs b/ReferenceClientProxyImplementation/Controllers/FrontendController.cs new file mode 100644
index 0000000..b12996d --- /dev/null +++ b/ReferenceClientProxyImplementation/Controllers/FrontendController.cs
@@ -0,0 +1,77 @@ +using Microsoft.AspNetCore.Mvc; +using ReferenceClientProxyImplementation.Configuration; +using ReferenceClientProxyImplementation.Helpers; +using ReferenceClientProxyImplementation.Patches.Implementations; + +namespace ReferenceClientProxyImplementation.Controllers; + +[Controller] +[Route("/")] +public class FrontendController(ProxyConfiguration proxyConfiguration, PatchSet patches) : Controller { + [HttpGet] + [HttpGet("/app")] + [HttpGet("/login")] + [HttpGet("/register")] + [HttpGet("/channels/@me")] + [HttpGet("/channels/{*_}")] + [HttpGet("/shop")] + [HttpGet("/app/{*_}")] + [HttpGet("/open")] + [HttpGet("/settings/{*_}")] + [HttpGet("/action/{*_}")] + [HttpGet("/library/{*_}")] + public async Task<Stream> Home() { + var patchedPath = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "patched", "app.html"); + if (!System.IO.File.Exists(patchedPath)) { + var path = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "src", "app.html"); + var patchedContent = await patches.ApplyPatches("app.html", await System.IO.File.ReadAllBytesAsync(path)); + Directory.CreateDirectory(Path.GetDirectoryName(patchedPath)!); + await System.IO.File.WriteAllBytesAsync(patchedPath, patchedContent); + } + + return System.IO.File.OpenRead(patchedPath); + // return null; + // if (!proxyConfiguration.TestClient.Enabled) + // return NotFound("Test client is disabled"); + // var html = await System.IO.File.ReadAllTextAsync(proxyConfiguration.TestClient.UseLatest ? "Resources/Pages/index-updated.html" : "Resources/Pages/index.html"); + // + // //inject debug utilities + // var debugOptions = proxyConfiguration.TestClient.DebugOptions; + // if (debugOptions.DumpWebsocketTrafficToBrowserConsole) + // html = html.Replace("<!-- preload plugin marker -->", + // await System.IO.File.ReadAllTextAsync("Resources/Private/Injections/WebSocketDataLog.html") + "\n<!-- preload plugin marker -->"); + // if (debugOptions.DumpWebsocketTraffic) + // html = html.Replace("<!-- preload plugin marker -->", + // await System.IO.File.ReadAllTextAsync("Resources/Private/Injections/WebSocketDumper.html") + "\n<!-- preload plugin marker -->"); + // + // return File(Encoding.UTF8.GetBytes(html), "text/html"); + } + + [HttpGet("/developers")] + [HttpGet("/developers/{*_}")] + public async Task<object> Developers() { + var patchedPath = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "patched", "developers.html"); + if (!System.IO.File.Exists(patchedPath)) { + var path = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "src", "developers.html"); + var patchedContent = await patches.ApplyPatches("developers.html", await System.IO.File.ReadAllBytesAsync(path)); + Directory.CreateDirectory(Path.GetDirectoryName(patchedPath)!); + await System.IO.File.WriteAllBytesAsync(patchedPath, patchedContent); + } + + return System.IO.File.OpenRead(patchedPath); + } + + [HttpGet("/popout")] + [HttpGet("/popout/{*_}")] + public async Task<object> Popout() { + var patchedPath = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "patched", "popout.html"); + if (!System.IO.File.Exists(patchedPath)) { + var path = Path.Combine(proxyConfiguration.TestClient.RevisionPath, "src", "popout.html"); + var patchedContent = await patches.ApplyPatches("popout.html", await System.IO.File.ReadAllBytesAsync(path)); + Directory.CreateDirectory(Path.GetDirectoryName(patchedPath)!); + await System.IO.File.WriteAllBytesAsync(patchedPath, patchedContent); + } + + return System.IO.File.OpenRead(patchedPath); + } +} diff --git a/ReferenceClientProxyImplementation/Controllers/StaticController.cs b/ReferenceClientProxyImplementation/Controllers/StaticController.cs new file mode 100644
index 0000000..a2ecf2c --- /dev/null +++ b/ReferenceClientProxyImplementation/Controllers/StaticController.cs
@@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using ReferenceClientProxyImplementation.Helpers; + +namespace ReferenceClientProxyImplementation.Controllers; + +[Controller] +[Route("/")] +public class StaticController : Controller { + [HttpGet("/resources/{*res:required}")] + public object Resource(string res) { + if (System.IO.File.Exists("./Resources/Static/" + res)) + return Resolvers.ReturnFile("./Resources/Static/" + res); + return new RedirectResult("https://discord.gg/assets/" + res); + } +} \ No newline at end of file