From eb4349031b62f38fc8f68c6e2e84269e4a3ce4dd Mon Sep 17 00:00:00 2001 From: MiscFrizzy Date: Mon, 7 Apr 2025 07:30:34 -0400 Subject: [PATCH] ### Commit Summary - **TestSetup.cs** - Updated `CreateTestConfig` method to initialize `Config` with required properties using object initializer syntax. - **ProxyIntegrationTests.cs** - Added null checks for `mockServer.Urls` before accessing it to prevent potential null reference exceptions. - Improved error handling for mock server URL access. - **VRChatAuthenticationTests.cs** - Added null checks for `mockServer.Urls` before accessing it to prevent potential null reference exceptions. - Enhanced the mock server setup to include null checks for request body content. - **Config.cs** - Added the `required` modifier to non-nullable properties in `ConfigAccount` and `iConfig` classes. - Updated the `Load` method to initialize the `Config` instance with required properties using object initializer syntax. - **Program.cs** - Added a null check for `result.CloseStatus` in WebSocket handling to prevent potential null reference exceptions. --- Tests/Helpers/TestSetup.cs | 26 +++++++++---------- Tests/Integration/ProxyIntegrationTests.cs | 24 ++++++++++++----- .../Integration/VRChatAuthenticationTests.cs | 16 +++++++++--- VRCAuthProxy/Config.cs | 19 ++++++++++---- VRCAuthProxy/Program.cs | 2 +- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/Tests/Helpers/TestSetup.cs b/Tests/Helpers/TestSetup.cs index 5bbf1e0..5fab7a2 100644 --- a/Tests/Helpers/TestSetup.cs +++ b/Tests/Helpers/TestSetup.cs @@ -23,23 +23,23 @@ namespace VRCAuthProxy.Tests.Helpers /// public static Config CreateTestConfig() { - var config = new Config(); - config.Accounts = new List + return new Config { - new ConfigAccount + Accounts = new List { - username = "testuser1", - password = "testpassword1", - totpSecret = "TESTSECRET1" - }, - new ConfigAccount - { - username = "testuser2", - password = "testpassword2" + new ConfigAccount + { + username = "testuser1", + password = "testpassword1", + totpSecret = "TESTSECRET1" + }, + new ConfigAccount + { + username = "testuser2", + password = "testpassword2" + } } }; - - return config; } } } \ No newline at end of file diff --git a/Tests/Integration/ProxyIntegrationTests.cs b/Tests/Integration/ProxyIntegrationTests.cs index 257e686..7b7a487 100644 --- a/Tests/Integration/ProxyIntegrationTests.cs +++ b/Tests/Integration/ProxyIntegrationTests.cs @@ -52,11 +52,17 @@ namespace VRCAuthProxy.Tests.Integration .WithHeader("Content-Type", "application/json") .WithBody(@"[{""id"":""usr_test1"",""displayName"":""TestUser1""},{""id"":""usr_test2"",""displayName"":""TestUser2""}]")); - // Create a client - var httpClient = new HttpClient(); + // Create a client with the test setup + var handler = new HttpClientHandler { UseCookies = true }; + var mockServerUrls = mockServer.Urls; + if (mockServerUrls == null || !mockServerUrls.Any()) + { + throw new InvalidOperationException("Mock server URLs not available"); + } + var baseUri = mockServerUrls.First(); // Call the users endpoint directly - var baseUri = mockServer.Urls.First(); + var httpClient = new HttpClient(handler); var response = await httpClient.GetAsync($"{baseUri}/api/1/users"); // Assert @@ -90,11 +96,17 @@ namespace VRCAuthProxy.Tests.Integration .WithHeader("Content-Type", "application/json") .WithBody(@"[{""id"":""wrld_test1"",""name"":""TestWorld1""},{""id"":""wrld_test2"",""name"":""TestWorld2""}]")); - // Create a client - var httpClient = new HttpClient(); + // Create a client with the test setup + var handler = new HttpClientHandler { UseCookies = true }; + var mockServerUrls = mockServer.Urls; + if (mockServerUrls == null || !mockServerUrls.Any()) + { + throw new InvalidOperationException("Mock server URLs not available"); + } + var baseUri = mockServerUrls.First(); // First authenticate - var baseUri = mockServer.Urls.First(); + var httpClient = new HttpClient(handler); await httpClient.GetAsync($"{baseUri}/api/1/auth/user"); // Then call the worlds endpoint diff --git a/Tests/Integration/VRChatAuthenticationTests.cs b/Tests/Integration/VRChatAuthenticationTests.cs index 9b21096..3e65caf 100644 --- a/Tests/Integration/VRChatAuthenticationTests.cs +++ b/Tests/Integration/VRChatAuthenticationTests.cs @@ -38,9 +38,14 @@ namespace VRCAuthProxy.Tests.Integration // Create a client with the test setup var handler = new HttpClientHandler { UseCookies = true }; + var mockServerUrls = mockServer.Urls; + if (mockServerUrls == null || !mockServerUrls.Any()) + { + throw new InvalidOperationException("Mock server URLs not available"); + } var httpClient = new HttpClient(handler) { - BaseAddress = new Uri(mockServer.Urls.First()) + BaseAddress = new Uri(mockServerUrls.First()) }; // Act @@ -82,7 +87,7 @@ namespace VRCAuthProxy.Tests.Integration mockServer.Given(Request.Create() .WithPath("/api/1/auth/twofactorauth/totp/verify") .UsingPost() - .WithBody(x => x.Contains("code"))) + .WithBody(x => x != null && x.Contains("code"))) .RespondWith(Response.Create() .WithStatusCode(200) .WithHeader("Content-Type", "application/json") @@ -101,9 +106,14 @@ namespace VRCAuthProxy.Tests.Integration // Create a client with the test setup var handler = new HttpClientHandler { UseCookies = true }; + var mockServerUrls = mockServer.Urls; + if (mockServerUrls == null || !mockServerUrls.Any()) + { + throw new InvalidOperationException("Mock server URLs not available"); + } var httpClient = new HttpClient(handler) { - BaseAddress = new Uri(mockServer.Urls.First()) + BaseAddress = new Uri(mockServerUrls.First()) }; // Act - First authenticate which will indicate TOTP is required diff --git a/VRCAuthProxy/Config.cs b/VRCAuthProxy/Config.cs index d68abee..c7df150 100644 --- a/VRCAuthProxy/Config.cs +++ b/VRCAuthProxy/Config.cs @@ -4,21 +4,26 @@ namespace VRCAuthProxy; public class ConfigAccount { - public string username { get; set; } - public string password { get; set; } + public required string username { get; set; } + public required string password { get; set; } public string? totpSecret { get; set; } } public class iConfig { - public List accounts { get; set; } + public required List accounts { get; set; } } // Load config from appsettings.json public class Config { private static Config? _instance; - public List Accounts { get; set; } + public required List Accounts { get; set; } + + public Config() + { + Accounts = new List(); + } public static Config Instance { @@ -31,8 +36,12 @@ public class Config public static Config Load() { - var config = new Config(); var configPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); + var config = new Config + { + Accounts = new List() + }; + if (File.Exists(configPath)) { var json = File.ReadAllText(configPath); diff --git a/VRCAuthProxy/Program.cs b/VRCAuthProxy/Program.cs index 733026f..0e5af6e 100644 --- a/VRCAuthProxy/Program.cs +++ b/VRCAuthProxy/Program.cs @@ -155,7 +155,7 @@ app.Use(async (context, next) => var result = await source.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { - await target.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + await target.CloseAsync(result.CloseStatus ?? WebSocketCloseStatus.NormalClosure, result.CloseStatusDescription, CancellationToken.None); break; } await target.SendAsync(new ArraySegment(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);