- add: TFA think
This commit is contained in:
20
Nebula.Launcher/LauncherConVar.cs
Normal file
20
Nebula.Launcher/LauncherConVar.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Nebula.Launcher.ViewModels.Pages;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher;
|
||||
|
||||
public static class LauncherConVar
|
||||
{
|
||||
public static readonly ConVar<ProfileAuthCredentials[]> AuthProfiles =
|
||||
ConVarBuilder.Build<ProfileAuthCredentials[]>("auth.profiles.v2", []);
|
||||
|
||||
public static readonly ConVar<CurrentAuthInfo?> AuthCurrent =
|
||||
ConVarBuilder.Build<CurrentAuthInfo?>("auth.current.v2");
|
||||
|
||||
public static readonly ConVar<string[]> Favorites =
|
||||
ConVarBuilder.Build<string[]>("server.favorites", []);
|
||||
|
||||
public static readonly ConVar<string[]> AuthServers = ConVarBuilder.Build<string[]>("launcher.authServers", [
|
||||
"https://auth.spacestation14.com/"
|
||||
]);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
@@ -38,7 +39,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
[GenerateProperty] private AuthService AuthService { get; } = default!;
|
||||
[GenerateProperty, DesignConstruct] private ViewHelperService ViewHelperService { get; } = default!;
|
||||
|
||||
public ObservableCollection<AuthLoginPasswordModel> Accounts { get; } = new();
|
||||
public ObservableCollection<ProfileAuthCredentials> Accounts { get; } = new();
|
||||
public ObservableCollection<string> AuthUrls { get; } = new();
|
||||
|
||||
private AuthLoginPassword CurrentAlp
|
||||
@@ -52,6 +53,9 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private CurrentAuthInfo? _currAuthTemp;
|
||||
|
||||
public string AuthItemSelect
|
||||
{
|
||||
set => CurrentAuthServer = value;
|
||||
@@ -71,37 +75,61 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
ReadAuthConfig();
|
||||
}
|
||||
|
||||
public void AuthByAlp(AuthLoginPassword authLoginPassword)
|
||||
public void AuthByProfile(ProfileAuthCredentials credentials)
|
||||
{
|
||||
CurrentAlp = authLoginPassword;
|
||||
CurrentAlp = new AuthLoginPassword(credentials.Login, credentials.Password, credentials.AuthServer);
|
||||
DoAuth();
|
||||
}
|
||||
|
||||
public void DoAuth()
|
||||
public void DoAuth(string? code = null)
|
||||
{
|
||||
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
||||
message.InfoText = "Auth think, please wait...";
|
||||
message.IsInfoClosable = false;
|
||||
Console.WriteLine("AUTH SHIT");
|
||||
PopupMessageService.Popup(message);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (await AuthService.Auth(CurrentAlp))
|
||||
try
|
||||
{
|
||||
await AuthService.Auth(CurrentAlp, code);
|
||||
message.Dispose();
|
||||
IsLogged = true;
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.AuthCurrent, CurrentAlp);
|
||||
ConfigurationService.SetConfigValue(LauncherConVar.AuthCurrent, AuthService.SelectedAuth);
|
||||
}
|
||||
else
|
||||
catch (AuthException e)
|
||||
{
|
||||
message.Dispose();
|
||||
|
||||
switch (e.Error.Code)
|
||||
{
|
||||
case AuthenticateDenyCode.TfaRequired:
|
||||
case AuthenticateDenyCode.TfaInvalid:
|
||||
var p = ViewHelperService.GetViewModel<TfaViewModel>();
|
||||
p.OnTfaEntered += OnTfaEntered;
|
||||
PopupMessageService.Popup(p);
|
||||
break;
|
||||
case AuthenticateDenyCode.InvalidCredentials:
|
||||
PopupMessageService.Popup("Invalid Credentials!");
|
||||
break;
|
||||
default:
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
message.Dispose();
|
||||
Logout();
|
||||
PopupMessageService.Popup("Well, shit is happened: " + AuthService.Reason);
|
||||
PopupMessageService.Popup(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnTfaEntered(string code)
|
||||
{
|
||||
DoAuth(code);
|
||||
}
|
||||
|
||||
public void Logout()
|
||||
{
|
||||
IsLogged = false;
|
||||
@@ -118,10 +146,10 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
|
||||
private void AddAccount(AuthLoginPassword authLoginPassword)
|
||||
{
|
||||
var onDelete = new DelegateCommand<AuthLoginPasswordModel>(OnDeleteProfile);
|
||||
var onSelect = new DelegateCommand<AuthLoginPasswordModel>(AuthByAlp);
|
||||
var onDelete = new DelegateCommand<ProfileAuthCredentials>(OnDeleteProfile);
|
||||
var onSelect = new DelegateCommand<ProfileAuthCredentials>(AuthByProfile);
|
||||
|
||||
var alpm = new AuthLoginPasswordModel(
|
||||
var alpm = new ProfileAuthCredentials(
|
||||
authLoginPassword.Login,
|
||||
authLoginPassword.Password,
|
||||
authLoginPassword.AuthServer,
|
||||
@@ -134,25 +162,39 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
Accounts.Add(alpm);
|
||||
}
|
||||
|
||||
private void ReadAuthConfig()
|
||||
private async void ReadAuthConfig()
|
||||
{
|
||||
var message = ViewHelperService.GetViewModel<InfoPopupViewModel>();
|
||||
message.InfoText = "Read configuration file, please wait...";
|
||||
message.IsInfoClosable = false;
|
||||
PopupMessageService.Popup(message);
|
||||
foreach (var profile in
|
||||
ConfigurationService.GetConfigValue(CurrentConVar.AuthProfiles)!)
|
||||
AddAccount(profile);
|
||||
ConfigurationService.GetConfigValue(LauncherConVar.AuthProfiles)!)
|
||||
AddAccount(new AuthLoginPassword(profile.Login, profile.Password, profile.AuthServer));
|
||||
|
||||
if (Accounts.Count == 0) UpdateAuthMenu();
|
||||
|
||||
var currProfile = ConfigurationService.GetConfigValue(CurrentConVar.AuthCurrent);
|
||||
AuthUrls.Clear();
|
||||
var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!;
|
||||
foreach (var url in authUrls) AuthUrls.Add(url);
|
||||
|
||||
var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent);
|
||||
|
||||
if (currProfile != null)
|
||||
{
|
||||
CurrentAlp = currProfile;
|
||||
DoAuth();
|
||||
try
|
||||
{
|
||||
CurrentAlp = new AuthLoginPassword(currProfile.Login, string.Empty, currProfile.AuthServer);
|
||||
IsLogged = await AuthService.SetAuth(currProfile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
message.Dispose();
|
||||
PopupMessageService.Popup(e);
|
||||
}
|
||||
}
|
||||
|
||||
AuthUrls.Clear();
|
||||
var authUrls = ConfigurationService.GetConfigValue(CurrentConVar.AuthServers)!;
|
||||
foreach (var url in authUrls) AuthUrls.Add(url);
|
||||
|
||||
message.Dispose();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -164,7 +206,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
DirtyProfile();
|
||||
}
|
||||
|
||||
private void OnDeleteProfile(AuthLoginPasswordModel account)
|
||||
private void OnDeleteProfile(ProfileAuthCredentials account)
|
||||
{
|
||||
Accounts.Remove(account);
|
||||
_isProfilesEmpty = Accounts.Count == 0;
|
||||
@@ -187,20 +229,18 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
||||
|
||||
private void DirtyProfile()
|
||||
{
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.AuthProfiles,
|
||||
Accounts.Select(a => (AuthLoginPassword)a).ToArray());
|
||||
ConfigurationService.SetConfigValue(LauncherConVar.AuthProfiles,
|
||||
Accounts.ToArray());
|
||||
}
|
||||
|
||||
public void OnPageOpen(object? args)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public record AuthLoginPasswordModel(
|
||||
public sealed record ProfileAuthCredentials(
|
||||
string Login,
|
||||
string Password,
|
||||
string AuthServer,
|
||||
ICommand OnSelect = default!,
|
||||
ICommand OnDelete = default!)
|
||||
: AuthLoginPassword(Login, Password, AuthServer);
|
||||
[property: JsonIgnore] ICommand OnSelect = default!,
|
||||
[property: JsonIgnore] ICommand OnDelete = default!
|
||||
);
|
||||
@@ -22,7 +22,7 @@ public partial class ServerListViewModel
|
||||
{
|
||||
FavoriteServers.Clear();
|
||||
|
||||
var servers = ConfigurationService.GetConfigValue(CurrentConVar.Favorites);
|
||||
var servers = ConfigurationService.GetConfigValue(LauncherConVar.Favorites);
|
||||
if (servers is null || servers.Length == 0)
|
||||
{
|
||||
return;
|
||||
@@ -44,17 +44,17 @@ public partial class ServerListViewModel
|
||||
|
||||
public void AddFavorite(RobustUrl robustUrl)
|
||||
{
|
||||
var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList();
|
||||
var servers = (ConfigurationService.GetConfigValue(LauncherConVar.Favorites) ?? []).ToList();
|
||||
servers.Add(robustUrl.ToString());
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray());
|
||||
ConfigurationService.SetConfigValue(LauncherConVar.Favorites, servers.ToArray());
|
||||
UpdateFavoriteEntries();
|
||||
}
|
||||
|
||||
public void RemoveFavorite(ServerEntryModelView entryModelView)
|
||||
{
|
||||
var servers = (ConfigurationService.GetConfigValue(CurrentConVar.Favorites) ?? []).ToList();
|
||||
var servers = (ConfigurationService.GetConfigValue(LauncherConVar.Favorites) ?? []).ToList();
|
||||
servers.Remove(entryModelView.Address.ToString());
|
||||
ConfigurationService.SetConfigValue(CurrentConVar.Favorites, servers.ToArray());
|
||||
ConfigurationService.SetConfigValue(LauncherConVar.Favorites, servers.ToArray());
|
||||
entryModelView.IsFavorite = false;
|
||||
UpdateFavoriteEntries();
|
||||
}
|
||||
|
||||
29
Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs
Normal file
29
Nebula.Launcher/ViewModels/Popup/TfaViewModel.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Nebula.Launcher.Views.Popup;
|
||||
using Nebula.Shared.Services;
|
||||
|
||||
namespace Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
[ConstructGenerator, ViewModelRegister(typeof(TfaView))]
|
||||
public partial class TfaViewModel : PopupViewModelBase
|
||||
{
|
||||
public Action<string>? OnTfaEntered;
|
||||
|
||||
protected override void InitialiseInDesignMode()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Initialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnTfaEnter(string code)
|
||||
{
|
||||
OnTfaEntered?.Invoke(code);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||
public override string Title => "2fa";
|
||||
public override bool IsClosable => true;
|
||||
}
|
||||
@@ -185,10 +185,10 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
{ "ROBUST_AUTH_USERID", authProv?.UserId.ToString() },
|
||||
{ "ROBUST_AUTH_TOKEN", authProv?.Token.Token },
|
||||
{ "ROBUST_AUTH_SERVER", authProv?.AuthLoginPassword.AuthServer },
|
||||
{ "ROBUST_AUTH_SERVER", authProv?.AuthServer },
|
||||
{ "ROBUST_AUTH_PUBKEY", buildInfo.BuildInfo.Auth.PublicKey },
|
||||
{ "GAME_URL", Address.ToString() },
|
||||
{ "AUTH_LOGIN", authProv?.AuthLoginPassword.Login }
|
||||
{ "AUTH_LOGIN", authProv?.Login }
|
||||
},
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
@@ -253,8 +253,7 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
CurrLog.Append(e.Data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void ReadLog()
|
||||
{
|
||||
PopupMessageService.Popup(CurrLog);
|
||||
@@ -286,7 +285,6 @@ public partial class ServerEntryModelView : ViewModelBase
|
||||
{
|
||||
Links.Add(link);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static string FindDotnetPath()
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
ItemsSource="{Binding Accounts}"
|
||||
Padding="0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type pages:AuthLoginPasswordModel}">
|
||||
<DataTemplate DataType="{x:Type pages:ProfileAuthCredentials}">
|
||||
<Border
|
||||
Background="{StaticResource DefaultBackground}"
|
||||
BoxShadow="0 1 15 -2 #121212"
|
||||
|
||||
39
Nebula.Launcher/Views/Popup/TfaView.axaml
Normal file
39
Nebula.Launcher/Views/Popup/TfaView.axaml
Normal file
@@ -0,0 +1,39 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:popup="clr-namespace:Nebula.Launcher.ViewModels.Popup"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Nebula.Launcher.Views.Popup.TfaView">
|
||||
<Design.DataContext>
|
||||
<popup:TfaViewModel />
|
||||
</Design.DataContext>
|
||||
<StackPanel HorizontalAlignment="Stretch" Spacing="25" VerticalAlignment="Center">
|
||||
<Label HorizontalAlignment="Center">You have two-factor authentication enabled. Please enter the code.</Label>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10" x:Name="TContainer">
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||
<TextBox MaxLength="1"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<Border BoxShadow="{StaticResource DefaultShadow}" Background="{StaticResource DefaultSelected}" HorizontalAlignment="Center">
|
||||
<Button Click="Button_OnClick">
|
||||
<Label HorizontalAlignment="Center" Margin="15,5,15,5">OK</Label>
|
||||
</Button>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
100
Nebula.Launcher/Views/Popup/TfaView.axaml.cs
Normal file
100
Nebula.Launcher/Views/Popup/TfaView.axaml.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Nebula.Launcher.ViewModels.Popup;
|
||||
|
||||
namespace Nebula.Launcher.Views.Popup;
|
||||
|
||||
public partial class TfaView : UserControl
|
||||
{
|
||||
public List<TextBox> Boxes = new();
|
||||
|
||||
public TfaView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
foreach (var textBox in TContainer.Children.Select(UnzipBox))
|
||||
{
|
||||
var currIndex = Boxes.Count;
|
||||
Boxes.Add(textBox);
|
||||
textBox.TextChanged += (_,_) => OnTextChanged(currIndex);
|
||||
textBox.PastingFromClipboard += OnPasteFromClipboard;
|
||||
textBox.KeyUp += (sender, args) =>
|
||||
{
|
||||
if (args.Key == Key.Back && string.IsNullOrEmpty(textBox.Text)) OnTextChanged(currIndex);
|
||||
};
|
||||
textBox.KeyDown += (sender, args) =>
|
||||
{
|
||||
textBox.Text = args.KeySymbol;
|
||||
textBox.SelectionStart = 1;
|
||||
//OnTextChanged(currIndex);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPasteFromClipboard(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
// TODO: CLIPBOARD THINK
|
||||
}
|
||||
|
||||
private void OnTextChanged(int index)
|
||||
{
|
||||
var box = Boxes[index];
|
||||
|
||||
if (string.IsNullOrEmpty(box.Text))
|
||||
{
|
||||
if(index == 0) return;
|
||||
index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!int.TryParse(box.Text, out var _))
|
||||
{
|
||||
box.Text = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (index == 5)
|
||||
{
|
||||
CheckupCode();
|
||||
return;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
Boxes[index].Focus();
|
||||
}
|
||||
|
||||
private void CheckupCode()
|
||||
{
|
||||
var str = "";
|
||||
foreach (var vtTextBox in Boxes)
|
||||
{
|
||||
if(string.IsNullOrEmpty(vtTextBox.Text)) return;
|
||||
str += vtTextBox.Text;
|
||||
}
|
||||
|
||||
((TfaViewModel)DataContext!).OnTfaEnter(str);
|
||||
}
|
||||
|
||||
private TextBox UnzipBox(Control control)
|
||||
{
|
||||
var box = (Border)control;
|
||||
return (TextBox)box.Child!;
|
||||
}
|
||||
|
||||
public TfaView(TfaViewModel tfaViewModel) : this()
|
||||
{
|
||||
DataContext = tfaViewModel;
|
||||
}
|
||||
|
||||
private void Button_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
CheckupCode();
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
Grid.Column="3"
|
||||
Grid.Row="1"
|
||||
IsVisible="{Binding ExpandInfo}"
|
||||
Margin="5,5,0,0"
|
||||
|
||||
Reference in New Issue
Block a user