81 lines
3.9 KiB
C#
81 lines
3.9 KiB
C#
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.Constants;
|
|
using SVSim.EmulatedEntrypoint.Security;
|
|
using SVSim.EmulatedEntrypoint.Services;
|
|
|
|
namespace SVSim.EmulatedEntrypoint.Middlewares;
|
|
|
|
/// <summary>
|
|
/// Translates incoming requests and outgoing responses from the Shadowverse client into the messagepack format.
|
|
/// </summary>
|
|
public class ShadowverseTranslationMiddleware : IMiddleware
|
|
{
|
|
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
|
|
private readonly ShadowverseSessionService _sessionService;
|
|
|
|
public ShadowverseTranslationMiddleware(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider, ShadowverseSessionService sessionService)
|
|
{
|
|
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
|
|
_sessionService = sessionService;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// Replace response body stream to re-access it.
|
|
using var tempResponseBody = new MemoryStream();
|
|
var originalResponsebody = context.Response.Body;
|
|
context.Response.Body = tempResponseBody;
|
|
|
|
// Pull out the request bytes into a stream
|
|
using var requestBytesStream = new MemoryStream();
|
|
await context.Request.Body.CopyToAsync(requestBytesStream);
|
|
byte[] requestBytes = requestBytesStream.ToArray();
|
|
|
|
// Get encryption values for this request
|
|
string sid = context.Request.Headers[NetworkConstants.SessionIdHeaderName];
|
|
string udid = _sessionService.GetUdidFromSessionId(sid).GetValueOrDefault().ToString();
|
|
|
|
// Decrypt incoming data.
|
|
requestBytes = Encryption.Decrypt(requestBytes, 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);
|
|
|
|
// Convert the response into a messagepack, encrypt it
|
|
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, udid);
|
|
await originalResponsebody.WriteAsync(Encoding.UTF8.GetBytes(Convert.ToBase64String(packedData)));
|
|
context.Response.Body = originalResponsebody;
|
|
}
|
|
} |