From 65e87071465f47efeeedbe285760fba083a24c6b Mon Sep 17 00:00:00 2001 From: Loporrit <141286461+loporrit@users.noreply.github.com> Date: Fri, 8 Aug 2025 02:48:49 +0000 Subject: [PATCH] Generate secret keys locally --- MareAPI | 2 +- MareSynchronos/Plugin.cs | 1 + MareSynchronos/UI/IntroUI.cs | 15 +--- MareSynchronos/UI/SettingsUi.cs | 17 ++-- .../WebAPI/AccountRegistrationService.cs | 84 +++++++++++++++++++ 5 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 MareSynchronos/WebAPI/AccountRegistrationService.cs diff --git a/MareAPI b/MareAPI index 8b77956..b2f4453 160000 --- a/MareAPI +++ b/MareAPI @@ -1 +1 @@ -Subproject commit 8b77956ec8620eb96f9f12b72182e0a6c70b23d1 +Subproject commit b2f4453b79a67d28dd5048ab3e7e84241663ab5a diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 56cfc7e..30a4438 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -108,6 +108,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 4644578..8d686ac 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -29,6 +29,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase private readonly CacheMonitor _cacheMonitor; private readonly ServerConfigurationManager _serverConfigurationManager; private readonly DalamudUtilService _dalamudUtilService; + private readonly AccountRegistrationService _registerService; private readonly UiSharedService _uiShared; private bool _readFirstPage; @@ -42,13 +43,14 @@ public partial class IntroUi : WindowMediatorSubscriberBase public IntroUi(ILogger logger, UiSharedService uiShared, MareConfigService configService, CacheMonitor fileCacheManager, ServerConfigurationManager serverConfigurationManager, MareMediator mareMediator, - PerformanceCollectorService performanceCollectorService, DalamudUtilService dalamudUtilService) : base(logger, mareMediator, "Loporrit Setup", performanceCollectorService) + PerformanceCollectorService performanceCollectorService, DalamudUtilService dalamudUtilService, AccountRegistrationService registerService) : base(logger, mareMediator, "Loporrit Setup", performanceCollectorService) { _uiShared = uiShared; _configService = configService; _cacheMonitor = fileCacheManager; _serverConfigurationManager = serverConfigurationManager; _dalamudUtilService = dalamudUtilService; + _registerService = registerService; IsOpen = false; ShowCloseButton = false; RespectCloseHotkey = false; @@ -261,16 +263,7 @@ This service is provided as-is. _ = Task.Run(async () => { try { - using HttpClient httpClient = new(); - var ver = Assembly.GetExecutingAssembly().GetName().Version; - httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MareSynchronos", ver!.Major + "." + ver!.Minor + "." + ver!.Build)); - var postUri = MareAuth.AuthRegisterFullPath(new Uri(_serverConfigurationManager.CurrentRealApiUrl - .Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase) - .Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase))); - _logger.LogInformation("Registering new account: {uri}", postUri.ToString()); - var result = await httpClient.PostAsync(postUri, null).ConfigureAwait(false); - result.EnsureSuccessStatusCode(); - var reply = await result.Content.ReadFromJsonAsync().ConfigureAwait(false) ?? new(); + var reply = await _registerService.RegisterAccount(CancellationToken.None).ConfigureAwait(false); if (!reply.Success) { _logger.LogWarning("Registration failed: {err}", reply.ErrorMessage); diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index f4978e1..f0a884c 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -50,9 +50,10 @@ public class SettingsUi : WindowMediatorSubscriberBase private readonly ChatService _chatService; private readonly GuiHookService _guiHookService; private readonly PerformanceCollectorService _performanceCollector; - private readonly ServerConfigurationManager _serverConfigurationManager; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly PlayerPerformanceService _playerPerformanceService; + private readonly AccountRegistrationService _registerService; + private readonly ServerConfigurationManager _serverConfigurationManager; private readonly UiSharedService _uiShared; private bool _deleteAccountPopupModalShown = false; private string _lastTab = string.Empty; @@ -80,7 +81,7 @@ public class SettingsUi : WindowMediatorSubscriberBase FileCacheManager fileCacheManager, FileCompactor fileCompactor, ApiController apiController, IpcManager ipcManager, IpcProvider ipcProvider, CacheMonitor cacheMonitor, - DalamudUtilService dalamudUtilService) : base(logger, mediator, "Loporrit Settings", performanceCollector) + DalamudUtilService dalamudUtilService, AccountRegistrationService registerService) : base(logger, mediator, "Loporrit Settings", performanceCollector) { _configService = configService; _pairManager = pairManager; @@ -98,6 +99,7 @@ public class SettingsUi : WindowMediatorSubscriberBase _ipcProvider = ipcProvider; _cacheMonitor = cacheMonitor; _dalamudUtilService = dalamudUtilService; + _registerService = registerService; _fileCompactor = fileCompactor; _uiShared = uiShared; AllowClickthrough = false; @@ -1753,16 +1755,7 @@ public class SettingsUi : WindowMediatorSubscriberBase _ = Task.Run(async () => { try { - using HttpClient httpClient = new(); - var ver = Assembly.GetExecutingAssembly().GetName().Version; - httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MareSynchronos", ver!.Major + "." + ver!.Minor + "." + ver!.Build)); - var postUri = MareAuth.AuthRegisterFullPath(new Uri(selectedServer.ServerUri - .Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase) - .Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase))); - _logger.LogInformation("Registering new account: {uri}", postUri.ToString()); - var result = await httpClient.PostAsync(postUri, null).ConfigureAwait(false); - result.EnsureSuccessStatusCode(); - var reply = await result.Content.ReadFromJsonAsync().ConfigureAwait(false) ?? new(); + var reply = await _registerService.RegisterAccount(CancellationToken.None).ConfigureAwait(false); if (!reply.Success) { _logger.LogWarning("Registration failed: {err}", reply.ErrorMessage); diff --git a/MareSynchronos/WebAPI/AccountRegistrationService.cs b/MareSynchronos/WebAPI/AccountRegistrationService.cs new file mode 100644 index 0000000..b36e73c --- /dev/null +++ b/MareSynchronos/WebAPI/AccountRegistrationService.cs @@ -0,0 +1,84 @@ +using MareSynchronos.API.Dto.Account; +using MareSynchronos.API.Routes; +using MareSynchronos.Services; +using MareSynchronos.Services.ServerConfiguration; +using MareSynchronos.Utils; +using MareSynchronos.WebAPI.SignalR; +using Microsoft.Extensions.Logging; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Reflection; +using System.Security.Cryptography; + +namespace MareSynchronos.WebAPI; + +public sealed class AccountRegistrationService : IDisposable +{ + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + private readonly ServerConfigurationManager _serverManager; + private readonly RemoteConfigurationService _remoteConfig; + + private string GenerateSecretKey() + { + return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64))); + } + + public AccountRegistrationService(ILogger logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig) + { + _logger = logger; + _serverManager = serverManager; + _remoteConfig = remoteConfig; + _httpClient = new( + new HttpClientHandler + { + AllowAutoRedirect = true, + MaxAutomaticRedirections = 5 + } + ); + var ver = Assembly.GetExecutingAssembly().GetName().Version; + _httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MareSynchronos", ver!.Major + "." + ver!.Minor + "." + ver!.Build)); + } + + public void Dispose() + { + _httpClient.Dispose(); + } + + public async Task RegisterAccount(CancellationToken token) + { + var authApiUrl = _serverManager.CurrentApiUrl; + + // Override the API URL used for auth from remote config, if one is available + if (authApiUrl.Equals(ApiController.LoporritServiceUri, StringComparison.Ordinal)) + { + var config = await _remoteConfig.GetConfigAsync("mainServer").ConfigureAwait(false) ?? new(); + if (!string.IsNullOrEmpty(config.ApiUrl)) + authApiUrl = config.ApiUrl; + else + authApiUrl = ApiController.LoporritServiceApiUri; + } + + var secretKey = GenerateSecretKey(); + var hashedSecretKey = secretKey.GetHash256(); + + Uri postUri = MareAuth.AuthRegisterV2FullPath(new Uri(authApiUrl + .Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase) + .Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase))); + + var result = await _httpClient.PostAsync(postUri, new FormUrlEncodedContent([ + new("hashedSecretKey", hashedSecretKey) + ]), token).ConfigureAwait(false); + result.EnsureSuccessStatusCode(); + + var response = await result.Content.ReadFromJsonAsync(token).ConfigureAwait(false) ?? new(); + + return new RegisterReplyDto() + { + Success = response.Success, + ErrorMessage = response.ErrorMessage, + UID = response.UID, + SecretKey = secretKey + }; + } +} \ No newline at end of file