Medusa.net/Medusa.Core/Endpoints/PostCoreEndpoint.cs

107 lines
4.0 KiB
C#

using FastEndpoints;
using KbinXml.Net;
using Medusa.Core.Request;
using Medusa.Core.Services;
using Medusa.Core.Utils;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
namespace Medusa.Core.Endpoints;
public class PostCoreEndpoint(IHandlerService handlerService, ILogger<PostCoreEndpoint> logger) : EndpointWithoutRequest
{
static readonly byte[] Key =
Convert.FromHexString("00000000000069D74627D985EE2187161570D08D93B12455035B6DF0D8205DF5");
private readonly IHandlerService _handlerService = handlerService;
private readonly ILogger<PostCoreEndpoint> _logger = logger;
public override void Configure()
{
Post("{**catchAll}");
AllowAnonymous();
}
public override async Task HandleAsync(CancellationToken ct)
{
// Enable buffering to allow multiple reads of the request body
HttpContext.Request.EnableBuffering();
// The body is 932 encoded xml
using var reader = new StreamReader(HttpContext.Request.Body, Encoding.GetEncoding(932), false, 1024, true);
var body = await reader.ReadToEndAsync();
HttpContext.Request.Body.Position = 0;
bool compress = HttpContext.Request.Headers["X-Compress"].ToString().Contains("lz77");
bool encrypt = HttpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault() is not null;
var amusementRequest = new AmusementRequest() { Method = "", Model = "", Module = "" };
//Check if request is query or path type
if(HttpContext.Request.Query.Count > 0)
{
var query = HttpContext.Request.Query;
var model = query.TryGetValue("model", out var modelValue) ? modelValue.ToString() : "";
var module = query.TryGetValue("module", out var moduleValue) ? moduleValue.ToString() : "";
var method = query.TryGetValue("method", out var methodValue) ? methodValue.ToString() : "";
amusementRequest.Model = model;
amusementRequest.Module = module;
amusementRequest.Method = method;
}
else
{
// Else get the last 3 values from the path from the end
var pathValues = HttpContext.Request.Path.ToString().Split('/').Skip(1).ToArray();
amusementRequest.Model = pathValues[^3];
amusementRequest.Module = pathValues[^2];
amusementRequest.Method = pathValues[^1];
//remove the last 3 values from the path
HttpContext.Request.Path = string.Join("/", HttpContext.Request.Path.ToString().Split('/').SkipLast(3).ToArray());
}
_logger.LogInformation("Handling {Module} {Method}", amusementRequest.Module, amusementRequest.Method);
var document = XDocument.Parse(body);
var responseXml = await _handlerService.Handle(amusementRequest.Model, amusementRequest.Module, amusementRequest.Method, document);
var encoding = HttpContext.Items["Encoding"]?.ToString() ?? "ShiftJIS";
switch(encoding)
{
case "shift_jis":
encoding = "ShiftJIS";
break;
case "us-ascii":
encoding = "ASCII";
break;
}
byte[] encodedBody = KbinConverter.Write(responseXml, (KnownEncodings)Enum.Parse(typeof(KnownEncodings), encoding, true));
if(compress)
{
encodedBody = LZ77.CompressEmpty(encodedBody);
}
if(encrypt)
{
string[] originalInfo = HttpContext.Request.Headers["X-Eamuse-Info"].FirstOrDefault()?.Split('-') ?? [];
byte[] part = Convert.FromHexString((originalInfo[1] + originalInfo[2]));
for(int i = 0; i < 6; i++)
Key[i] = part[i];
var rc4Key = MD5.HashData(Key);
encodedBody = RC4.Encrypt(rc4Key, encodedBody);
HttpContext.Response.Headers.Append("X-Eamuse-Info", string.Join('-', originalInfo));
}
await SendBytesAsync(encodedBody);
}
}