2025-01-27 15:55:30 +03:00
|
|
|
using System;
|
2025-05-03 18:20:24 +03:00
|
|
|
using System.Collections.Generic;
|
2024-12-22 21:38:19 +03:00
|
|
|
using System.Collections.ObjectModel;
|
2024-12-27 08:22:17 +03:00
|
|
|
using System.Linq;
|
2025-06-20 16:27:42 +03:00
|
|
|
using System.Net.Http;
|
2025-01-27 15:55:30 +03:00
|
|
|
using System.Threading.Tasks;
|
2024-12-22 21:38:19 +03:00
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
2025-07-02 21:32:51 +03:00
|
|
|
using Nebula.Launcher.Models.Auth;
|
2025-01-14 22:10:16 +03:00
|
|
|
using Nebula.Launcher.Services;
|
|
|
|
|
using Nebula.Launcher.ViewModels.Popup;
|
2024-12-21 13:11:30 +03:00
|
|
|
using Nebula.Launcher.Views.Pages;
|
2025-01-05 17:05:23 +03:00
|
|
|
using Nebula.Shared.Services;
|
2025-05-05 22:01:59 +03:00
|
|
|
using Nebula.Shared.Services.Logging;
|
2025-01-05 17:05:23 +03:00
|
|
|
using Nebula.Shared.Utils;
|
2025-07-02 21:32:51 +03:00
|
|
|
using Nebula.Shared.ViewHelper;
|
2024-12-21 13:11:30 +03:00
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
namespace Nebula.Launcher.ViewModels.Pages;
|
2024-12-21 13:11:30 +03:00
|
|
|
|
2025-01-05 17:05:23 +03:00
|
|
|
[ViewModelRegister(typeof(AccountInfoView))]
|
2025-01-14 22:10:16 +03:00
|
|
|
[ConstructGenerator]
|
2025-06-14 22:33:03 +03:00
|
|
|
public partial class AccountInfoViewModel : ViewModelBase
|
2024-12-21 13:11:30 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
[ObservableProperty] private bool _authMenuExpand;
|
2024-12-22 21:38:19 +03:00
|
|
|
|
2024-12-27 19:15:33 +03:00
|
|
|
[ObservableProperty] private bool _authUrlConfigExpand;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty] private int _authViewSpan = 1;
|
|
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
[ObservableProperty] private string _currentAuthServer = string.Empty;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty] private string _currentLogin = string.Empty;
|
|
|
|
|
|
|
|
|
|
[ObservableProperty] private string _currentPassword = string.Empty;
|
2024-12-27 08:22:17 +03:00
|
|
|
|
2024-12-27 19:15:33 +03:00
|
|
|
[ObservableProperty] private bool _isLogged;
|
2025-06-20 16:27:42 +03:00
|
|
|
[ObservableProperty] private bool _doRetryAuth;
|
2024-12-22 21:38:19 +03:00
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
private bool _isProfilesEmpty;
|
2025-06-23 16:39:30 +03:00
|
|
|
[GenerateProperty] private LocalisationService LocalisationService { get; }
|
2025-01-14 22:10:16 +03:00
|
|
|
[GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!;
|
|
|
|
|
[GenerateProperty] private ConfigurationService ConfigurationService { get; } = default!;
|
2025-05-05 22:01:59 +03:00
|
|
|
[GenerateProperty] private DebugService DebugService { get; }
|
2025-01-14 22:10:16 +03:00
|
|
|
[GenerateProperty] private AuthService AuthService { get; } = default!;
|
2025-01-22 21:06:05 +03:00
|
|
|
[GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
public ObservableCollection<ProfileAuthCredentials> Accounts { get; } = new();
|
2025-05-03 18:20:24 +03:00
|
|
|
public ObservableCollection<AuthServerCredentials> AuthUrls { get; } = new();
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-05-03 18:20:24 +03:00
|
|
|
[ObservableProperty] private AuthServerCredentials _authItemSelect;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-05-05 22:01:59 +03:00
|
|
|
private ILogger _logger;
|
|
|
|
|
|
2024-12-22 21:38:19 +03:00
|
|
|
//Design think
|
2025-01-14 22:10:16 +03:00
|
|
|
protected override void InitialiseInDesignMode()
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
2025-03-12 14:51:47 +03:00
|
|
|
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
|
|
|
|
|
2025-05-03 18:20:24 +03:00
|
|
|
AuthUrls.Add(new AuthServerCredentials("Test",["example.com"]));
|
2024-12-22 21:38:19 +03:00
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2024-12-22 21:38:19 +03:00
|
|
|
//Real think
|
2025-01-14 22:10:16 +03:00
|
|
|
protected override void Initialise()
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-05-05 22:01:59 +03:00
|
|
|
_logger = DebugService.GetLogger(this);
|
2025-06-20 16:27:42 +03:00
|
|
|
Task.Run(ReadAuthConfig);
|
2024-12-22 21:38:19 +03:00
|
|
|
}
|
|
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
public void AuthByProfile(ProfileAuthCredentials credentials)
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-05-03 18:20:24 +03:00
|
|
|
CurrentLogin = credentials.Login;
|
|
|
|
|
CurrentPassword = credentials.Password;
|
|
|
|
|
CurrentAuthServer = credentials.AuthServer;
|
|
|
|
|
|
2024-12-22 21:38:19 +03:00
|
|
|
DoAuth();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
public void DoAuth(string? code = null)
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-01-14 22:10:16 +03:00
|
|
|
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
2025-06-23 16:39:30 +03:00
|
|
|
message.InfoText = LocalisationService.GetString("auth-processing");
|
2025-01-27 15:55:30 +03:00
|
|
|
message.IsInfoClosable = false;
|
2025-01-14 22:10:16 +03:00
|
|
|
PopupMessageService.Popup(message);
|
|
|
|
|
|
2025-05-03 18:20:24 +03:00
|
|
|
var serverCandidates = new List<string>();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(CurrentAuthServer))
|
|
|
|
|
serverCandidates.AddRange(AuthItemSelect.Servers);
|
|
|
|
|
else
|
|
|
|
|
serverCandidates.Add(CurrentAuthServer);
|
|
|
|
|
|
2025-01-27 15:55:30 +03:00
|
|
|
Task.Run(async () =>
|
2024-12-27 08:22:17 +03:00
|
|
|
{
|
2025-05-03 18:20:24 +03:00
|
|
|
Exception? exception = null;
|
|
|
|
|
foreach (var server in serverCandidates)
|
2025-02-01 18:19:18 +03:00
|
|
|
{
|
2025-05-03 18:20:24 +03:00
|
|
|
try
|
2025-02-01 18:19:18 +03:00
|
|
|
{
|
2025-06-20 16:27:42 +03:00
|
|
|
await CatchAuthError(async () => await TryAuth(CurrentLogin, CurrentPassword, server, code), ()=> message.Dispose());
|
2025-05-03 18:20:24 +03:00
|
|
|
break;
|
|
|
|
|
}
|
2025-06-20 16:27:42 +03:00
|
|
|
catch (Exception ex)
|
2025-05-03 18:20:24 +03:00
|
|
|
{
|
2025-06-23 16:39:30 +03:00
|
|
|
var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), ex);
|
2025-06-20 16:27:42 +03:00
|
|
|
_logger.Error(unexpectedError);
|
|
|
|
|
PopupMessageService.Popup(unexpectedError);
|
2025-02-01 18:19:18 +03:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-03 18:20:24 +03:00
|
|
|
|
|
|
|
|
message.Dispose();
|
|
|
|
|
|
|
|
|
|
if (!IsLogged)
|
2025-01-27 15:55:30 +03:00
|
|
|
{
|
2025-06-23 16:39:30 +03:00
|
|
|
PopupMessageService.Popup(exception ?? new Exception(LocalisationService.GetString("auth-error")));
|
2025-01-27 15:55:30 +03:00
|
|
|
}
|
|
|
|
|
});
|
2024-12-27 19:15:33 +03:00
|
|
|
}
|
|
|
|
|
|
2025-06-20 16:27:42 +03:00
|
|
|
private async Task TryAuth(CurrentAuthInfo currentAuthInfo)
|
2025-05-03 18:20:24 +03:00
|
|
|
{
|
2025-06-20 16:27:42 +03:00
|
|
|
CurrentLogin = currentAuthInfo.Login;
|
|
|
|
|
CurrentAuthServer = currentAuthInfo.AuthServer;
|
|
|
|
|
await AuthService.SetAuth(currentAuthInfo);
|
|
|
|
|
IsLogged = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task TryAuth(string login, string password, string authServer, string? code)
|
|
|
|
|
{
|
|
|
|
|
await AuthService.Auth(new AuthLoginPassword(login, password, authServer), code);
|
|
|
|
|
CurrentLogin = login;
|
|
|
|
|
CurrentPassword = password;
|
|
|
|
|
CurrentAuthServer = authServer;
|
|
|
|
|
IsLogged = true;
|
|
|
|
|
ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task CatchAuthError(Func<Task> a, Action? onError)
|
|
|
|
|
{
|
|
|
|
|
DoRetryAuth = false;
|
|
|
|
|
|
2025-05-03 18:20:24 +03:00
|
|
|
try
|
|
|
|
|
{
|
2025-06-20 16:27:42 +03:00
|
|
|
await a();
|
2025-05-03 18:20:24 +03:00
|
|
|
}
|
|
|
|
|
catch (AuthException e)
|
|
|
|
|
{
|
2025-06-20 16:27:42 +03:00
|
|
|
onError?.Invoke();
|
2025-05-03 18:20:24 +03:00
|
|
|
switch (e.Error.Code)
|
|
|
|
|
{
|
|
|
|
|
case AuthenticateDenyCode.TfaRequired:
|
|
|
|
|
case AuthenticateDenyCode.TfaInvalid:
|
|
|
|
|
var p = ViewHelperService.GetViewModel<TfaViewModel>();
|
|
|
|
|
p.OnTfaEntered += OnTfaEntered;
|
|
|
|
|
PopupMessageService.Popup(p);
|
2025-05-05 22:01:59 +03:00
|
|
|
_logger.Log("TFA required");
|
2025-05-03 18:20:24 +03:00
|
|
|
break;
|
|
|
|
|
case AuthenticateDenyCode.InvalidCredentials:
|
2025-06-23 16:39:30 +03:00
|
|
|
PopupError(LocalisationService.GetString("auth-invalid-credentials"), e);
|
2025-05-03 18:20:24 +03:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-20 16:27:42 +03:00
|
|
|
catch (HttpRequestException e)
|
|
|
|
|
{
|
|
|
|
|
onError?.Invoke();
|
|
|
|
|
switch (e.HttpRequestError)
|
|
|
|
|
{
|
|
|
|
|
case HttpRequestError.ConnectionError:
|
2025-06-23 16:39:30 +03:00
|
|
|
PopupError(LocalisationService.GetString("auth-connection-error"), e);
|
2025-06-20 16:27:42 +03:00
|
|
|
DoRetryAuth = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case HttpRequestError.NameResolutionError:
|
2025-06-23 16:39:30 +03:00
|
|
|
PopupError(LocalisationService.GetString("auth-name-resolution-error"), e);
|
2025-06-20 16:27:42 +03:00
|
|
|
DoRetryAuth = true;
|
|
|
|
|
break;
|
2025-06-23 19:48:11 +03:00
|
|
|
|
|
|
|
|
case HttpRequestError.SecureConnectionError:
|
|
|
|
|
PopupError(LocalisationService.GetString("auth-secure-error"), e);
|
|
|
|
|
DoRetryAuth = true;
|
|
|
|
|
break;
|
2025-06-20 16:27:42 +03:00
|
|
|
|
|
|
|
|
default:
|
2025-06-23 16:39:30 +03:00
|
|
|
var authError = new Exception(LocalisationService.GetString("auth-error"), e);
|
2025-06-20 16:27:42 +03:00
|
|
|
_logger.Error(authError);
|
|
|
|
|
PopupMessageService.Popup(authError);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-03 18:20:24 +03:00
|
|
|
}
|
|
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
private void OnTfaEntered(string code)
|
|
|
|
|
{
|
|
|
|
|
DoAuth(code);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-27 19:15:33 +03:00
|
|
|
public void Logout()
|
|
|
|
|
{
|
|
|
|
|
IsLogged = false;
|
2025-01-14 22:10:16 +03:00
|
|
|
AuthService.ClearAuth();
|
2024-12-27 19:15:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateAuthMenu()
|
|
|
|
|
{
|
|
|
|
|
if (AuthMenuExpand || _isProfilesEmpty)
|
|
|
|
|
AuthViewSpan = 2;
|
|
|
|
|
else
|
|
|
|
|
AuthViewSpan = 1;
|
2024-12-22 21:38:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddAccount(AuthLoginPassword authLoginPassword)
|
|
|
|
|
{
|
2025-02-01 18:19:18 +03:00
|
|
|
var onDelete = new DelegateCommand<ProfileAuthCredentials>(OnDeleteProfile);
|
|
|
|
|
var onSelect = new DelegateCommand<ProfileAuthCredentials>(AuthByProfile);
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
var alpm = new ProfileAuthCredentials(
|
2025-01-14 22:10:16 +03:00
|
|
|
authLoginPassword.Login,
|
2024-12-22 21:38:19 +03:00
|
|
|
authLoginPassword.Password,
|
2025-01-14 22:10:16 +03:00
|
|
|
authLoginPassword.AuthServer,
|
|
|
|
|
onSelect,
|
2024-12-22 21:38:19 +03:00
|
|
|
onDelete);
|
|
|
|
|
|
|
|
|
|
onDelete.TRef.Value = alpm;
|
|
|
|
|
onSelect.TRef.Value = alpm;
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2024-12-22 21:38:19 +03:00
|
|
|
Accounts.Add(alpm);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-23 16:39:30 +03:00
|
|
|
private void ReadAuthConfig()
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-02-01 18:19:18 +03:00
|
|
|
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
2025-06-23 16:39:30 +03:00
|
|
|
message.InfoText = LocalisationService.GetString("auth-config-read");
|
2025-02-01 18:19:18 +03:00
|
|
|
message.IsInfoClosable = false;
|
|
|
|
|
PopupMessageService.Popup(message);
|
2025-01-14 22:10:16 +03:00
|
|
|
foreach (var profile in
|
2025-02-01 18:19:18 +03:00
|
|
|
ConfigurationService.GetConfigValue(LauncherConVar.AuthProfiles)!)
|
|
|
|
|
AddAccount(new AuthLoginPassword(profile.Login, profile.Password, profile.AuthServer));
|
2024-12-27 08:22:17 +03:00
|
|
|
|
2025-01-14 22:10:16 +03:00
|
|
|
if (Accounts.Count == 0) UpdateAuthMenu();
|
2024-12-27 19:15:33 +03:00
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
AuthUrls.Clear();
|
|
|
|
|
var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!;
|
|
|
|
|
foreach (var url in authUrls) AuthUrls.Add(url);
|
2025-05-03 18:20:24 +03:00
|
|
|
if(authUrls.Length > 0) AuthItemSelect = authUrls[0];
|
2025-06-20 16:27:42 +03:00
|
|
|
message.Dispose();
|
|
|
|
|
|
|
|
|
|
DoCurrentAuth();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async void DoCurrentAuth()
|
|
|
|
|
{
|
|
|
|
|
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
2025-06-23 16:39:30 +03:00
|
|
|
message.InfoText = LocalisationService.GetString("auth-try-auth-config");
|
2025-06-20 16:27:42 +03:00
|
|
|
message.IsInfoClosable = false;
|
|
|
|
|
PopupMessageService.Popup(message);
|
|
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent);
|
2024-12-27 08:22:17 +03:00
|
|
|
|
|
|
|
|
if (currProfile != null)
|
|
|
|
|
{
|
2025-02-01 18:19:18 +03:00
|
|
|
try
|
|
|
|
|
{
|
2025-06-20 16:27:42 +03:00
|
|
|
await CatchAuthError(async () => await TryAuth(currProfile), () => message.Dispose());
|
2025-02-01 18:19:18 +03:00
|
|
|
}
|
2025-06-20 16:27:42 +03:00
|
|
|
catch (Exception ex)
|
2025-02-01 18:19:18 +03:00
|
|
|
{
|
2025-06-23 16:39:30 +03:00
|
|
|
var unexpectedError = new Exception(LocalisationService.GetString("auth-error"), ex);
|
2025-06-20 16:27:42 +03:00
|
|
|
_logger.Error(unexpectedError);
|
|
|
|
|
PopupMessageService.Popup(unexpectedError);
|
|
|
|
|
return;
|
2025-02-01 18:19:18 +03:00
|
|
|
}
|
2024-12-27 08:22:17 +03:00
|
|
|
}
|
2025-06-20 16:27:42 +03:00
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
message.Dispose();
|
2024-12-22 21:38:19 +03:00
|
|
|
}
|
|
|
|
|
|
2024-12-27 08:22:17 +03:00
|
|
|
[RelayCommand]
|
2024-12-27 19:15:33 +03:00
|
|
|
private void OnSaveProfile()
|
2024-12-22 21:38:19 +03:00
|
|
|
{
|
2025-05-03 18:20:24 +03:00
|
|
|
AddAccount(new AuthLoginPassword(CurrentLogin, CurrentPassword, CurrentAuthServer));
|
2024-12-27 19:15:33 +03:00
|
|
|
_isProfilesEmpty = Accounts.Count == 0;
|
|
|
|
|
UpdateAuthMenu();
|
|
|
|
|
DirtyProfile();
|
|
|
|
|
}
|
2025-01-14 22:10:16 +03:00
|
|
|
|
2025-02-01 18:19:18 +03:00
|
|
|
private void OnDeleteProfile(ProfileAuthCredentials account)
|
2024-12-27 19:15:33 +03:00
|
|
|
{
|
|
|
|
|
Accounts.Remove(account);
|
|
|
|
|
_isProfilesEmpty = Accounts.Count == 0;
|
|
|
|
|
UpdateAuthMenu();
|
|
|
|
|
DirtyProfile();
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-20 16:27:42 +03:00
|
|
|
private void PopupError(string message, Exception e)
|
|
|
|
|
{
|
2025-06-23 16:39:30 +03:00
|
|
|
message = LocalisationService.GetString("auth-error-occured") + message;
|
2025-06-20 16:27:42 +03:00
|
|
|
_logger.Error(new Exception(message, e));
|
|
|
|
|
|
|
|
|
|
var messageView = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
|
|
|
|
messageView.InfoText = message;
|
|
|
|
|
messageView.IsInfoClosable = true;
|
|
|
|
|
PopupMessageService.Popup(messageView);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-27 19:15:33 +03:00
|
|
|
[RelayCommand]
|
|
|
|
|
private void OnExpandAuthUrl()
|
|
|
|
|
{
|
|
|
|
|
AuthUrlConfigExpand = !AuthUrlConfigExpand;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void OnExpandAuthView()
|
|
|
|
|
{
|
|
|
|
|
AuthMenuExpand = !AuthMenuExpand;
|
|
|
|
|
UpdateAuthMenu();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DirtyProfile()
|
|
|
|
|
{
|
2025-02-01 18:19:18 +03:00
|
|
|
ConfigurationService.SetConfigValue(LauncherConVar.AuthProfiles,
|
|
|
|
|
Accounts.ToArray());
|
2024-12-22 21:38:19 +03:00
|
|
|
}
|
2025-07-02 21:32:51 +03:00
|
|
|
}
|