From 48d9373e5013dc676e7a7448967dda7695d64291 Mon Sep 17 00:00:00 2001 From: tintinhamans <5984296+tintinhamans@users.noreply.github.com> Date: Sun, 9 Aug 2026 17:22:44 +0200 Subject: [PATCH 1/3] fix(login): handle unmapped known client IDs without returning 500 --- .../Controllers/CheckLogin/CheckLoginController.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/GenOnlineService/Controllers/CheckLogin/CheckLoginController.cs b/GenOnlineService/Controllers/CheckLogin/CheckLoginController.cs index 626a396..2de92fb 100644 --- a/GenOnlineService/Controllers/CheckLogin/CheckLoginController.cs +++ b/GenOnlineService/Controllers/CheckLogin/CheckLoginController.cs @@ -189,11 +189,10 @@ public async Task Post_InternalHandler(string jsonData, string ipAddr } // full login (known clients) - if (Enum.TryParse(typeof(KnownClients.EKnownClients), clientID, ignoreCase: true, out object knownClientIDObj)) + // Enum.TryParse also accepts "unknown" and arbitrary numeric strings, neither of which is mapped. + if (Enum.TryParse(clientID, ignoreCase: true, out KnownClients.EKnownClients knownClientID) + && KnownClients.KnownClientSessionTypes.TryGetValue(knownClientID, out EUserSessionType sessionType)) { - KnownClients.EKnownClients knownClientID = (KnownClients.EKnownClients)knownClientIDObj; - EUserSessionType sessionType = KnownClients.KnownClientSessionTypes[knownClientID]; - // Game clients should register the user device if (sessionType == EUserSessionType.GameClient) { From b0996ee71c8e464e6f336b93259e59193f4505ad Mon Sep 17 00:00:00 2001 From: tintinhamans <5984296+tintinhamans@users.noreply.github.com> Date: Sun, 9 Aug 2026 17:22:45 +0200 Subject: [PATCH 2/3] fix(matchdata): skip S3 initialization and signing when uploads are disabled --- GenOnlineService/Constants.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/GenOnlineService/Constants.cs b/GenOnlineService/Constants.cs index 985ae6f..37f1c15 100644 --- a/GenOnlineService/Constants.cs +++ b/GenOnlineService/Constants.cs @@ -2029,9 +2029,24 @@ public class TURNResponse public static class S3CredentialManager { private static AmazonS3Client m_s3client = null; + private static bool s_uploadsEnabled = false; public static void Initialize() { + if (Program.g_Config == null) + { + throw new Exception("Config not loaded"); + } + + s_uploadsEnabled = Program.g_Config.GetSection("MatchData").GetValue("upload_match_data") ?? false; + + // When uploads are disabled, the S3 settings are intentionally optional. + if (!s_uploadsEnabled) + { + Console.WriteLine("MatchData: upload_match_data is false, replay and screenshot uploads are disabled."); + return; + } + GetS3Config(out int TTL, out string access_key, out string secret_key, out string bucket_name, out string client_endpoint); var config = new AmazonS3Config @@ -2103,6 +2118,11 @@ private static void GetS3Config(out int TTL, out string access_key, out string s public static async Task GetPresignedURL(EMetadataFileType fileType, EScreenshotType screenshotTypeIfScreenshot, UInt64 matchID, Int64 userID, int slotIndex, DateTime matchStartTime) { + if (!s_uploadsEnabled || m_s3client == null) + { + return null; + } + GetS3Config(out int TTL, out string access_key, out string secret_key, out string bucket_name, out string client_endpoint); TimeSpan expiresIn = TimeSpan.FromMinutes(TTL); From 73429b0b3bfc644417268bbe5bce8b7bdc07b885 Mon Sep 17 00:00:00 2001 From: tintinhamans <5984296+tintinhamans@users.noreply.github.com> Date: Sun, 9 Aug 2026 17:22:45 +0200 Subject: [PATCH 3/3] fix(upload-urls): return empty URLs when match uploads are disabled --- GenOnlineService/Controllers/Lobby/LobbyController.cs | 4 ++-- GenOnlineService/Controllers/WebSocket/WebSocketController.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GenOnlineService/Controllers/Lobby/LobbyController.cs b/GenOnlineService/Controllers/Lobby/LobbyController.cs index f1b3774..00e3404 100644 --- a/GenOnlineService/Controllers/Lobby/LobbyController.cs +++ b/GenOnlineService/Controllers/Lobby/LobbyController.cs @@ -334,8 +334,8 @@ public async Task Delete(Int64 lobbyID) DailyStatsManager.RegisterOutcome(army, won); // give them back signed URLs they need - result.screenshot_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_SCREENSHOT, EScreenshotType.SCREENSHOT_TYPE_SCORESCREEN, match_id, user_id, slotIndexInLobby, LobbyCreationTime); - result.replay_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_REPLAY, EScreenshotType.NONE, match_id, user_id, slotIndexInLobby, LobbyCreationTime); + result.screenshot_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_SCREENSHOT, EScreenshotType.SCREENSHOT_TYPE_SCORESCREEN, match_id, user_id, slotIndexInLobby, LobbyCreationTime) ?? String.Empty; + result.replay_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_REPLAY, EScreenshotType.NONE, match_id, user_id, slotIndexInLobby, LobbyCreationTime) ?? String.Empty; // store in DB await using var db = await _dbFactory.CreateDbContextAsync(); diff --git a/GenOnlineService/Controllers/WebSocket/WebSocketController.cs b/GenOnlineService/Controllers/WebSocket/WebSocketController.cs index ec57472..067bb16 100644 --- a/GenOnlineService/Controllers/WebSocket/WebSocketController.cs +++ b/GenOnlineService/Controllers/WebSocket/WebSocketController.cs @@ -758,7 +758,7 @@ private async Task ProcessWSMessage(UserWebSocketInstance sourceWS, UserSession // response WebSocketMessage_StartMatch startCommand = new WebSocketMessage_StartMatch(); startCommand.msg_id = (int)EWebSocketMessageID.START_GAME; - startCommand.screenshot_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_SCREENSHOT, EScreenshotType.SCREENSHOT_TYPE_LOADSCREEN, lobbyInfo.MatchID, lobbyMember.UserID, lobbyMember.SlotIndex, lobbyInfo.TimeCreated); + startCommand.screenshot_url = await S3CredentialManager.GetPresignedURL(EMetadataFileType.FILE_TYPE_SCREENSHOT, EScreenshotType.SCREENSHOT_TYPE_LOADSCREEN, lobbyInfo.MatchID, lobbyMember.UserID, lobbyMember.SlotIndex, lobbyInfo.TimeCreated) ?? String.Empty; // Serialize once before broadcasting byte[] bytesJSON = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(startCommand));