From 89ca08f6cf03204b88b1e96e7365dd522d3767e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=B2=D0=B8=D0=B4=20=D0=A7=D0=B5=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D0=BE=D0=B2?= Date: Sun, 1 Sep 2024 02:51:35 +0300 Subject: [PATCH 1/3] Pre-release performance update. - Potentially fixed memory leak in code progress bar - Added using statement in SteamGuardCodeGenerator on disposable HMACSHA1 - Most of packages updated to the last version --- NebulaAuth/Core/DialogsController.cs | 1 - NebulaAuth/Model/Storage.cs | 1 - NebulaAuth/NebulaAuth.csproj | 16 +++++++-------- .../Dialogs/LoginAgainOnImportDialog.xaml.cs | 4 +--- NebulaAuth/View/UpdaterView.xaml.cs | 15 +------------- NebulaAuth/ViewModel/MainVM_Code.cs | 20 +++++++++++-------- NebulaAuth/ViewModel/MainVM_Groups.cs | 1 - NebulaAuth/ViewModel/Other/LinkAccountVM.cs | 2 -- .../ViewModel/Other/LoginAgainOnImportVM.cs | 1 - NebulaAuth/ViewModel/Other/LoginAgainVM.cs | 7 +------ NebulaAuth/ViewModel/Other/ProxyManagerVM.cs | 4 ++-- NebulaAuth/ViewModel/Other/UpdaterVM.cs | 1 - .../SteamMobile/SteamGuardCodeGenerator.cs | 6 ++---- SteamLibForked/SteamMobile/TimeAligner.cs | 4 +--- 14 files changed, 28 insertions(+), 55 deletions(-) diff --git a/NebulaAuth/Core/DialogsController.cs b/NebulaAuth/Core/DialogsController.cs index fb9e70d..f7047a7 100644 --- a/NebulaAuth/Core/DialogsController.cs +++ b/NebulaAuth/Core/DialogsController.cs @@ -5,7 +5,6 @@ using NebulaAuth.Model.Entities; using NebulaAuth.View; using NebulaAuth.View.Dialogs; using NebulaAuth.ViewModel.Other; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; namespace NebulaAuth.Core; diff --git a/NebulaAuth/Model/Storage.cs b/NebulaAuth/Model/Storage.cs index be74735..9cb90ba 100644 --- a/NebulaAuth/Model/Storage.cs +++ b/NebulaAuth/Model/Storage.cs @@ -9,7 +9,6 @@ using SteamLib.Utility.MaFiles; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.DirectoryServices.ActiveDirectory; using System.IO; using System.Linq; diff --git a/NebulaAuth/NebulaAuth.csproj b/NebulaAuth/NebulaAuth.csproj index ac148e1..6713f62 100644 --- a/NebulaAuth/NebulaAuth.csproj +++ b/NebulaAuth/NebulaAuth.csproj @@ -19,17 +19,17 @@ - - - - - + + + + + - - - + + + diff --git a/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs b/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs index 56b2ab0..ae1bdce 100644 --- a/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs +++ b/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs @@ -1,6 +1,4 @@ -using System.Windows.Controls; - -namespace NebulaAuth.View.Dialogs +namespace NebulaAuth.View.Dialogs { /// /// Логика взаимодействия для LoginAgainDialog.xaml diff --git a/NebulaAuth/View/UpdaterView.xaml.cs b/NebulaAuth/View/UpdaterView.xaml.cs index 04363ed..c77a531 100644 --- a/NebulaAuth/View/UpdaterView.xaml.cs +++ b/NebulaAuth/View/UpdaterView.xaml.cs @@ -1,17 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; +using System.Windows.Controls; namespace NebulaAuth.View { diff --git a/NebulaAuth/ViewModel/MainVM_Code.cs b/NebulaAuth/ViewModel/MainVM_Code.cs index 3496e9d..2e688db 100644 --- a/NebulaAuth/ViewModel/MainVM_Code.cs +++ b/NebulaAuth/ViewModel/MainVM_Code.cs @@ -1,8 +1,10 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using System; +using CommunityToolkit.Mvvm.ComponentModel; using SteamLib.SteamMobile; using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Windows; +using System.Windows.Threading; namespace NebulaAuth.ViewModel; @@ -14,30 +16,32 @@ public partial class MainVM [MemberNotNull(nameof(_codeTimer))] - [MemberNotNull(nameof(_code))] private void CreateCodeTimer() { - var currentTime = TimeAligner.GetSteamTime(); _codeTimer = new Timer(UpdateCode, null, 0, 1000); } + + private void UpdateCode(object? state = null) { var currentTime = TimeAligner.GetSteamTime(); var untilChange = currentTime - currentTime / 30L * 30L; var codeProgress = untilChange / 30D * 100; - + string? code = null; if (untilChange == 0 && SelectedMafile != null) { code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile!.SharedSecret); } - if(Application.Current == null) return; - Application.Current.Dispatcher.BeginInvoke(() => + + if (Application.Current == null) return; + Application.Current.Dispatcher.Invoke((string? c) => { + if (Application.Current.MainWindow?.WindowState == WindowState.Minimized) return; CodeProgress = codeProgress; - if (code != null) Code = code; - }); + if (c != null) Code = c; + }, DispatcherPriority.Background, code); } } \ No newline at end of file diff --git a/NebulaAuth/ViewModel/MainVM_Groups.cs b/NebulaAuth/ViewModel/MainVM_Groups.cs index 6b7b767..b5df780 100644 --- a/NebulaAuth/ViewModel/MainVM_Groups.cs +++ b/NebulaAuth/ViewModel/MainVM_Groups.cs @@ -5,7 +5,6 @@ using NebulaAuth.Model.Entities; using System; using System.Collections.ObjectModel; using System.Linq; -using System.Threading.Tasks; namespace NebulaAuth.ViewModel; diff --git a/NebulaAuth/ViewModel/Other/LinkAccountVM.cs b/NebulaAuth/ViewModel/Other/LinkAccountVM.cs index 190ff61..706e0b2 100644 --- a/NebulaAuth/ViewModel/Other/LinkAccountVM.cs +++ b/NebulaAuth/ViewModel/Other/LinkAccountVM.cs @@ -6,7 +6,6 @@ using MaterialDesignThemes.Wpf; using NebulaAuth.Model; using NebulaAuth.Model.Entities; using NebulaAuth.Utility; -using Newtonsoft.Json; using NLog; using SteamLib; using SteamLib.Account; @@ -26,7 +25,6 @@ using System.Net.Http; using System.Threading.Tasks; using System.Windows; using NebulaAuth.Core; -using SteamLib.Utility.MaFiles; namespace NebulaAuth.ViewModel.Other; diff --git a/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs b/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs index 860c16f..1263743 100644 --- a/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs +++ b/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs @@ -2,7 +2,6 @@ using NebulaAuth.Model.Entities; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Windows.Forms; using CommunityToolkit.Mvvm.Input; namespace NebulaAuth.ViewModel.Other; diff --git a/NebulaAuth/ViewModel/Other/LoginAgainVM.cs b/NebulaAuth/ViewModel/Other/LoginAgainVM.cs index 1135370..69fde2d 100644 --- a/NebulaAuth/ViewModel/Other/LoginAgainVM.cs +++ b/NebulaAuth/ViewModel/Other/LoginAgainVM.cs @@ -1,9 +1,4 @@ -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using CommunityToolkit.Mvvm.ComponentModel; -using NebulaAuth.Model; -using NebulaAuth.Model.Entities; +using CommunityToolkit.Mvvm.ComponentModel; namespace NebulaAuth.ViewModel.Other; diff --git a/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs b/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs index 14ff354..9be1d1f 100644 --- a/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs +++ b/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs @@ -21,7 +21,7 @@ public partial class ProxyManagerVM : ObservableObject [ObservableProperty] private KeyValuePair? _defaultProxy; public ObservableDictionary Proxies => ProxyStorage.Proxies; - private static readonly Regex IdRegex = new(@"\{(\d+)\}$"); + private static readonly Regex IdRegex = new(@"\{(\d+)\}$", RegexOptions.Compiled); public ProxyManagerVM() @@ -77,7 +77,7 @@ public partial class ProxyManagerVM : ObservableObject SnackbarController.SendSnackbar(string.Format(GetLocalizationOrDefault("DuplicateId"), id)); return; } - proxies.Add(new KeyValuePair(id, proxy)); + proxies.Add(KeyValuePair.Create(id, proxy)); } else { diff --git a/NebulaAuth/ViewModel/Other/UpdaterVM.cs b/NebulaAuth/ViewModel/Other/UpdaterVM.cs index 83fc9cd..715ce35 100644 --- a/NebulaAuth/ViewModel/Other/UpdaterVM.cs +++ b/NebulaAuth/ViewModel/Other/UpdaterVM.cs @@ -1,6 +1,5 @@ using AutoUpdaterDotNET; using CommunityToolkit.Mvvm.ComponentModel; -using Microsoft.VisualBasic.FileIO; namespace NebulaAuth.ViewModel.Other; diff --git a/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs b/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs index edd77b1..0f9b01e 100644 --- a/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs +++ b/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs @@ -44,10 +44,8 @@ public class SteamGuardCodeGenerator : ISteamGuardProvider time >>= 8; } - HMACSHA1 hmacGenerator = new() - { - Key = sharedSecret - }; + using HMACSHA1 hmacGenerator = new(); + hmacGenerator.Key = sharedSecret; var hashedData = hmacGenerator.ComputeHash(timeArray); var codeArray = new byte[5]; diff --git a/SteamLibForked/SteamMobile/TimeAligner.cs b/SteamLibForked/SteamMobile/TimeAligner.cs index cee4720..27007c2 100644 --- a/SteamLibForked/SteamMobile/TimeAligner.cs +++ b/SteamLibForked/SteamMobile/TimeAligner.cs @@ -46,9 +46,8 @@ public static class TimeAligner var req = new HttpRequestMessage(HttpMethod.Post, SteamConstants.STEAM_API + TIME_ALIGN_ENDPOINT); var response = client.Send(req).EnsureSuccessStatusCode(); sw.Stop(); - var stream = new StreamReader(response.Content.ReadAsStream()); + using var stream = new StreamReader(response.Content.ReadAsStream()); var respStr = stream.ReadToEnd(); - stream.Dispose(); var j = JObject.Parse(respStr); var time = j["response"]!["server_time"]!.Value(); var now = UtcNow - sw.Elapsed; @@ -80,7 +79,6 @@ public static class TimeAligner } finally { - sw.Stop(); client.Dispose(); } } From e6ae762d5ab7f8c906d484259b4e93d9742613b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=B2=D0=B8=D0=B4=20=D0=A7=D0=B5=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D0=BE=D0=B2?= Date: Sun, 15 Sep 2024 16:45:20 +0300 Subject: [PATCH 2/3] - Added splashscreen - Added Copy Login to Context Menu - UI and localization improvements --- NebulaAuth.sln | 1 + NebulaAuth/MainWindow.xaml | 11 +++- NebulaAuth/NebulaAuth.csproj | 8 ++- NebulaAuth/Theme/SplashScreen.png | Bin 0 -> 422890 bytes NebulaAuth/Theme/nebula lock.ico | Bin 218134 -> 0 bytes NebulaAuth/Theme/nebula.ico | Bin 128485 -> 0 bytes NebulaAuth/View/SettingsView.xaml | 2 +- NebulaAuth/ViewModel/MainVM_File.cs | 27 +++++++++ NebulaAuth/localization.loc.json | 29 +++++++--- changelog/1.5.2.html | 85 ++++++++++++++++++++++++++++ 10 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 NebulaAuth/Theme/SplashScreen.png delete mode 100644 NebulaAuth/Theme/nebula lock.ico delete mode 100644 NebulaAuth/Theme/nebula.ico create mode 100644 changelog/1.5.2.html diff --git a/NebulaAuth.sln b/NebulaAuth.sln index f755fa3..bb80a76 100644 --- a/NebulaAuth.sln +++ b/NebulaAuth.sln @@ -23,6 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "changelog", "changelog", "{ changelog\1.4.9.html = changelog\1.4.9.html changelog\1.5.0.html = changelog\1.5.0.html changelog\1.5.1.html = changelog\1.5.1.html + changelog\1.5.2.html = changelog\1.5.2.html EndProjectSection EndProject Global diff --git a/NebulaAuth/MainWindow.xaml b/NebulaAuth/MainWindow.xaml index 96f4bab..451a6ff 100644 --- a/NebulaAuth/MainWindow.xaml +++ b/NebulaAuth/MainWindow.xaml @@ -137,6 +137,7 @@ + + + + +
+ +
+
Version 1.5.2
+
DATE
+
+ - FIX: Potentially fixed problem with memory-leak on some devices (Windows 10, 11 Home/Professional)
+ - FIX: Small performance improvements
+ - UI: Added splash screen on application start
+ - UI: Added "Copy Login" in context menu of account on right-click.
+ - UI: Small localization update
+ - UI: Added tooltip to "Use Indicator" setting
+ - UI: Small design improvements
+ - UPDATE: most of the libraries were updated to the last version
+
+
+
+ + + \ No newline at end of file From 80d7c09b0d5ed35974efcf9a5d4f0b54bb99df07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=B2=D0=B8=D0=B4=20=D0=A7=D0=B5=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D0=BE=D0=B2?= Date: Wed, 18 Sep 2024 14:16:32 +0300 Subject: [PATCH 3/3] Prepared for 1.5.2 release HOTFIX: Resolved an issue introduced by the September 18, 2024, Steam update, where an error occurred during session refresh due to changes in Steam's response model. --- NebulaAuth/Core/UpdateManager.cs | 91 +++++++++----------- NebulaAuth/View/Dialogs/WaitLoginDialog.xaml | 1 - NebulaAuth/update.xml | 6 +- SteamLibForked/Api/SteamGlobalApi.cs | 43 ++++++++- changelog/1.5.2.html | 19 ++-- 5 files changed, 94 insertions(+), 66 deletions(-) diff --git a/NebulaAuth/Core/UpdateManager.cs b/NebulaAuth/Core/UpdateManager.cs index 784fbec..d93e794 100644 --- a/NebulaAuth/Core/UpdateManager.cs +++ b/NebulaAuth/Core/UpdateManager.cs @@ -1,14 +1,7 @@ using AutoUpdaterDotNET; -using MaterialDesignThemes.Wpf; using NebulaAuth.Model; -using NebulaAuth.View; -using NebulaAuth.ViewModel.Other; using System; using System.IO; -using System.Net; -using System.Windows.Forms; -using System.Windows.Threading; -using Application = System.Windows.Application; namespace NebulaAuth.Core; @@ -29,55 +22,55 @@ public static class UpdateManager } - static UpdateManager() - { - //AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent; + //static UpdateManager() + //{ + // //AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent; - } + //} - private static async void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) - { - if (args.Error == null) - { - if (args.IsUpdateAvailable) - { - DialogResult dialogResult; - var dialog = new UpdaterView() - { - DataContext = new UpdaterVM(args) - }; + //private static async void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) + //{ + // if (args.Error == null) + // { + // if (args.IsUpdateAvailable) + // { + // DialogResult dialogResult; + // var dialog = new UpdaterView() + // { + // DataContext = new UpdaterVM(args) + // }; - await DialogHost.Show(dialog); - Application.Current.Shutdown(); + // await DialogHost.Show(dialog); + // Application.Current.Shutdown(); - } - else - { + // } + // else + // { - } - } - else - { - if (args.Error is WebException) - { + // } + // } + // else + // { + // if (args.Error is WebException) + // { - } - else - { + // } + // else + // { - } - } + // } + // } - } + //} - private static void RunUpdate(UpdateInfoEventArgs args) - { - Application.Current.Dispatcher.Invoke(() => - { - if (AutoUpdater.DownloadUpdate(args)) - { - Application.Current.Shutdown(); - } - }, DispatcherPriority.ContextIdle); - } + //private static void RunUpdate(UpdateInfoEventArgs args) + //{ + // Application.Current.Dispatcher.Invoke(() => + // { + // if (AutoUpdater.DownloadUpdate(args)) + // { + // Application.Current.Shutdown(); + // } + // }, DispatcherPriority.ContextIdle); + //} } \ No newline at end of file diff --git a/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml b/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml index 6de5e85..41f263b 100644 --- a/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml +++ b/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml @@ -5,7 +5,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:theme="clr-namespace:NebulaAuth.Theme" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" theme:FontScaleWindow.ResizeFont="True" theme:FontScaleWindow.Scale="1" Foreground="WhiteSmoke" Background="{DynamicResource WindowBackground}"> diff --git a/NebulaAuth/update.xml b/NebulaAuth/update.xml index 0e9d39e..de7990a 100644 --- a/NebulaAuth/update.xml +++ b/NebulaAuth/update.xml @@ -1,8 +1,8 @@  - 1.5.1.0 - https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.1/NebulaAuth.1.5.1.zip - https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.1.html + 1.5.2.0 + https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.2/NebulaAuth.1.5.2.zip + https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.2.html false \ No newline at end of file diff --git a/SteamLibForked/Api/SteamGlobalApi.cs b/SteamLibForked/Api/SteamGlobalApi.cs index 39f9421..4c6b2e9 100644 --- a/SteamLibForked/Api/SteamGlobalApi.cs +++ b/SteamLibForked/Api/SteamGlobalApi.cs @@ -1,9 +1,12 @@ -using Newtonsoft.Json; +using AchiesUtilities.Models; +using AchiesUtilities.Newtonsoft.JSON.Converters.Special; +using Newtonsoft.Json; using SteamLib.Authentication; using SteamLib.Core; using SteamLib.Core.Enums; using SteamLib.Core.StatusCodes; using SteamLib.Exceptions; +using SteamLib.Exceptions.General; namespace SteamLib.Api; @@ -27,7 +30,17 @@ public static class SteamGlobalApi var cont = new FormUrlEncodedContent(data); var resp = await client.PostAsync("https://login.steampowered.com/jwt/ajaxrefresh", cont, cancellationToken); var respStr = await resp.EnsureSuccessStatusCode().Content.ReadAsStringAsync(cancellationToken); - var jwtRefresh = JsonConvert.DeserializeObject(respStr); + + JwtRefreshJson? jwtRefresh; + try + { + jwtRefresh = JsonConvert.DeserializeObject(respStr); + } + catch (Exception ex) + { + throw new UnsupportedResponseException(respStr, ex); + } + if (jwtRefresh?.Success != true) { Exception? inner = null; @@ -52,14 +65,26 @@ public static class SteamGlobalApi cont = new FormUrlEncodedContent(data); var update = await client.PostAsync(jwtRefresh.LoginUrl, cont, cancellationToken); var updateResp = await update.Content.ReadAsStringAsync(cancellationToken); - if (updateResp != "{\"result\":1}") + JwtUpdateJson result; + try + { + result = JsonConvert.DeserializeObject(updateResp) ?? throw new NullReferenceException(); + } + catch (Exception ex) + { + throw new UnsupportedResponseException(updateResp, ex); + } + + var resultStatus = SteamStatusCode.Translate(result.Result, out _); + if (resultStatus.Equals(SteamStatusCode.Ok) == false) { throw new SessionInvalidException( "AjaxRefresh (set-token) response was not successful. Response string stored in Exception.Data") { - Data = {{"Response", updateResp}} + Data = { { "Response", updateResp } } }; } + return SteamTokenHelper.ExtractJwtFromSetCookiesHeader(update.Headers); } @@ -74,5 +99,15 @@ public static class SteamGlobalApi [JsonProperty("auth")] public string Auth { get; set; } = string.Empty; [JsonProperty("error")] public int? Error { get; set; } } + + private class JwtUpdateJson + { + [JsonProperty("result")] + public int Result { get; set; } + + [JsonProperty("rtExpiry")] + [JsonConverter(typeof(UnixTimeStampConverter))] + public UnixTimeStamp RtExpiry { get; set; } + } } diff --git a/changelog/1.5.2.html b/changelog/1.5.2.html index 04ab1f6..613f9cc 100644 --- a/changelog/1.5.2.html +++ b/changelog/1.5.2.html @@ -67,16 +67,17 @@
Version 1.5.2
-
DATE
+
18.09.2024
- - FIX: Potentially fixed problem with memory-leak on some devices (Windows 10, 11 Home/Professional)
- - FIX: Small performance improvements
- - UI: Added splash screen on application start
- - UI: Added "Copy Login" in context menu of account on right-click.
- - UI: Small localization update
- - UI: Added tooltip to "Use Indicator" setting
- - UI: Small design improvements
- - UPDATE: most of the libraries were updated to the last version
+ - HOTFIX: Resolved an issue introduced by the September 18, 2024, Steam update, where an error occurred during session refresh due to changes in Steam's response model.
+ - FIX: Potentially resolved a memory leak issue on some devices (Windows 10, 11 Home/Professional).
+ - FIX: Minor performance improvements.
+ - UI: Added a splash screen on application startup.
+ - UI: Added "Copy Login" option in the account context menu on right-click.
+ - UI: Minor localization updates.
+ - UI: Added a tooltip to the "Use Indicator" setting.
+ - UI: Minor design improvements.
+ - UPDATE: Most libraries have been updated to their latest versions.