Initial commit: RR3 Community Server with web admin panel

- ASP.NET Core 8 REST API server
- 12 API endpoints matching EA Synergy protocol
- SQLite database with Entity Framework Core
- Web admin panel with Bootstrap 5
- User, Catalog, Session, Purchase management
- Comprehensive documentation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-02-17 22:02:12 -08:00
commit 0a327f3a8b
187 changed files with 9282 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
namespace RR3CommunityServer.Middleware;
public class SynergyHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<SynergyHeadersMiddleware> _logger;
public SynergyHeadersMiddleware(RequestDelegate next, ILogger<SynergyHeadersMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
// Log incoming Synergy headers
var sessionId = context.Request.Headers["EAM-SESSION"].FirstOrDefault();
var userId = context.Request.Headers["EAM-USER-ID"].FirstOrDefault();
var sellId = context.Request.Headers["EA-SELL-ID"].FirstOrDefault();
var sdkVersion = context.Request.Headers["SDK-VERSION"].FirstOrDefault();
_logger.LogInformation(
"Synergy Request: Path={Path}, Session={Session}, User={User}, Sell={Sell}, SDK={SDK}",
context.Request.Path,
sessionId ?? "none",
userId ?? "none",
sellId ?? "none",
sdkVersion ?? "none"
);
// Store in context for controllers
context.Items["EAM-SESSION"] = sessionId;
context.Items["EAM-USER-ID"] = userId;
context.Items["EA-SELL-ID"] = sellId;
await _next(context);
}
}
public class SessionValidationMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<SessionValidationMiddleware> _logger;
// Paths that don't require session validation
private static readonly HashSet<string> PublicPaths = new()
{
"/director/api/android/getDirectionByPackage",
"/user/api/android/getDeviceID",
"/user/api/android/getAnonUid",
"/swagger",
"/health"
};
public SessionValidationMiddleware(RequestDelegate next, ILogger<SessionValidationMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var path = context.Request.Path.Value ?? "";
// Skip validation for public paths
if (PublicPaths.Any(p => path.StartsWith(p, StringComparison.OrdinalIgnoreCase)))
{
await _next(context);
return;
}
// For now, allow all requests (lenient for community server)
// In production, validate session here
await _next(context);
}
}