From c52e7daeafd0cccff6e6b14cebd986af47539eb6 Mon Sep 17 00:00:00 2001 From: Kayori Date: Thu, 29 Jan 2026 23:24:03 +0100 Subject: [PATCH] Added more attribute types. Added GnInquire for charge machine. Added handeling for when plugin still returns XDocument instead of typed response. Fixed 500 error when no encoding specified. Move Handle method after return --- Abstractions/SerializationTypes/XrpcIp4.cs | 12 +++ Abstractions/SerializationTypes/XrpcLong.cs | 26 +++++- Abstractions/SerializationTypes/XrpcULong.cs | 25 +++++- Core/Client/package-lock.json | 12 +-- .../Handlers/Boot/GetServicesHandler.cs | 3 +- .../Card/GnInquireCardManagementHandler.cs | 79 ++++++++++++++++++ .../Handlers/Common/GetFacilityHandler.cs | 14 ++-- .../Common/OTAUpdates/ListPackageHandler.cs | 1 + .../Models/Response/GetFacilityResponse.cs | 4 +- .../Models/Response/GetMessageResponse.cs | 2 +- .../Models/Response/GetServicesResponse.cs | 4 +- .../Models/Response/GnInquireResponse.cs | 45 ++++++++++ .../Models/Response/ListPackageResponse.cs | 5 +- Core/Server/Program.cs | 35 ++++---- Core/Server/Services/HandlerService.cs | 16 +++- Core/Server/database/Medusa.db | Bin 110592 -> 110592 bytes 16 files changed, 232 insertions(+), 51 deletions(-) create mode 100644 Abstractions/SerializationTypes/XrpcIp4.cs create mode 100644 Core/Server/Handlers/Common/Card/GnInquireCardManagementHandler.cs create mode 100644 Core/Server/Models/Response/GnInquireResponse.cs diff --git a/Abstractions/SerializationTypes/XrpcIp4.cs b/Abstractions/SerializationTypes/XrpcIp4.cs new file mode 100644 index 0000000..e2449a1 --- /dev/null +++ b/Abstractions/SerializationTypes/XrpcIp4.cs @@ -0,0 +1,12 @@ +using System.Xml.Serialization; + +namespace Abstractions.SerializationTypes; + +public struct XrpcIp4(string value) +{ + [XmlAttribute("__type")] + public string Type { get; set; } = "ip4"; + + [XmlText] + public string Value { get; set; } = value; +} \ No newline at end of file diff --git a/Abstractions/SerializationTypes/XrpcLong.cs b/Abstractions/SerializationTypes/XrpcLong.cs index 5a52f93..1675325 100644 --- a/Abstractions/SerializationTypes/XrpcLong.cs +++ b/Abstractions/SerializationTypes/XrpcLong.cs @@ -2,11 +2,29 @@ using System.Xml.Serialization; namespace Abstractions.SerializationTypes; -public struct XrpcLong(long value) +public struct XrpcLong { [XmlAttribute("__type")] - public string Type { get; set; } = "s64"; - + public string Type { get; set; } + [XmlText] - public long Value { get; set; } = value; + public long Value { get; set; } + + public XrpcLong(byte value) + { + Value = value; + Type = "s8"; + } + + public XrpcLong(short value) + { + Value = value; + Type = "s16"; + } + + public XrpcLong(long value) + { + Value = value; + Type = "s32"; + } } \ No newline at end of file diff --git a/Abstractions/SerializationTypes/XrpcULong.cs b/Abstractions/SerializationTypes/XrpcULong.cs index f02670c..b9cafb5 100644 --- a/Abstractions/SerializationTypes/XrpcULong.cs +++ b/Abstractions/SerializationTypes/XrpcULong.cs @@ -2,10 +2,29 @@ using System.Xml.Serialization; namespace Abstractions.SerializationTypes; -public struct XrpcULong(ulong value) +public struct XrpcULong { [XmlAttribute("__type")] - public string Type { get; set; } = "u64"; + public string Type { get; set; } - [XmlText] public ulong Value { get; set; } = value; + [XmlText] + public ulong Value { get; set; } + + public XrpcULong(byte value) + { + Value = value; + Type = "u8"; + } + + public XrpcULong(ushort value) + { + Value = value; + Type = "u16"; + } + + public XrpcULong(ulong value) + { + Value = value; + Type = "u32"; + } } \ No newline at end of file diff --git a/Core/Client/package-lock.json b/Core/Client/package-lock.json index e7e5705..544eb69 100644 --- a/Core/Client/package-lock.json +++ b/Core/Client/package-lock.json @@ -1321,7 +1321,6 @@ "integrity": "sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.19.2" } @@ -1366,7 +1365,6 @@ "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -1849,7 +1847,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2407,7 +2404,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -2464,7 +2460,6 @@ "integrity": "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -4452,8 +4447,7 @@ "version": "4.1.11", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tailwindcss-primeui": { "version": "0.6.1", @@ -4566,7 +4560,6 @@ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4739,7 +4732,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -4821,7 +4813,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", @@ -4868,7 +4859,6 @@ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", "license": "MIT", - "peer": true, "dependencies": { "@vue/devtools-api": "^6.6.4" }, diff --git a/Core/Server/Handlers/Boot/GetServicesHandler.cs b/Core/Server/Handlers/Boot/GetServicesHandler.cs index 4476635..80deed0 100644 --- a/Core/Server/Handlers/Boot/GetServicesHandler.cs +++ b/Core/Server/Handlers/Boot/GetServicesHandler.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Hosting.Server; using System.Xml.Linq; using Abstractions.Handlers; -using Abstractions.SerializationTypes; using Abstractions.Utils; using Server.Models.Response; @@ -28,7 +27,7 @@ namespace Server.Handlers.Boot private static GetServicesResponse CreateCoreServicesElement() { var services = new GetServicesResponse() - { + { Expire = 3600, Method = "get", Mode = "operation", diff --git a/Core/Server/Handlers/Common/Card/GnInquireCardManagementHandler.cs b/Core/Server/Handlers/Common/Card/GnInquireCardManagementHandler.cs new file mode 100644 index 0000000..df7bc2f --- /dev/null +++ b/Core/Server/Handlers/Common/Card/GnInquireCardManagementHandler.cs @@ -0,0 +1,79 @@ +using Abstractions.Handlers; +using Abstractions.Services; +using Server.Models.Request; +using Server.Models.Response; +using Server.Services; + +namespace Server.Handlers.Common.Card +{ + public class GnInquireCardManagementHandler(IPluginService pluginService, ICardService cardService) : Handler + { + public override void Configure() + { + Module("cardmng"); + Method("gninquire"); + } + + public override async Task HandleAsync(InquireRequest req, string model) + { + var splitModel = model.Split(':'); + var gameCode = splitModel[0]; + + var plugin = pluginService.FindPlugin(gameCode); + + var cardId = req.CardId; + + var inquireResponse = new GnInquireResponse() + { + Status = 0 + }; + + if (string.IsNullOrEmpty(cardId)) + { + inquireResponse.Status = 111; + return inquireResponse; + } + + var konamiId = cardService.ConvertUidToKonamiId(cardId); + + if (string.IsNullOrEmpty(konamiId)) + { + inquireResponse.Status = 111; + return inquireResponse; + } + + var exisitngCard = await cardService.FindByKonamiId(konamiId); + + if (exisitngCard == null) + { + inquireResponse.Status = 112; + return inquireResponse; + } + + if (plugin is null) + { + inquireResponse.Status = 113; + return inquireResponse; + } + + var profileExists = await plugin!.DoesProfileExist(cardId); + + var userIdFlag = profileExists ? "1" : "0"; + var extIdFlag = profileExists ? "1" : "0"; + var newFlag = profileExists ? "0" : "1"; + var isGeniune = profileExists ? "1" : "0"; + + inquireResponse.Binded = 0; + inquireResponse.DataId = konamiId; + inquireResponse.EcFlag = 1; + inquireResponse.Expired = 0; + inquireResponse.NewFlag = newFlag; + inquireResponse.IsGeniune = isGeniune; + inquireResponse.ExtidFlag = extIdFlag; + inquireResponse.RefId = konamiId; + inquireResponse.UserIdFlag = userIdFlag; + + return inquireResponse; + } + } +} diff --git a/Core/Server/Handlers/Common/GetFacilityHandler.cs b/Core/Server/Handlers/Common/GetFacilityHandler.cs index d8b1b10..2d5ecf3 100644 --- a/Core/Server/Handlers/Common/GetFacilityHandler.cs +++ b/Core/Server/Handlers/Common/GetFacilityHandler.cs @@ -20,7 +20,7 @@ public class GetFacilityHandler: HandlerWithoutRequest Location = new FacilityLocation() { Id = new XrpcString("00000000"), - Country = new XrpcString("US"), + Country = new XrpcString("JP"), Region = new XrpcString("NA"), Name = new XrpcString("Medusa"), Type = new XrpcULong(0) @@ -32,7 +32,7 @@ public class GetFacilityHandler: HandlerWithoutRequest }, PortForward = new FacilityPortForward() { - GlobalIp = new XrpcString("127.0.0.1"), + GlobalIp = new XrpcIp4("127.0.0.1"), GlobalPort = new XrpcULong(5246), PrivatePort = new XrpcULong(5246) }, @@ -40,16 +40,16 @@ public class GetFacilityHandler: HandlerWithoutRequest { Flag = new XrpcULong(1), Name = new XrpcString("Medusa"), - Latitude = new XrpcString("0.0"), - Longitude = new XrpcString("0.0") + Latitude = new XrpcString("0"), + Longitude = new XrpcString("0") }, Share = new FacilityShare() { EaCoin = new FacilityEaCoin() { - NotchAmount = new XrpcLong(3000), - NotchCount = new XrpcLong(3), - SupplyLimit = new XrpcLong(100000) + NotchAmount = new XrpcLong((long)3000), + NotchCount = new XrpcLong((long)3), + SupplyLimit = new XrpcLong(1000000) }, Url = new FacilityUrl() { diff --git a/Core/Server/Handlers/Common/OTAUpdates/ListPackageHandler.cs b/Core/Server/Handlers/Common/OTAUpdates/ListPackageHandler.cs index 02b977d..9eafef6 100644 --- a/Core/Server/Handlers/Common/OTAUpdates/ListPackageHandler.cs +++ b/Core/Server/Handlers/Common/OTAUpdates/ListPackageHandler.cs @@ -15,6 +15,7 @@ public class ListPackageHandler: HandlerWithoutRequest { var package = new ListPackageResponse() { + Expire = 1200, Status = 0 }; diff --git a/Core/Server/Models/Response/GetFacilityResponse.cs b/Core/Server/Models/Response/GetFacilityResponse.cs index 30feedb..59ab685 100644 --- a/Core/Server/Models/Response/GetFacilityResponse.cs +++ b/Core/Server/Models/Response/GetFacilityResponse.cs @@ -9,7 +9,7 @@ public class GetFacilityResponse { [XmlAttribute("status")] public required int Status { get; set; } - + [XmlElement("location")] public required FacilityLocation Location { get; set; } @@ -56,7 +56,7 @@ public record FacilityLine public record FacilityPortForward { [XmlElement("globalip")] - public required XrpcString GlobalIp { get; set; } + public required XrpcIp4 GlobalIp { get; set; } [XmlElement("globalport")] public required XrpcULong GlobalPort { get; set; } diff --git a/Core/Server/Models/Response/GetMessageResponse.cs b/Core/Server/Models/Response/GetMessageResponse.cs index 49c69bb..b7fbdbf 100644 --- a/Core/Server/Models/Response/GetMessageResponse.cs +++ b/Core/Server/Models/Response/GetMessageResponse.cs @@ -7,7 +7,7 @@ namespace Server.Models.Response; public class GetMessageResponse { [XmlAttribute("status")] - public required int Status { get; set; } + public required int Status { get; set; } [XmlAttribute("expire")] public required int Expire { get; set; } diff --git a/Core/Server/Models/Response/GetServicesResponse.cs b/Core/Server/Models/Response/GetServicesResponse.cs index 6d91d52..7e0fbe9 100644 --- a/Core/Server/Models/Response/GetServicesResponse.cs +++ b/Core/Server/Models/Response/GetServicesResponse.cs @@ -10,8 +10,8 @@ public class GetServicesResponse public int Expire { get; set; } [XmlAttribute("method")] - public required string Method { get; set; } - + public required string Method { get; set; } + [XmlAttribute("mode")] public required string Mode { get; set; } diff --git a/Core/Server/Models/Response/GnInquireResponse.cs b/Core/Server/Models/Response/GnInquireResponse.cs new file mode 100644 index 0000000..b0122bd --- /dev/null +++ b/Core/Server/Models/Response/GnInquireResponse.cs @@ -0,0 +1,45 @@ +using System.Xml.Serialization; + +namespace Server.Models.Response; + +[XmlRoot("cardmng")] +[Serializable] +public class GnInquireResponse +{ + [XmlAttribute("status")] + public required int Status { get; set; } + + [XmlAttribute("binded")] + public int Binded { get; set; } + + [XmlAttribute("dataid")] + public string DataId { get; set; } = ""; + + [XmlAttribute("ecflag")] + public int EcFlag { get; set; } + + [XmlAttribute("expired")] + public int Expired { get; set; } + + [XmlAttribute("newflag")] + public string NewFlag { get; set; } = ""; + + [XmlAttribute("isgenuine")] + public string IsGeniune { get; set; } = ""; + + + [XmlAttribute("altstatus")] + public string AltStatus { get; set; } = ""; + + [XmlAttribute("articleno")] + public string ArticleNo { get; set; } = ""; + + [XmlAttribute("extidflag")] + public string ExtidFlag { get; set; } = ""; + + [XmlAttribute("refid")] + public string RefId { get; set; } = ""; + + [XmlAttribute("useridflag")] + public string UserIdFlag { get; set; } = ""; +} \ No newline at end of file diff --git a/Core/Server/Models/Response/ListPackageResponse.cs b/Core/Server/Models/Response/ListPackageResponse.cs index 353a805..50f3eeb 100644 --- a/Core/Server/Models/Response/ListPackageResponse.cs +++ b/Core/Server/Models/Response/ListPackageResponse.cs @@ -7,5 +7,8 @@ namespace Server.Models.Response; public class ListPackageResponse { [XmlAttribute("status")] - public required int Status { get; set; } + public required int Status { get; set; } + + [XmlAttribute("expire")] + public required int Expire { get; set; } } \ No newline at end of file diff --git a/Core/Server/Program.cs b/Core/Server/Program.cs index 8d5e263..18658fc 100644 --- a/Core/Server/Program.cs +++ b/Core/Server/Program.cs @@ -21,6 +21,7 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; +using System.Xml; using System.Xml.Linq; var key = @@ -115,6 +116,7 @@ var eamuseGroup = app.MapGroup("eamuse"); eamuseGroup.MapPost("/{model}/{module}/{method}", async (string model, string module, string method, HttpContext httpContext, [FromServices] ILogger logger, [FromServices] IHandlerService handlerService, [FromServices] IPluginService pluginService) => { + Console.WriteLine(httpContext.Request.Headers.UserAgent); // Enable buffering to allow multiple reads of the request body httpContext.Request.EnableBuffering(); var body = ""; @@ -132,7 +134,7 @@ var eamuseGroup = app.MapGroup("eamuse"); var amusementRequest = new AmusementRequest() { Model = model, Module = module ?? "", Method = method ?? "" }; - var encoding = httpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS"; + var encoding = httpContext.Items["Encoding"]?.ToString() ?? "SHIFT_JIS"; httpContext.Request.Headers.TryGetValue("IsEncoded", out var isEncoded); @@ -148,6 +150,7 @@ var eamuseGroup = app.MapGroup("eamuse"); eamuseGroup.MapPost("/{m}", async (string m, [FromQuery] string model, [FromQuery] string? module, [FromQuery] string? method, [FromQuery] string? f, HttpContext httpContext, [FromServices] ILogger logger, [FromServices] IHandlerService handlerService, [FromServices] IPluginService pluginService) => { + Console.WriteLine(httpContext.Request.Headers.UserAgent); // Enable buffering to allow multiple reads of the request body httpContext.Request.EnableBuffering(); var body = ""; @@ -172,7 +175,7 @@ var eamuseGroup = app.MapGroup("eamuse"); amusementRequest.Method = fParts[1]; } - var encoding = httpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS"; + var encoding = httpContext.Items["Encoding"]?.ToString() ?? "SHIFT_JIS"; httpContext.Request.Headers.TryGetValue("IsEncoded", out var isEncoded); @@ -188,7 +191,7 @@ var eamuseGroup = app.MapGroup("eamuse"); eamuseGroup.MapPost("/", async ([FromQuery] string model, [FromQuery] string? module, [FromQuery] string? method, [FromQuery] string? f, HttpContext httpContext, [FromServices] ILogger logger, [FromServices] IHandlerService handlerService, [FromServices] IPluginService pluginService) => { - + Console.WriteLine(httpContext.Request.Headers.UserAgent); // Enable buffering to allow multiple reads of the request body httpContext.Request.EnableBuffering(); var body = ""; @@ -213,7 +216,7 @@ var eamuseGroup = app.MapGroup("eamuse"); amusementRequest.Method = fParts[1]; } - var encoding = httpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS"; + var encoding = httpContext.Items["Encoding"]?.ToString() ?? "SHIFT_JIS"; httpContext.Request.Headers.TryGetValue("IsEncoded", out var isEncoded); @@ -226,6 +229,17 @@ var eamuseGroup = app.MapGroup("eamuse"); return TypedResults.Bytes(result, "application/octet-stream"); }); + app.MapFallbackToFile("/index.html"); + +await using var scope = app.Services.CreateAsyncScope(); + +var appDbContext = scope.ServiceProvider.GetRequiredService(); + +await appDbContext.Database.MigrateAsync(); + +app.Run(); +return; + async Task HandleEAmuseRequest(AmusementRequest request, string body, string info, bool compress, bool encrypt, bool isEncoded, string encoding, ILogger logger, IHandlerService handlerService, IPluginService pluginService) { logger.LogInformation("Handling {Module} {Method}", request.Module, request.Method); @@ -238,7 +252,7 @@ async Task HandleEAmuseRequest(AmusementRequest request, string body, st var responseXml = await handlerService.Handle(request.Model, request.Module, request.Method, document); var plugins = pluginService.GetPlugins(); - var forcedEncoding = plugins.FirstOrDefault(p => p.GameCode == request.Model)?.ForcedEncoding; + var forcedEncoding = plugins.FirstOrDefault(p => p.GameCode == request.Model.Split(":")[0])?.ForcedEncoding; var encodingEnum = encoding switch { @@ -293,14 +307,3 @@ async Task HandleEAmuseRequest(AmusementRequest request, string body, st return encodedBody; } -app.MapFallbackToFile("/index.html"); - -await using var scope = app.Services.CreateAsyncScope(); - -var appDbContext = scope.ServiceProvider.GetRequiredService(); - -await appDbContext.Database.MigrateAsync(); - -app.Run(); -return; - diff --git a/Core/Server/Services/HandlerService.cs b/Core/Server/Services/HandlerService.cs index 1b0ff3f..5d21eb7 100644 --- a/Core/Server/Services/HandlerService.cs +++ b/Core/Server/Services/HandlerService.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Xml; using Server.Attributes; using System.Xml.Linq; using System.Xml.Serialization; @@ -211,7 +212,8 @@ public class HandlerService(IServiceScopeFactory serviceScopeFactory, ILogger2Q|{TX?itFkS6bE_zvLXAGpPX%WvWtCa3N`) x%aVF-$vv6NqAc9m2QL1@qjeY-VYfT0RuA#WoBOv0RtllL340UWpq_@WpZ;0vjK4bFQR}DvY-S| gvjjl>548aS18}nhK>QDpPz$#UfC2drvjlMbAGSay8UO$Q