From b86b65fd661be86230c796d255d9904707b14d44 Mon Sep 17 00:00:00 2001 From: Cinka Date: Sun, 17 Aug 2025 21:02:45 +0300 Subject: [PATCH] - fix: profiles token refresh now --- .../ViewModels/Pages/AccountInfoViewModel.cs | 44 +++++++++++++------ .../ViewModels/Popup/PopupViewModelBase.cs | 3 ++ .../ViewModels/Popup/TfaViewModel.cs | 12 ++--- Nebula.Shared/Services/AuthService.cs | 13 ++++++ Nebula.Shared/Services/RestService.cs | 28 ++++++------ Nebula.Shared/Utils/ExceptionHelper.cs | 19 ++++++++ 6 files changed, 86 insertions(+), 33 deletions(-) create mode 100644 Nebula.Shared/Utils/ExceptionHelper.cs diff --git a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs index fee8a5a..745ab1a 100644 --- a/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs +++ b/Nebula.Launcher/ViewModels/Pages/AccountInfoViewModel.cs @@ -62,6 +62,7 @@ public partial class AccountInfoViewModel : ViewModelBase _logger = DebugService.GetLogger(this); Credentials = new AuthTokenCredentialsVar(this); Task.Run(ReadAuthConfig); + Credentials.Value = Credentials.Value; } public void DoAuth(string? code = null) @@ -81,13 +82,15 @@ public partial class AccountInfoViewModel : ViewModelBase Task.Run(async () => { Exception? exception = null; - AuthTokenCredentials? credentials = null; foreach (var server in serverCandidates) { try { - credentials = await AuthService.Auth(CurrentLogin, CurrentPassword, server, code); + await CatchAuthError(async() => + { + Credentials.Value = await AuthService.Auth(CurrentLogin, CurrentPassword, server, code); + }, ()=> message.Dispose()); break; } catch (Exception ex) @@ -98,13 +101,10 @@ public partial class AccountInfoViewModel : ViewModelBase message.Dispose(); - if (credentials is null) + if (exception != null) { - PopupMessageService.Popup(exception ?? new Exception(LocalisationService.GetString("auth-error"))); - return; + PopupMessageService.Popup(new Exception("Error while auth", exception)); } - - Credentials.Value = credentials; }); } @@ -124,7 +124,6 @@ public partial class AccountInfoViewModel : ViewModelBase case AuthenticateDenyCode.TfaRequired: case AuthenticateDenyCode.TfaInvalid: var p = ViewHelperService.GetViewModel(); - p.OnTfaEntered += OnTfaEntered; PopupMessageService.Popup(p); _logger.Log("TFA required"); break; @@ -242,7 +241,7 @@ public partial class AccountInfoViewModel : ViewModelBase Accounts.Add(alpm); } - private async void ReadAuthConfig() + private async Task ReadAuthConfig() { var message = ViewHelperService.GetViewModel(); message.InfoText = LocalisationService.GetString("auth-config-read"); @@ -290,20 +289,27 @@ public partial class AccountInfoViewModel : ViewModelBase { if(authTokenCredentials is null) return null; + + var daysLeft = (int)(authTokenCredentials.Token.ExpireTime - DateTime.Now).TotalDays; - if (authTokenCredentials.Token.ExpireTime < DateTime.Now.AddDays(2)) + if(daysLeft >= 4) + { + _logger.Log("Token " + authTokenCredentials.Login + " is active, "+daysLeft+" days left, undo renewing!"); return authTokenCredentials; + } try { _logger.Log($"Renewing token for {authTokenCredentials.Login}"); - return await AuthService.Refresh(authTokenCredentials); + return await ExceptionHelper.TryRun(() => AuthService.Refresh(authTokenCredentials),3, (attempt, e) => + { + _logger.Error(new Exception("Error while renewing, attempts: " + attempt, e)); + }); } catch (Exception e) { var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), e); _logger.Error(unexpectedError); - //PopupMessageService.Popup(unexpectedError); return authTokenCredentials; } } @@ -376,7 +382,19 @@ public partial class AccountInfoViewModel : ViewModelBase var errorRun = false; - //currProfile = await CheckOrRenewToken(currProfile); + currProfile = await accountInfoViewModel.CheckOrRenewToken(currProfile); + + if (currProfile is null) + { + message.Dispose(); + + accountInfoViewModel._logger.Log("profile credentials update required!"); + + accountInfoViewModel.PopupMessageService.Popup("profile credentials update required!"); + + accountInfoViewModel.IsLogged = false; + return null; + } try { diff --git a/Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs b/Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs index d9d6a62..cab3ed2 100644 --- a/Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs +++ b/Nebula.Launcher/ViewModels/Popup/PopupViewModelBase.cs @@ -12,6 +12,9 @@ public abstract class PopupViewModelBase : ViewModelBase, IDisposable public void Dispose() { + OnDispose(); PopupMessageService.ClosePopup(this); } + + protected virtual void OnDispose(){} } \ No newline at end of file diff --git a/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs b/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs index 58d5162..6cd1aba 100644 --- a/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs +++ b/Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs @@ -1,5 +1,6 @@ using System; using Nebula.Launcher.Services; +using Nebula.Launcher.ViewModels.Pages; using Nebula.Launcher.Views.Popup; using Nebula.Shared.Services; using Nebula.Shared.ViewHelper; @@ -9,7 +10,10 @@ namespace Nebula.Launcher.ViewModels.Popup; [ConstructGenerator, ViewModelRegister(typeof(TfaView))] public partial class TfaViewModel : PopupViewModelBase { - public Action? OnTfaEntered; + [GenerateProperty] public override PopupMessageService PopupMessageService { get; } + [GenerateProperty] public AccountInfoViewModel AccountInfo { get; } + public override string Title => LocalisationService.GetString("popup-twofa"); + public override bool IsClosable => true; protected override void InitialiseInDesignMode() { @@ -21,11 +25,7 @@ public partial class TfaViewModel : PopupViewModelBase public void OnTfaEnter(string code) { - OnTfaEntered?.Invoke(code); + AccountInfo.DoAuth(code); Dispose(); } - - [GenerateProperty] public override PopupMessageService PopupMessageService { get; } - public override string Title => LocalisationService.GetString("popup-twofa"); - public override bool IsClosable => true; } \ No newline at end of file diff --git a/Nebula.Shared/Services/AuthService.cs b/Nebula.Shared/Services/AuthService.cs index fef64c6..e4bb345 100644 --- a/Nebula.Shared/Services/AuthService.cs +++ b/Nebula.Shared/Services/AuthService.cs @@ -74,6 +74,19 @@ public sealed record AuthDenyError(string[] Errors, AuthenticateDenyCode Code); public sealed class AuthException(AuthDenyError error) : Exception { public AuthDenyError Error { get; } = error; + + public override string Message + { + get + { + var str = "Error while logging in. Please try again. " + Error.Code; + foreach (var error in Error.Errors) + { + str += "\n" + error; + } + return str; + } + } } [JsonConverter(typeof(JsonStringEnumConverter))] diff --git a/Nebula.Shared/Services/RestService.cs b/Nebula.Shared/Services/RestService.cs index 2f36b53..c74673b 100644 --- a/Nebula.Shared/Services/RestService.cs +++ b/Nebula.Shared/Services/RestService.cs @@ -32,20 +32,6 @@ public class RestService var response = await _client.GetAsync(uri, cancellationToken); return await ReadResult(response, cancellationToken, uri); } - - [Pure] - public async Task GetAsyncDefault(Uri uri, T defaultValue, CancellationToken cancellationToken) where T : notnull - { - try - { - return await GetAsync(uri, cancellationToken); - } - catch (Exception e) - { - _logger.Error(e); - return defaultValue; - } - } public async Task PostAsync(T information, Uri uri, CancellationToken cancellationToken) where K : notnull { @@ -71,6 +57,20 @@ public class RestService var response = await _client.DeleteAsync(uri, cancellationToken); return await ReadResult(response, cancellationToken, uri); } + + [Pure] + public async Task GetAsyncDefault(Uri uri, T defaultValue, CancellationToken cancellationToken) where T : notnull + { + try + { + return await GetAsync(uri, cancellationToken); + } + catch (Exception e) + { + _logger.Error(e); + return defaultValue; + } + } [Pure] private async Task ReadResult(HttpResponseMessage response, CancellationToken cancellationToken, Uri uri) where T : notnull diff --git a/Nebula.Shared/Utils/ExceptionHelper.cs b/Nebula.Shared/Utils/ExceptionHelper.cs new file mode 100644 index 0000000..fceb6a6 --- /dev/null +++ b/Nebula.Shared/Utils/ExceptionHelper.cs @@ -0,0 +1,19 @@ +namespace Nebula.Shared.Utils; + +public static class ExceptionHelper +{ + public static Task TryRun(Func> func, int attempts = 3, Action? attemptsCallback = null) + { + try + { + return func.Invoke(); + } + catch (Exception e) + { + if (attempts <= 0) throw new("Attempts was expired! ", e); + attempts--; + attemptsCallback?.Invoke(attempts, e); + return TryRun(func, attempts); + } + } +} \ No newline at end of file