using ModMenu; using Func; using System; using System.Collections.Generic; using System.Text; using System.Text.Json; using System.Text.Encodings.Web; using System.Text.RegularExpressions; using System.Security.Cryptography; using System.Text.Json.Serialization; using System.Security.Cryptography.X509Certificates; namespace TelemetryWebpost { public class SplatTelemetry { private static readonly HttpClient client = new HttpClient(); public static uint LastStartNetworkTime = 0; public static string Telemetry2Json(byte[] rawData) { if (rawData == null || rawData.Length == 0) return "{}"; int actualStart = Array.IndexOf(rawData, (byte)0x2D); if (actualStart == -1) return "{}"; string content = Encoding.UTF8.GetString(rawData, actualStart, rawData.Length - actualStart); string[] lines = content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); if (lines.Length == 0 || string.IsNullOrWhiteSpace(lines[0])) return "{}"; string boundary = lines[0].Trim(); string[] parts = content.Split(new[] { boundary }, StringSplitOptions.RemoveEmptyEntries); var result = new Dictionary(); foreach (var part in parts) { if (string.IsNullOrWhiteSpace(part) || part.Trim() == "--" || part.Contains("name=\"FaceImg\"") || // Kit Kat said he doesnt need faceimg.tga so i'll skip it :innocent:, makes my life easier. !part.Contains("Content-Disposition")) { continue; } var nameMatch = Regex.Match(part, "name=\"(?[^\"]+)\""); if (!nameMatch.Success) continue; string key = nameMatch.Groups["name"].Value; int valueStart = part.IndexOf("\r\n\r\n"); int offset = 4; if (valueStart == -1) { valueStart = part.IndexOf("\n\n"); offset = 2; } if (valueStart == -1) continue; string value = part.Substring(valueStart + offset).Trim(new[] { '\r', '\n', '-', ' ' }); result[key] = value; } var options = new JsonSerializerOptions { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; return JsonSerializer.Serialize(result, options); } public static async Task SendTelemetryHttp(string targetUrl, string uniqueId, string TelemetryPayload, byte[] faceImgData) { var TelemetryPayloadDict = JsonSerializer.Deserialize>(TelemetryPayload); TelemetryPayloadDict["ServerEnv"] = "L1"; if (LastStartNetworkTime == Convert.ToUInt32(TelemetryPayloadDict["StartNetworkTime"])) { Console.WriteLine("Data sent already..."); return; } LastStartNetworkTime = Convert.ToUInt32(TelemetryPayloadDict["StartNetworkTime"]); try { using (var content = new MultipartFormDataContent()) { foreach (var kvp in TelemetryPayloadDict) { content.Add(new StringContent(kvp.Value), kvp.Key); } var imageContent = new ByteArrayContent(faceImgData); imageContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); content.Add(imageContent, "FaceImg", "face.bin"); byte[] requestBody = await content.ReadAsByteArrayAsync(); string sha1Hash; using (SHA1 sha1 = SHA1.Create()) { byte[] hashBytes = sha1.ComputeHash(requestBody); sha1Hash = BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); } var request = new HttpRequestMessage(HttpMethod.Post, targetUrl); request.Content = content; request.Headers.Add("X-BOSS-Digest", sha1Hash); request.Headers.Add("X-BOSS-UniqueId", uniqueId); Console.WriteLine($"Sending telemetry for {TelemetryPayloadDict["MiiName"]}..."); HttpResponseMessage response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { Console.WriteLine("SUCCESS: Splatoon result saved."); } else { string errorText = await response.Content.ReadAsStringAsync(); Console.WriteLine($"FAILED: {(int)response.StatusCode} - {errorText}"); } } } catch (Exception ex) { Console.WriteLine($"Connection Error: {ex.Message}"); } } public static void SendTelemetry() { if (Program.readUInt32(0x101E4FF8) == 0) { var p = Program.readUInt32(0x101DCDB0) + 0x150; var data = Program.readBytes(p, 0x1800); byte[] faceimg_pattern = new byte[]{ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00 }; int faceimg_offset = ExtFunc.FindPattern(data, faceimg_pattern); if (faceimg_offset == -1) { return; } var faceimg = Program.readBytes((uint)(p + faceimg_offset), 65580); var TelemetryPayload = Telemetry2Json(data); // Console.WriteLine(TelemetryPayload); SendTelemetryHttp(Program.config["TelemetryUrl"], "0162b", TelemetryPayload, faceimg).GetAwaiter().GetResult(); } } } }