From dfafc7463d47e366732c7862214e11ddca5beb05 Mon Sep 17 00:00:00 2001 From: Yelo420 Date: Wed, 6 Aug 2025 16:24:31 +0200 Subject: [PATCH 1/5] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bce46f1..f449d0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # GameVault App Changelog -##1.17.1 +## 1.17.1 Recommended Gamevault Server Version: `v15.0.2` ### Changes - User registration has also been added to the Admin Panel. From 1fd4493cfb037138ec6e1ddf71bd52a6fb52bef2 Mon Sep 17 00:00:00 2001 From: Yelo420 Date: Sun, 17 Aug 2025 07:53:51 +0200 Subject: [PATCH 2/5] =?UTF-8?q?Added=20authorization=20to=20the=20admin=20?= =?UTF-8?q?panel's=20registration=20action=20so=20administrators=20can=20r?= =?UTF-8?q?egister=20users=20even=20when=20server=E2=80=91side=20registrat?= =?UTF-8?q?ion=20is=20disabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamevault/AssemblyInfo.cs | 2 +- gamevault/Helper/LoginManager.cs | 14 +++++++++++--- .../RegistrationUserControl.xaml.cs | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gamevault/AssemblyInfo.cs b/gamevault/AssemblyInfo.cs index 525d34e..bfb06b5 100644 --- a/gamevault/AssemblyInfo.cs +++ b/gamevault/AssemblyInfo.cs @@ -11,7 +11,7 @@ //(used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )] -[assembly: AssemblyVersion("1.17.1.0")] +[assembly: AssemblyVersion("1.17.2.0")] [assembly: AssemblyCopyright("© Phalcode™. All Rights Reserved.")] #if DEBUG [assembly: XmlnsDefinition("debug-mode", "Namespace")] diff --git a/gamevault/Helper/LoginManager.cs b/gamevault/Helper/LoginManager.cs index 6aed09e..4f8995d 100644 --- a/gamevault/Helper/LoginManager.cs +++ b/gamevault/Helper/LoginManager.cs @@ -72,7 +72,7 @@ public string GetServerLoginResponseMessage() public void SwitchToOfflineMode() { MainWindowViewModel.Instance.OnlineState = System.Windows.Visibility.Visible; - m_User = null; + m_User = null; } public UserProfile GetUserProfile() { @@ -385,12 +385,20 @@ public void PhalcodeLogout() } - public async Task Register(LoginUser user) + public async Task Register(LoginUser user, bool useOAuth = false) { try { string userObject = JsonSerializer.Serialize(new User { Username = user.Username, Password = user.Password, EMail = user.EMail, FirstName = user.FirstName, LastName = user.LastName, BirthDate = user.BirthDate }); - string newUser = await WebHelper.BasePostAsync($"{user.ServerUrl}/api/auth/basic/register", userObject); + string newUser = ""; + if (useOAuth) + { + newUser = await WebHelper.PostAsync($"{user.ServerUrl}/api/auth/basic/register", userObject); + } + else + { + newUser = await WebHelper.BasePostAsync($"{user.ServerUrl}/api/auth/basic/register", userObject); + } User newUserObject = JsonSerializer.Deserialize(newUser); if (newUserObject!.Activated != true) { diff --git a/gamevault/UserControls/SettingsComponents/RegistrationUserControl.xaml.cs b/gamevault/UserControls/SettingsComponents/RegistrationUserControl.xaml.cs index 0f0ffeb..78637b2 100644 --- a/gamevault/UserControls/SettingsComponents/RegistrationUserControl.xaml.cs +++ b/gamevault/UserControls/SettingsComponents/RegistrationUserControl.xaml.cs @@ -107,11 +107,11 @@ private async void RegisterNewUser_Click(object sender, RoutedEventArgs e) try { ValidateSignUpData(); - LoginState state = await LoginManager.Instance.Register(ViewModel.SignupUser); + LoginState state = await LoginManager.Instance.Register(ViewModel.SignupUser, true); if (state != LoginState.Error) { MainWindowViewModel.Instance.ClosePopup(); - if(MainWindowViewModel.Instance.ActiveControl.GetType() == typeof(AdminConsoleUserControl)) + if (MainWindowViewModel.Instance.ActiveControl.GetType() == typeof(AdminConsoleUserControl)) { await MainWindowViewModel.Instance.AdminConsole.InitUserList(); } From 559805ec836bd5b56d83030ba99da17c4d2cdb41 Mon Sep 17 00:00:00 2001 From: Yelo420 Date: Tue, 19 Aug 2025 13:50:32 +0200 Subject: [PATCH 3/5] Extended the existing overwrite warning to allow users to continue the installation at their own risk. --- CHANGELOG.md | 6 ++++++ gamevault/UserControls/GameDownloadUserControl.xaml.cs | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f449d0d..e9bcfe7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # GameVault App Changelog +## 1.17.2 +Recommended Gamevault Server Version: `v15.0.2` +### Changes +- Added authorization to the admin panel’s registration action, allowing administrators to register users even when server-side registration is disabled. +- Extended the existing overwrite warning to allow users to continue the installation at their own risk. + ## 1.17.1 Recommended Gamevault Server Version: `v15.0.2` ### Changes diff --git a/gamevault/UserControls/GameDownloadUserControl.xaml.cs b/gamevault/UserControls/GameDownloadUserControl.xaml.cs index 7c8f9be..1a733fb 100644 --- a/gamevault/UserControls/GameDownloadUserControl.xaml.cs +++ b/gamevault/UserControls/GameDownloadUserControl.xaml.cs @@ -652,8 +652,12 @@ private async Task Install() { if (InstallViewModel.Instance.InstalledGames.Any(game => game.Key.ID == ViewModel.Game.ID)) { - await ((MetroWindow)App.Current.MainWindow).ShowMessageAsync($"The Game {ViewModel.Game.Title} is already installed at \n'{InstallViewModel.Instance.InstalledGames.First(game => game.Key.ID == ViewModel.Game.ID).Value}'", "", MessageDialogStyle.Affirmative, new MetroDialogSettings() { AffirmativeButtonText = "Ok", AnimateHide = false }); - return; + MessageDialogResult result = await ((MetroWindow)App.Current.MainWindow).ShowMessageAsync($"The Game {ViewModel.Game.Title} is already installed at \n'{InstallViewModel.Instance.InstalledGames.First(game => game.Key.ID == ViewModel.Game.ID).Value}'" + + $"\nWarning: Overwriting an existing installation with a new one may cause data corruption.", "", + MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings() { AffirmativeButtonText = "Continue", NegativeButtonText = "Cancel", AnimateHide = false }); + + if (result == MessageDialogResult.Negative) + return; } string targedDir = (SettingsViewModel.Instance.MountIso && Directory.Exists(mountedDrive)) ? mountedDrive : $"{m_DownloadPath}\\Extract"; From ae380294cbb0a554069d5db3996141cf0a599155 Mon Sep 17 00:00:00 2001 From: Yelo420 Date: Wed, 20 Aug 2025 13:54:36 +0200 Subject: [PATCH 4/5] Bug fix: OAuth access token expiration was not calculated correctly under certain circumstances. Added more skeleton loading controls to community tab Skeleton loading control animations are now paused if not needed anymore --- CHANGELOG.md | 4 +- gamevault/Helper/VisualHelper.cs | 21 +++++++++- gamevault/Helper/Web/OAuthHttpClient.cs | 29 ++++++++++---- .../UserControls/CommunityUserControl.xaml | 28 +++++++++++--- .../UserControls/CommunityUserControl.xaml.cs | 38 +++++++++++++++++-- 5 files changed, 100 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9bcfe7..5c512c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ Recommended Gamevault Server Version: `v15.0.2` ### Changes - Added authorization to the admin panel’s registration action, allowing administrators to register users even when server-side registration is disabled. -- Extended the existing overwrite warning to allow users to continue the installation at their own risk. +- Extended the existing installation overwrite warning to allow users to continue the installation at their own risk. +- Performance optimization in the community tab +- Bug fix: OAuth access token expiration was not calculated correctly under certain circumstances. ## 1.17.1 Recommended Gamevault Server Version: `v15.0.2` diff --git a/gamevault/Helper/VisualHelper.cs b/gamevault/Helper/VisualHelper.cs index 4e2e364..e53eae8 100644 --- a/gamevault/Helper/VisualHelper.cs +++ b/gamevault/Helper/VisualHelper.cs @@ -23,6 +23,25 @@ internal static T FindNextParentByType(DependencyObject child) while (parentDepObj != null); return default; } + internal static IEnumerable FindVisualChildren(DependencyObject depObj) where T : DependencyObject + { + if (depObj != null) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) + { + DependencyObject child = VisualTreeHelper.GetChild(depObj, i); + if (child is T t) + { + yield return t; + } + + foreach (T childOfChild in FindVisualChildren(child)) + { + yield return childOfChild; + } + } + } + } internal static void AdjustWindowChrome(MetroWindow window) { try @@ -47,7 +66,7 @@ internal static void HideWindow(Window window) internal static void RestoreHiddenWindow(Window window, int height, int width) { window.Width = width; - window.Height = height; + window.Height = height; window.ShowInTaskbar = true; double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth; double screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight; diff --git a/gamevault/Helper/Web/OAuthHttpClient.cs b/gamevault/Helper/Web/OAuthHttpClient.cs index 5342b4e..f4f8da9 100644 --- a/gamevault/Helper/Web/OAuthHttpClient.cs +++ b/gamevault/Helper/Web/OAuthHttpClient.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using System.Text.Json; using gamevault.Models; +using System.Diagnostics; namespace gamevault.Helper { @@ -66,7 +67,7 @@ private async Task SendAsync(HttpRequestMessage request, Re await LoginBasicAuthAsync(UserName, Password); } - if (IsTokenExpired(_accessToken) && !await RefreshTokenAsync()) + if (IsTokenExpired() && !await RefreshTokenAsync()) throw new InvalidOperationException("Failed to refresh token."); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken); @@ -106,20 +107,30 @@ private async Task RefreshTokenAsync() _accessToken = json?.AccessToken; _refreshToken = json?.RefreshToken; - + nextTokenRefresh = GetNextTokenRefresh(_accessToken); + //Debug.WriteLine($"Token refreshed. Next refresh at: {nextTokenRefresh}"); return true; } - - private bool IsTokenExpired(string token) + DateTimeOffset nextTokenRefresh; + private bool IsTokenExpired() + { + return nextTokenRefresh <= DateTimeOffset.UtcNow.AddMinutes(1); + } + private DateTimeOffset GetNextTokenRefresh(string token) { var parts = token.Split('.'); - if (parts.Length != 3) return true; + if (parts.Length != 3) return DateTimeOffset.UtcNow; var payload = parts[1]; var jsonBytes = Convert.FromBase64String(Base64UrlDecode(payload)); - - var json = JsonSerializer.Deserialize(Encoding.UTF8.GetString(jsonBytes)); - return json?.Exp == null || DateTimeOffset.FromUnixTimeSeconds(json.Exp) <= DateTimeOffset.UtcNow.AddMinutes(1); + var json = JsonSerializer.Deserialize(Encoding.UTF8.GetString(jsonBytes)); + if (json?.Exp == null) + { + return DateTimeOffset.UtcNow; + } + var expTimestamp = DateTimeOffset.FromUnixTimeSeconds(json.Exp); + var creationTimestamp = DateTimeOffset.FromUnixTimeSeconds(json.Creation); + return DateTimeOffset.UtcNow + (expTimestamp - creationTimestamp); } private string Base64UrlDecode(string input) @@ -140,6 +151,8 @@ public class AuthResponse public class JwtPayload { + [JsonPropertyName("iat")] + public long Creation { get; set; } [JsonPropertyName("exp")] public long Exp { get; set; } } diff --git a/gamevault/UserControls/CommunityUserControl.xaml b/gamevault/UserControls/CommunityUserControl.xaml index 1b24e85..5d9dfaa 100644 --- a/gamevault/UserControls/CommunityUserControl.xaml +++ b/gamevault/UserControls/CommunityUserControl.xaml @@ -67,7 +67,7 @@ - +