using System.Text; using MessagePack; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.Primitives; using Newtonsoft.Json; using SVSim.EmulatedEntrypoint.Security; namespace SVSim.EmulatedEntrypoint.Middlewares; /// /// Translates incoming requests and outgoing responses from the Shadowverse client into the messagepack format. /// public class ShadowverseTranslationMiddleware : IMiddleware { private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; public ShadowverseTranslationMiddleware(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) { _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { bool isUnity = context.Request.Headers.UserAgent.Any(agent => agent?.Contains("UnityPlayer") ?? false); string path = context.Request.Path; var endpointDescriptor = _actionDescriptorCollectionProvider.ActionDescriptors.Items.FirstOrDefault(ad => $"/{ad.AttributeRouteInfo.Template}".Equals(path, StringComparison.InvariantCultureIgnoreCase)); if (!isUnity || endpointDescriptor == null) { await next.Invoke(context); return; } using var requestBytesStream = new MemoryStream(); using var tempResponseBody = new MemoryStream(); var originalResponsebody = context.Response.Body; context.Response.Body = tempResponseBody; await context.Request.Body.CopyToAsync(requestBytesStream); byte[] requestBytes = requestBytesStream.ToArray(); // Decrypt incoming data. Placeholder. requestBytes = Encryption.Decrypt(requestBytes, Encryption.Decode(context.Request.Headers["UDID"])); object? data = MessagePackSerializer.Deserialize(endpointDescriptor.Parameters.FirstOrDefault().ParameterType, requestBytes); var json = JsonConvert.SerializeObject(data); var newStream = new StringContent(json, Encoding.UTF8, "application/json"); context.Request.Body = newStream.ReadAsStream(); context.Request.Headers.ContentType = new StringValues("application/json"); await next.Invoke(context); var responseType = ((ControllerActionDescriptor)endpointDescriptor).MethodInfo.ReturnType; if (responseType.IsGenericType && responseType.GetGenericTypeDefinition() == typeof(Task<>)) { responseType = responseType.GetGenericArguments()[0]; } using var responseBytesStream = new MemoryStream(); context.Response.Body.Seek(0, SeekOrigin.Begin); await context.Response.Body.CopyToAsync(responseBytesStream); var responseBytes = responseBytesStream.ToArray(); var responseData = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(responseBytes), responseType); var packedData = MessagePackSerializer.Serialize(responseType, responseData); packedData = Encryption.Encrypt(packedData, Encryption.Decode(context.Request.Headers["UDID"])); await originalResponsebody.WriteAsync(Encoding.UTF8.GetBytes(Convert.ToBase64String(packedData))); context.Response.Body = originalResponsebody; } }