using SVSim.EmulatedEntrypoint.Constants; using SVSim.EmulatedEntrypoint.Security; using SVSim.EmulatedEntrypoint.Services; namespace SVSim.EmulatedEntrypoint.Middlewares; /// /// Maps an incoming request's session id to a udid if both are present. /// public class SessionidMappingMiddleware : IMiddleware { private readonly ShadowverseSessionService _shadowverseSessionService; private readonly ILogger _logger; public SessionidMappingMiddleware( ShadowverseSessionService shadowverseSessionService, ILogger logger) { _shadowverseSessionService = shadowverseSessionService; _logger = logger; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { // NOTE: the bool names below were historically inverted (hasSessionId held UDID and // vice versa). Variable names corrected in-place; behavior unchanged. bool hasUdid = context.Request.Headers.TryGetValue(NetworkConstants.UdidHeaderName, out var udid); bool hasSid = context.Request.Headers.TryGetValue(NetworkConstants.SessionIdHeaderName, out var sid); if (hasUdid && hasSid) { string? sidValue = sid.FirstOrDefault(); string? encodedUdid = udid.FirstOrDefault(); try { string? decoded = Encryption.Decode(encodedUdid); Guid parsedUdid = Guid.Parse(decoded); _shadowverseSessionService.StoreUdidForSessionId(sidValue, parsedUdid); _logger.LogDebug( "Stored SID→UDID mapping for {Path} (sid={Sid}, udid={Udid}).", context.Request.Path, sidValue, parsedUdid); } catch (Exception ex) { _logger.LogError(ex, "Failed to decode/parse UDID header for {Path} (sid={Sid}, encodedUdidLen={EncodedUdidLen}). " + "Downstream translation will fall back to Guid.Empty and almost certainly fail msgpack decrypt.", context.Request.Path, sidValue, encodedUdid?.Length ?? 0); } } else if (hasUdid ^ hasSid) { // Only one of the two headers present — usually a client bug or a test that forgot // to set both. The translation middleware will then fall back to Guid.Empty and // surface as a generic msgpack/decrypt error, so warn here where the cause is clear. _logger.LogWarning( "Only one of UDID/SID headers present for {Path} (hasUdid={HasUdid}, hasSid={HasSid}). " + "Translation will use Guid.Empty as the encryption key.", context.Request.Path, hasUdid, hasSid); } await next.Invoke(context); } }