using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text.Json.Serialization; using System.Threading.Tasks; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Nebula.Launcher.Services; using Nebula.Launcher.ViewModels.Popup; using Nebula.Launcher.Views.Pages; using Nebula.Shared; using Nebula.Shared.Services; using Nebula.Shared.Utils; namespace Nebula.Launcher.ViewModels.Pages; [ViewModelRegister(typeof(AccountInfoView))] [ConstructGenerator] public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage { [ObservableProperty] private bool _authMenuExpand; [ObservableProperty] private bool _authUrlConfigExpand; [ObservableProperty] private int _authViewSpan = 1; [ObservableProperty] private string _currentAuthServer = string.Empty; [ObservableProperty] private string _currentLogin = string.Empty; [ObservableProperty] private string _currentPassword = string.Empty; [ObservableProperty] private bool _isLogged; private bool _isProfilesEmpty; [GenerateProperty] private PopupMessageService PopupMessageService { get; } = default!; [GenerateProperty] private ConfigurationService ConfigurationService { get; } = default!; [GenerateProperty] private AuthService AuthService { get; } = default!; [GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!; public ObservableCollection Accounts { get; } = new(); public ObservableCollection AuthUrls { get; } = new(); [ObservableProperty] private AuthServerCredentials _authItemSelect; //Design think protected override void InitialiseInDesignMode() { AddAccount(new AuthLoginPassword("Binka", "12341", "")); AddAccount(new AuthLoginPassword("Binka", "12341", "")); AuthUrls.Add(new AuthServerCredentials("Test",["example.com"])); } //Real think protected override void Initialise() { ReadAuthConfig(); } public void AuthByProfile(ProfileAuthCredentials credentials) { CurrentLogin = credentials.Login; CurrentPassword = credentials.Password; CurrentAuthServer = credentials.AuthServer; DoAuth(); } public void DoAuth(string? code = null) { var message = ViewHelperService.GetViewModel(); message.InfoText = "Auth think, please wait..."; message.IsInfoClosable = false; PopupMessageService.Popup(message); var serverCandidates = new List(); if (string.IsNullOrWhiteSpace(CurrentAuthServer)) serverCandidates.AddRange(AuthItemSelect.Servers); else serverCandidates.Add(CurrentAuthServer); Task.Run(async () => { Exception? exception = null; foreach (var server in serverCandidates) { try { await TryAuth(CurrentLogin, CurrentPassword, server,code); break; } catch (Exception e) { exception = e; } } message.Dispose(); if (!IsLogged) { PopupMessageService.Popup(new Exception("No one of auth server is available.", exception)); } }); } private async Task TryAuth(string login, string password, string authServer,string? code) { try { await AuthService.Auth(new AuthLoginPassword(login, password, authServer), code); CurrentLogin = login; CurrentPassword = password; CurrentAuthServer = authServer; IsLogged = true; ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth); } catch (AuthException e) { switch (e.Error.Code) { case AuthenticateDenyCode.TfaRequired: case AuthenticateDenyCode.TfaInvalid: var p = ViewHelperService.GetViewModel(); p.OnTfaEntered += OnTfaEntered; PopupMessageService.Popup(p); break; case AuthenticateDenyCode.InvalidCredentials: PopupMessageService.Popup("Invalid Credentials!"); break; default: throw; } } } private void OnTfaEntered(string code) { DoAuth(code); } public void Logout() { IsLogged = false; AuthService.ClearAuth(); } private void UpdateAuthMenu() { if (AuthMenuExpand || _isProfilesEmpty) AuthViewSpan = 2; else AuthViewSpan = 1; } private void AddAccount(AuthLoginPassword authLoginPassword) { var onDelete = new DelegateCommand(OnDeleteProfile); var onSelect = new DelegateCommand(AuthByProfile); var alpm = new ProfileAuthCredentials( authLoginPassword.Login, authLoginPassword.Password, authLoginPassword.AuthServer, onSelect, onDelete); onDelete.TRef.Value = alpm; onSelect.TRef.Value = alpm; Accounts.Add(alpm); } private async void ReadAuthConfig() { var message = ViewHelperService.GetViewModel(); message.InfoText = "Read configuration file, please wait..."; message.IsInfoClosable = false; PopupMessageService.Popup(message); foreach (var profile in ConfigurationService.GetConfigValue(LauncherConVar.AuthProfiles)!) AddAccount(new AuthLoginPassword(profile.Login, profile.Password, profile.AuthServer)); if (Accounts.Count == 0) UpdateAuthMenu(); AuthUrls.Clear(); var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!; foreach (var url in authUrls) AuthUrls.Add(url); if(authUrls.Length > 0) AuthItemSelect = authUrls[0]; var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent); if (currProfile != null) { try { CurrentLogin = currProfile.Login; CurrentAuthServer = currProfile.AuthServer; IsLogged = await AuthService.SetAuth(currProfile); } catch (Exception e) { message.Dispose(); PopupMessageService.Popup(e); } } message.Dispose(); } [RelayCommand] private void OnSaveProfile() { AddAccount(new AuthLoginPassword(CurrentLogin, CurrentPassword, CurrentAuthServer)); _isProfilesEmpty = Accounts.Count == 0; UpdateAuthMenu(); DirtyProfile(); } private void OnDeleteProfile(ProfileAuthCredentials account) { Accounts.Remove(account); _isProfilesEmpty = Accounts.Count == 0; UpdateAuthMenu(); DirtyProfile(); } [RelayCommand] private void OnExpandAuthUrl() { AuthUrlConfigExpand = !AuthUrlConfigExpand; } [RelayCommand] private void OnExpandAuthView() { AuthMenuExpand = !AuthMenuExpand; UpdateAuthMenu(); } private void DirtyProfile() { ConfigurationService.SetConfigValue(LauncherConVar.AuthProfiles, Accounts.ToArray()); } public void OnPageOpen(object? args) { } } public sealed record ProfileAuthCredentials( string Login, string Password, string AuthServer, [property: JsonIgnore] ICommand OnSelect = default!, [property: JsonIgnore] ICommand OnDelete = default! ); public sealed record AuthServerCredentials( string Name, string[] Servers );