Compare commits

..

1 Commits

Author SHA1 Message Date
achiez 2a641e99ae Update version to 1.5.7
- Changed session ID retrieval method in `LoginV2Executor` for avoiding 429 errors
2025-05-23 16:32:50 +03:00
275 changed files with 4255 additions and 5666 deletions
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
+22 -18
View File
@@ -3,6 +3,15 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaAuth", "NebulaAuth\NebulaAuth.csproj", "{0FD01700-6D5C-451B-93BA-0860647E8F13}"
ProjectSection(ProjectDependencies) = postProject
{09F02072-F91D-4DAA-87BC-A34D3E150570} = {09F02072-F91D-4DAA-87BC-A34D3E150570}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaAuth.LegacyConverter", "NebulaAuth.LegacyConverter\NebulaAuth.LegacyConverter.csproj", "{2D78A7D9-986A-4890-8A91-7ABD57A91830}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SteamLibForked", "SteamLibForked\SteamLibForked.csproj", "{09F02072-F91D-4DAA-87BC-A34D3E150570}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "changelog", "changelog", "{161BFADE-FCF3-45D1-82EA-8A1B187529F7}"
ProjectSection(SolutionItems) = preProject
changelog\1.3.4.html = changelog\1.3.4.html
@@ -19,32 +28,27 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "changelog", "changelog", "{
changelog\1.5.4.html = changelog\1.5.4.html
changelog\1.5.5.html = changelog\1.5.5.html
changelog\1.5.6.html = changelog\1.5.6.html
changelog\1.5.7.html = changelog\1.5.7.html
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SteamLibForked", "src\SteamLibForked\SteamLibForked.csproj", "{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NebulaAuth.LegacyConverter", "src\NebulaAuth.LegacyConverter\NebulaAuth.LegacyConverter.csproj", "{C8235305-E5C4-155B-C718-C0F239CA3AB7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NebulaAuth", "src\NebulaAuth\NebulaAuth.csproj", "{C42F63B6-32F7-ED08-5B86-CD51989761AD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{224F9DB0-3D20-A614-BA2A-12F22B13A2C6}.Release|Any CPU.Build.0 = Release|Any CPU
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8235305-E5C4-155B-C718-C0F239CA3AB7}.Release|Any CPU.Build.0 = Release|Any CPU
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C42F63B6-32F7-ED08-5B86-CD51989761AD}.Release|Any CPU.Build.0 = Release|Any CPU
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FD01700-6D5C-451B-93BA-0860647E8F13}.Release|Any CPU.Build.0 = Release|Any CPU
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D78A7D9-986A-4890-8A91-7ABD57A91830}.Release|Any CPU.Build.0 = Release|Any CPU
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09F02072-F91D-4DAA-87BC-A34D3E150570}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+14 -28
View File
@@ -4,9 +4,13 @@
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:converters="clr-namespace:NebulaAuth.Converters"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:background="clr-namespace:NebulaAuth.Converters.Background">
xmlns:background="clr-namespace:NebulaAuth.Converters.Background"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="MaterialDesignPaper">#1E2025</SolidColorBrush>
<FontFamily x:Key="Roboto">pack://application:,,,/Fonts/Roboto/#Roboto</FontFamily>
<FontFamily x:Key="RobotoSymbols">pack://application:,,,/Fonts/Roboto/#Roboto Symbols</FontFamily>
<converters:CoefficientConverter x:Key="CoefficientConverter" />
<converters:ReverseBooleanConverter x:Key="ReverseBooleanConverter" />
<converters:ProxyTextConverter x:Key="ProxyTextConverter" />
@@ -15,50 +19,32 @@
<converters:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<converters:AnyMafilesToVisibilityConverter x:Key="AnyMafilesToVisibilityConverter" />
<converters:PortableMaClientStatusToColorConverter x:Key="PortableMaClientStatusToColorConverter" />
<converters:NullableToBooleanConverter x:Key="NullableToBooleanConverter" />
<!-- Background converters-->
<background:BackgroundImageVisibleConverter x:Key="BackgroundImageVisibleConverter" />
<background:BackgroundSourceConverter x:Key="BackgroundSourceConverter" />
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<materialDesign:NullableToVisibilityConverter x:Key="NullableToVisibilityConverter" />
<system:Boolean x:Key="True">True</system:Boolean>
<system:Boolean x:Key="False">False</system:Boolean>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Theme/Themes/DefaultTheme.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
<ResourceDictionary Source="Theme/Brushes.xaml" />
<!--Controls-->
<materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="LightGreen" SecondaryColor="Purple" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.snackbar.xaml" />
<ResourceDictionary Source="View/ConfirmationTemplates.xaml" />
<ResourceDictionary Source="View/LinkerStepTemplates.xaml" />
<ResourceDictionary Source="View/MafileMoverStepTemplates.xaml" />
<!--Theme-->
<ResourceDictionary
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.Dark.xaml" />
<!-- Theme-->
<ResourceDictionary Source="Theme/Brushes.xaml" />
<ResourceDictionary Source="Theme/WindowStyle/WindowStyle.xaml" />
<ResourceDictionary Source="Theme/MaterialDesignThemes.Overrides.xaml" />
<ResourceDictionary>
<Style TargetType="ToolTip" BasedOn="{StaticResource {x:Type ToolTip}}">
<Setter Property="Foreground" Value="{DynamicResource Base100Brush}" />
<Setter Property="Background" Value="{DynamicResource BaseContentBrush}" />
</Style>
</ResourceDictionary>
<!--Controls-->
<ResourceDictionary Source="View/ConfirmationTemplates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
+34
View File
@@ -0,0 +1,34 @@
using System;
using System.Windows;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Exceptions;
namespace NebulaAuth;
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LocManager.Init();
LocManager.SetApplicationLocalization(Settings.Instance.Language);
try
{
Shell.Initialize();
}
catch (Exception ex)
{
var msg = ex.ToString();
if (ex is CantAlignTimeException)
{
msg = LocManager.Get("CantAlignTimeError");
}
MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Stop, MessageBoxResult.OK,
MessageBoxOptions.DefaultDesktopOnly);
throw;
}
}
}
@@ -11,10 +11,10 @@ public class AnyMafilesToVisibilityConverter : IValueConverter
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
//if (_everAnyMafiles)
//{
// return Visibility.Collapsed;
//}
if (_everAnyMafiles)
{
return Visibility.Collapsed;
}
if (value is 0)
{
@@ -18,7 +18,7 @@ public class BackgroundSourceConverter : IValueConverter
}
return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.png"));
return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.jpg"));
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
@@ -14,7 +14,6 @@ public class PortableMaClientStatusToColorConverter : IValueConverter
return new SolidColorBrush(Color.FromRgb(187, 224, 139));
}
return new SolidColorBrush(Color.FromRgb(224, 139, 139));
}
@@ -5,8 +5,6 @@ using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel.Linker;
using NebulaAuth.ViewModel.MafileMover;
using NebulaAuth.ViewModel.Other;
namespace NebulaAuth.Core;
@@ -88,37 +86,11 @@ public static class DialogsController
public static async Task ShowLinkerDialog()
{
LinkAccountVM? vm = null;
try
var vm = new LinkAccountVM();
var view = new LinkerView
{
vm = new LinkAccountVM();
var view = new LinkerView
{
DataContext = vm
};
await DialogHost.Show(view);
}
finally
{
vm?.Dispose();
}
}
public static async Task ShowMafileMoverDialog()
{
MafileMoverVM? vm = null;
try
{
vm = new MafileMoverVM();
var view = new MafileMoverView
{
DataContext = vm
};
await DialogHost.Show(view);
}
finally
{
vm?.Dispose();
}
DataContext = vm
};
await DialogHost.Show(view);
}
}
@@ -38,7 +38,7 @@ public static class LocManager
public static void Init()
{
Loc.Instance.LogOutMissingTranslations = true;
Loc.LogOutMissingTranslations = true;
LocalizationLoader.Instance.FileLanguageLoaders.Add(new JsonFileLoader());
@@ -2,9 +2,9 @@
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shell;
using NebulaAuth.Model;
@@ -14,6 +14,7 @@ namespace NebulaAuth.Core;
public static class ThemeManager
{
public static System.Windows.Media.Color DefaultBackgroundColor = System.Windows.Media.Color.FromRgb(30, 32, 37);
private static readonly Window MainWindow = Application.Current.MainWindow!;
static ThemeManager()
@@ -23,7 +24,11 @@ public static class ThemeManager
private static void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Settings.IconColor))
if (e.PropertyName == nameof(Settings.BackgroundColor))
{
UpdateBackground();
}
else if (e.PropertyName == nameof(Settings.IconColor))
{
UpdateIcon();
}
@@ -53,40 +58,15 @@ public static class ThemeManager
}
}
public static void ApplyTheme(string themeName)
private static void UpdateBackground()
{
var colorDict = new ResourceDictionary
{
Source = new Uri($"Theme/Themes/{themeName}.xaml", UriKind.Relative)
};
var brushDict = new ResourceDictionary
{
Source = new Uri("Theme/Brushes.xaml", UriKind.Relative)
};
var mergedDictionaries = Application.Current.Resources.MergedDictionaries;
var toRemove = mergedDictionaries
.Where(d => d.Source?.OriginalString.Contains("Theme/Themes/") == true ||
d.Source?.OriginalString.EndsWith("Brushes.xaml") == true)
.ToList();
foreach (var dict in toRemove)
{
mergedDictionaries.Remove(dict);
}
mergedDictionaries.Insert(0, colorDict);
mergedDictionaries.Insert(0, brushDict);
var color = Settings.Instance.BackgroundColor ?? DefaultBackgroundColor;
Application.Current.Resources["WindowBackground"] = new SolidColorBrush(color);
}
public static void InitializeTheme()
{
UpdateIcon();
ApplyTheme(Settings.Instance.GetTheme());
UpdateBackground();
}
}
@@ -8,7 +8,7 @@ namespace NebulaAuth.Core;
public static class UpdateManager
{
private const string UPDATE_URL =
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/misc/update.xml";
"https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/NebulaAuth/update.xml";
public static void CheckForUpdates()
{
@@ -9,14 +9,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
xmlns:viewModel="clr-namespace:NebulaAuth.ViewModel"
xmlns:controls="clr-namespace:NebulaAuth.Theme.Controls"
WindowStartupLocation="CenterScreen"
MinHeight="500" MinWidth="500" DefaultFontSize="18" ScaleCoefficient="0.4"
Title="NebulaAuth" Height="800" Width="730"
Style="{StaticResource MainWindow}"
RenderOptions.BitmapScalingMode="HighQuality"
Title="NebulaAuth" Height="800" Width="730" Style="{StaticResource MainWindow}"
RenderOptions.BitmapScalingMode="HighQuality" Foreground="#FFF5F5F5"
FontFamily="{md:MaterialDesignFont}"
TextElement.Foreground="{DynamicResource BaseContentBrush}"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:MainVM}">
<b:Interaction.Behaviors>
@@ -30,31 +28,20 @@
</Window.InputBindings>
<Border Name="DragNDropBorder" Panel.ZIndex="3" Opacity="1" AllowDrop="True"
DragDrop.DragEnter="Rectangle_DragEnter" DragLeave="Rectangle_DragLeave" Drop="Rectangle_Drop">
<md:DialogHost DialogOpened="DialogHost_DialogOpened"
DialogClosed="DialogHost_DialogClosed"
ApplyBlurBackground="{Binding Settings.ApplyBlurBackground}"
BlurRadius="12"
x:Name="DialogHostInstance">
<md:DialogHost DialogOpened="DialogHost_DialogOpened" DialogClosed="DialogHost_DialogClosed">
<Grid ZIndex="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Grid.RowSpan="2" Opacity="{Binding Settings.BackgroundOpacity}" Stretch="UniformToFill"
<Image Grid.RowSpan="2" Opacity="0.6" Stretch="UniformToFill"
RenderOptions.BitmapScalingMode="LowQuality" HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}"
Source="{Binding Settings.BackgroundMode, Mode=OneWay, Converter={StaticResource BackgroundSourceConverter}}">
<Image.Effect>
<BlurEffect Radius="{Binding Settings.BackgroundBlur}" />
</Image.Effect>
</Image>
<Rectangle Grid.Row="0" Grid.RowSpan="2" Fill="Black" Stretch="UniformToFill"
Opacity="{Binding Settings.BackgroundGamma}"
IsHitTestVisible="False" />
Source="{Binding Settings.BackgroundMode, Mode=OneWay, Converter={StaticResource BackgroundSourceConverter}}" />
<Rectangle Grid.Row="0" Grid.RowSpan="2" Opacity="0.5" Fill="#FF1F1D1D"
Visibility="{Binding Settings.BackgroundMode, Converter={StaticResource BackgroundImageVisibleConverter}}" />
<Rectangle Name="DragNDropOverlay" Grid.Row="0" Grid.RowSpan="3" Panel.ZIndex="1" Fill="#242123"
Opacity="0.9" Visibility="Hidden" />
<StackPanel Name="DragNDropPanel" Grid.Row="0" ZIndex="2" w:FontScaleWindow.Scale="1"
@@ -64,10 +51,13 @@
<md:PackIcon Foreground="#9a65b8" HorizontalAlignment="Center" Width="36" Height="36"
Kind="FileReplaceOutline" />
</StackPanel>
<ToolBarTray>
<ToolBar ClipToBounds="True" HorizontalContentAlignment="Stretch"
Style="{StaticResource MaterialDesignToolBar}" FontSize="16">
<Menu FontSize="16">
<ToolBarTray IsLocked="True" Grid.Row="0">
<ToolBarTray.Background>
<SolidColorBrush Opacity="0.6" Color="#FF1A1C25" />
</ToolBarTray.Background>
<ToolBar Background="#00FFFFFF" ClipToBounds="False" Style="{StaticResource MaterialDesignToolBar}"
w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<Menu w:FontScaleWindow.Scale="0.68" w:FontScaleWindow.ResizeFont="True">
<MenuItem Header="{Tr MainWindow.Menu.File.Caption}">
<MenuItem Header="{Tr MainWindow.Menu.File.Import}"
Command="{Binding AddMafileCommand}" />
@@ -85,11 +75,8 @@
<MenuItem Header="{Tr MainWindow.Menu.Account.Caption}">
<MenuItem Header="{Tr MainWindow.Menu.Account.Link}"
Command="{Binding LinkAccountCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.Account.MoveSteamGuard}"
Command="{Binding MoveAccountCommand}" />
<MenuItem Header="{Tr MainWindow.Menu.Account.Unlink}"
Command="{Binding RemoveAuthenticatorCommand}" />
<MenuItem IsEnabled="False" Header="⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯" Height="15" />
<MenuItem IsEnabled="{Binding IsMafileSelected}"
Header="{Tr MainWindow.Menu.Account.RefreshSession}"
@@ -104,8 +91,7 @@
md:HintAssist.Hint="{Tr MainWindow.AppBar.GroupsHint}"
MinWidth="100" Margin="8,0,8,0" VerticalAlignment="Center" IsEditable="True"
ItemsSource="{Binding Groups}"
SelectedValue="{Binding SelectedGroup}"
md:TextFieldAssist.HasClearButton="True">
SelectedValue="{Binding SelectedGroup}">
<FrameworkElement.Resources>
<ResourceDictionary>
@@ -128,7 +114,6 @@
md:HintAssist.Hint="{Tr MainWindow.AppBar.Proxy.ProxyHint}"
md:ComboBoxAssist.ShowSelectedItem="False"
SelectedValue="{Binding SelectedProxy}"
ItemsSource="{Binding Proxies}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type entities:MaProxy}">
@@ -147,8 +132,7 @@
</UIElement.InputBindings>
</ComboBox>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="{DynamicResource ErrorBrush}" Margin="3"
ToolTipService.InitialShowDelay="300">
Foreground="#FFFF0000" Margin="3" ToolTipService.InitialShowDelay="300">
<md:PackIcon.ToolTip>
<TextBlock>
<Run
@@ -169,11 +153,12 @@
</UIElement.Visibility>
</md:PackIcon>
<md:PackIcon Kind="StopAlert" VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="{DynamicResource WarningBrush}" Margin="3"
Foreground="#FFFFA500" Margin="3"
ToolTip="{Tr MainWindow.AppBar.Proxy.ProxyAlert.DefaultInUse}"
ToolTipService.InitialShowDelay="300"
Visibility="{Binding IsDefaultProxy, Converter={StaticResource BooleanToVisibilityConverter}}" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.MarketTimerHint}"
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
IsEnabled="{Binding IsMafileSelected}" Margin="2"
Style="{StaticResource MaterialDesignFlatToggleButton}"
IsChecked="{Binding MarketTimerEnabled}">
@@ -190,6 +175,7 @@
</FrameworkElement.ContextMenu>
</ToggleButton>
<ToggleButton ToolTip="{Tr MainWindow.AppBar.TradeTimerHint}"
Foreground="{DynamicResource PrimaryHueDarkForegroundBrush}"
IsEnabled="{Binding IsMafileSelected}" Margin="2"
Style="{StaticResource MaterialDesignFlatToggleButton}"
IsChecked="{Binding TradeTimerEnabled}">
@@ -211,7 +197,7 @@
PreviewTextInput="UIElement_OnPreviewTextInput" />
<ToggleButton ToolTip="{Tr MainWindow.AppBar.ShowAutoConfirmAccountsHint}"
HorizontalAlignment="Right" IsChecked="{Binding MaacDisplay}"
Foreground="{DynamicResource BaseContentBrush}" VerticalAlignment="Center"
Foreground="WhiteSmoke" VerticalAlignment="Center"
Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}" Margin="4">
<md:PackIcon Kind="Accounts" />
</ToggleButton>
@@ -228,138 +214,117 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Grid.Row="0"
Margin="10,15,0,0" ItemsSource="{Binding MaFiles}"
SelectedValue="{Binding SelectedMafile}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
<TextBlock.Foreground>
<Binding Mode="OneWay" Path="LinkedClient.IsError"
Converter="{StaticResource PortableMaClientStatusToColorConverter}">
<Binding.FallbackValue>
<SolidColorBrush Color="WhiteSmoke" />
</Binding.FallbackValue>
</Binding>
</TextBlock.Foreground>
</TextBlock>
<StackPanel
Visibility="{Binding LinkedClient, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Column="1" Orientation="Horizontal">
<md:PackIcon Kind="ShoppingCart"
Visibility="{Binding LinkedClient.AutoConfirmMarket, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
<md:PackIcon Kind="AccountArrowRight"
Visibility="{Binding LinkedClient.AutoConfirmTrades, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Key="C" Modifiers="Control"
Command="{Binding DataContext.CopyLoginCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
<KeyBinding Key="X" Modifiers="Control"
Command="{Binding DataContext.CopyMafileCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
</ListBox.InputBindings>
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem InputGestureText="Ctrl+C"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyLogin}"
Command="{Binding CopyLoginCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopySteamId}"
Command="{Binding CopySteamIdCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem InputGestureText="Ctrl+X"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyMafile}"
Command="{Binding CopyMafileCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.AddToGroup}"
ItemsSource="{Binding Groups}">
<ItemsControl.ItemContainerStyle>
<Style BasedOn="{StaticResource MaterialDesignMenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="Command"
Value="{Binding DataContext.AddToGroupCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding
Converter="{StaticResource MultiCommandParameterConverter}">
<Binding />
<Binding Path="PlacementTarget.SelectedValue"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</MenuItem>
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.RemoveFromGroup}"
Command="{Binding Path=RemoveGroupCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopyPassword}"
Command="{Binding Path=CopyPasswordCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
</ListBox>
<Border Grid.Row="0" Margin="10" Padding="5"
BorderThickness="1"
CornerRadius="12">
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource Base300Color}" Opacity="0.3" />
</Border.BorderBrush>
Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}, Mode=OneWay}">
<Border.Background>
<SolidColorBrush Color="{DynamicResource Base100Color}"
Opacity="{Binding Settings.LeftOpacity}" />
<SolidColorBrush Color="DarkGray" Opacity="0.5" />
</Border.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Margin="4"
Visibility="{Binding MaFiles.Count, Converter={StaticResource AnyMafilesToVisibilityConverter}}"
TextWrapping="WrapWithOverflow" FontSize="16"
Text="{Tr MainWindow.LeftPart.NoMafiles}" />
<ListBox w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True" Margin="2"
ItemsSource="{Binding MaFiles}"
SelectedValue="{Binding SelectedMafile}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem"
BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Stretch" Text="{Binding AccountName}">
<TextBlock.Resources>
<SolidColorBrush x:Key="BaseContentBrushProxy"
Color="{DynamicResource BaseContentColor}" />
</TextBlock.Resources>
<TextBlock.Foreground>
<Binding Path="LinkedClient.IsError"
Converter="{StaticResource PortableMaClientStatusToColorConverter}"
FallbackValue="{StaticResource BaseContentBrushProxy}" />
</TextBlock.Foreground>
</TextBlock>
<StackPanel
Visibility="{Binding LinkedClient, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Column="1" Orientation="Horizontal">
<md:PackIcon Kind="ShoppingCart"
Visibility="{Binding LinkedClient.AutoConfirmMarket, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
<md:PackIcon Kind="AccountArrowRight"
Visibility="{Binding LinkedClient.AutoConfirmTrades, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Key="C" Modifiers="Control"
Command="{Binding DataContext.CopyLoginCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
<KeyBinding Key="X" Modifiers="Control"
Command="{Binding DataContext.CopyMafileCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" />
</ListBox.InputBindings>
<FrameworkElement.ContextMenu>
<ContextMenu>
<MenuItem InputGestureText="Ctrl+C"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyLogin}"
Command="{Binding CopyLoginCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopySteamId}"
Command="{Binding CopySteamIdCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem InputGestureText="Ctrl+X"
Header="{Tr MainWindow.ContextMenus.Mafile.CopyMafile}"
Command="{Binding CopyMafileCommand}"
CommandParameter="{Binding PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.AddToGroup}"
ItemsSource="{Binding Groups}">
<ItemsControl.ItemContainerStyle>
<Style BasedOn="{StaticResource MaterialDesignMenuItem}"
TargetType="{x:Type MenuItem}">
<Setter Property="Command"
Value="{Binding DataContext.AddToGroupCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding
Converter="{StaticResource MultiCommandParameterConverter}">
<Binding />
<Binding Path="PlacementTarget.SelectedValue"
RelativeSource="{RelativeSource AncestorType=ContextMenu}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</MenuItem>
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.RemoveFromGroup}"
Command="{Binding Path=RemoveGroupCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
<MenuItem Header="{Tr MainWindow.ContextMenus.Mafile.CopyPassword}"
Command="{Binding Path=CopyPasswordCommand}"
CommandParameter="{Binding Path=PlacementTarget.SelectedValue, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
</FrameworkElement.ContextMenu>
</ListBox>
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10"
md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<TextBlock TextWrapping="WrapWithOverflow" FontSize="16"
Text="{Tr MainWindow.Global.StartTip}" />
</Border>
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
md:TextFieldAssist.HasClearButton="True" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1" Margin="10,5,10,10"
md:HintAssist.Hint="{Tr MainWindow.LeftPart.SearchBoxHint}"
Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<md:Card BorderThickness="1" Style="{StaticResource MaterialDesignOutlinedCard}" Grid.Column="1"
Margin="10,10,15,10" UniformCornerRadius="12" Opacity="{Binding Settings.RightOpacity}">
<md:Card Grid.Column="1" Margin="10,10,15,10" UniformCornerRadius="15">
<Control.Background>
<SolidColorBrush Color="#FF1A1D25" Opacity="0.6" />
</Control.Background>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="115*" />
<RowDefinition Height="436*" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Row="0">
@@ -369,50 +334,47 @@
</Grid.RowDefinitions>
<TextBox w:FontScaleWindow.Scale="1.1" w:FontScaleWindow.ResizeFont="True"
IsReadOnly="True" HorizontalContentAlignment="Center" Background="#00FFFFFF"
Style="{StaticResource MaterialDesignTextBox}"
Style="{StaticResource MaterialDesignFilledTextBox}"
Text="{Binding Code, FallbackValue=Code}">
<TextBox.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding CopyCodeCommand}" />
</TextBox.InputBindings>
</TextBox>
<controls:CodeProgressBar
Visibility="{Binding SelectedMafile, Converter={StaticResource NullableToVisibilityConverter}}"
Grid.Row="1" Height="4" Style="{StaticResource MaterialDesignLinearProgressBar}"
MaxTime="30" TimeRemaining="{Binding CodeProgress, Mode=OneWay}" />
<Grid Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ProgressBar Margin="5" Foreground="#FF9932CC" Height="15"
md:TransitionAssist.DisableTransitions="True"
Value="{Binding CodeProgress}" />
</Grid>
</Grid>
<Button IsEnabled="{Binding IsMafileSelected}" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Grid.Row="1"
Style="{StaticResource MaterialDesignOutlinedButton}" Margin="0,10,0,10"
HorizontalAlignment="Center"
Content="{Tr MainWindow.RightPart.LoadConfirmations}"
Style="{StaticResource MaterialDesignOutlinedButton}" Margin="10"
Command="{Binding GetConfirmationsCommand}"
Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}" />
Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}">
<TextBlock TextWrapping="Wrap" TextTrimming="WordEllipsis"
Text="{Tr MainWindow.RightPart.LoadConfirmations}" />
</Button>
<ItemsControl md:RippleAssist.IsDisabled="True" Focusable="False" Grid.Row="2"
w:FontScaleWindow.Scale="0.72" w:FontScaleWindow.ResizeFont="True"
Margin="10,10,10,10"
Margin="10"
Visibility="{Binding ConfirmationsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
ItemsSource="{Binding Confirmations}" Grid.RowSpan="2" />
<Button Style="{StaticResource MaterialDesignFlatButton}" Grid.Row="4"
w:FontScaleWindow.Scale="0.8" w:FontScaleWindow.ResizeFont="True"
Command="{Binding ConfirmLoginCommand}"
ItemsSource="{Binding Confirmations}" />
<Button Grid.Row="3" Margin="1,0,1,3" w:FontScaleWindow.Scale="0.8"
w:FontScaleWindow.ResizeFont="True" Command="{Binding ConfirmLoginCommand}"
Content="{Tr MainWindow.RightPart.ConfirmLogin}" />
</Grid>
</md:Card>
</Grid>
<Border Grid.Row="2" BorderBrush="#1e1e24">
<Border Grid.Row="2" BorderBrush="#FF696969">
<Border.Background>
<SolidColorBrush Opacity="1" Color="{DynamicResource Base300Color}" />
<SolidColorBrush Opacity="0.5" Color="DimGray" />
</Border.Background>
<Grid>
<ToolBarPanel TextElement.Foreground="{DynamicResource SecondaryContentBrush}"
Orientation="Horizontal" Margin="5" w:FontScaleWindow.Scale="0.73"
<ToolBarPanel Orientation="Horizontal" Margin="5" w:FontScaleWindow.Scale="0.73"
w:FontScaleWindow.ResizeFont="True">
<TextBlock FontWeight="Bold" Text="{Tr MainWindow.Footer.Account}" />
<TextBlock Text="{Binding SelectedMafile.AccountName}" />
@@ -420,21 +382,19 @@
<TextBlock FontWeight="Bold" Text="{Tr MainWindow.Footer.Group}" />
<TextBlock FontWeight="Normal"
Text="{Binding SelectedMafile.Group, TargetNullValue=' ', FallbackValue=' ', Mode=OneWay}" />
<!--<Button Command="{Binding DebugCommand}">Debug</Button>-->
</ToolBarPanel>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Right" w:FontScaleWindow.Scale="0.7"
w:FontScaleWindow.ResizeFont="True" Margin="0,0,10,0">
<Hyperlink
NavigateUri="https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies"
Foreground="{DynamicResource AccentBrush}"
Command="{Binding OpenLinksViewCommand}">
Foreground="{DynamicResource PrimaryHueMidBrush}"
RequestNavigate="Hyperlink_OnRequestNavigate">
by achies
</Hyperlink>
</TextBlock>
</Grid>
</Border>
<md:Snackbar Grid.Row="1" MessageQueue="{Binding MessageQueue}" />
<md:Snackbar Grid.Row="1" FontSize="20" MessageQueue="{Binding MessageQueue}" />
</Grid>
</md:DialogHost>
</Border>
@@ -1,8 +1,10 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
@@ -28,13 +30,10 @@ public partial class MainWindow
private async void OnApplicationStarted(object? sender, EventArgs e)
{
((MainVM) DataContext).CurrentDialogHost = DialogHostInstance;
if (Settings.Instance.IsPasswordSet == false) return;
Topmost = false;
await Dispatcher.InvokeAsync(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
await Dispatcher.BeginInvoke(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
}
private async Task ShowSetPasswordDialog()
{
var vm = new SetEncryptPasswordVM();
@@ -42,7 +41,6 @@ public partial class MainWindow
{
DataContext = vm
};
var result = await DialogHost.Show(dialog);
var pass = vm.Password;
if (result is true && string.IsNullOrWhiteSpace(pass) == false)
@@ -51,6 +49,15 @@ public partial class MainWindow
}
}
private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.ToString())
{
UseShellExecute = true
});
}
#region Dran'n'Drop
private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
@@ -2,7 +2,7 @@
using NebulaAuth.Model.MAAC;
using Newtonsoft.Json;
using SteamLib;
using SteamLibForked.Models.Session;
using SteamLib.Account;
namespace NebulaAuth.Model.Entities;
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using AchiesUtilities.Extensions;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NLog;
namespace NebulaAuth.Model.MAAC;
@@ -15,8 +16,6 @@ public static class MultiAccountAutoConfirmer
{
private const string LOC_PATH = "MAAC";
private static readonly ReaderWriterLockSlim Lock = new();
private static readonly SemaphoreSlim ExecutionLock = new(1, 1);
public static ObservableCollection<Mafile> Clients { get; }
private static Timer Timer { get; }
@@ -28,10 +27,12 @@ public static class MultiAccountAutoConfirmer
UpdateTimer();
}
private static readonly SemaphoreSlim ExecutionLock = new(1, 1);
// ReSharper disable once AsyncVoidMethod //Already safe
private static async void TimerConfirm(object? state)
{
var isHeld = false;
bool isHeld = false;
try
{
isHeld = await ExecutionLock.WaitAsync(0);
@@ -40,8 +41,8 @@ public static class MultiAccountAutoConfirmer
SnackbarController.SendSnackbar(GetLocalization("TimerPreventedOverlap"));
return;
}
await TimerConfirmInternal();
}
catch (Exception e)
{
@@ -59,7 +60,7 @@ public static class MultiAccountAutoConfirmer
private static async Task TimerConfirmInternal()
{
var clients = Lock.ReadLock(() => Clients.ToArray());
var enabledClients = clients.Where(x => x.LinkedClient is {IsError: false}).ToArray();
var enabledClients = clients.Where(x => x.LinkedClient is { IsError: false }).ToArray();
enabledClients = DistributeEvenly(enabledClients).ToArray();
var confirmed = 0;
await Task.Run(async () =>
@@ -14,10 +14,10 @@ using NebulaAuth.Model.Entities;
using NebulaAuth.Utility;
using SteamLib.Api.Mobile;
using SteamLib.Authentication;
using SteamLib.Exceptions.Authorization;
using SteamLib.Core.Interfaces;
using SteamLib.Exceptions;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
using SteamLibForked.Abstractions;
namespace NebulaAuth.Model.MAAC;
@@ -7,9 +7,9 @@ using AchiesUtilities.Web.Models;
using AchiesUtilities.Web.Proxy;
using NebulaAuth.Model.Entities;
using SteamLib.Api.Mobile;
using SteamLib.Api.Services;
using SteamLib.Authentication;
using SteamLib.Exceptions.Authorization;
using SteamLib.Core.Interfaces;
using SteamLib.Exceptions;
using SteamLib.ProtoCore.Services;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
@@ -26,7 +26,6 @@ public static class MaClient
public static ProxyData? DefaultProxy { get; set; }
static MaClient()
{
Proxy = new DynamicProxy();
@@ -63,7 +62,7 @@ public static class MaClient
return SteamMobileConfirmationsApi.GetConfirmations(Client, mafile, mafile.SessionData!.SteamId);
}
public static Task LoginAgain(Mafile mafile, string password, bool savePassword)
public static Task LoginAgain(Mafile mafile, string password, bool savePassword, ICaptchaResolver? resolver)
{
SetProxy(mafile);
return SessionHandler.LoginAgain(new HttpClientHandlerPair(Client, ClientHandler), mafile, password,
@@ -138,7 +137,7 @@ public static class MaClient
ValidateMafile(mafile);
SetProxy(mafile);
var token = mafile.SessionData!.GetMobileToken()!.Value;
var sessions = await AuthenticationServiceApi.GetAuthSessionsForAccount(Client, token.Token);
var sessions = await SteamMobileAuthenticatorApi.GetAuthSessionsForAccount(Client, token.Token);
if (sessions.ClientIds.Count == 0)
{
@@ -157,11 +156,16 @@ public static class MaClient
}
var clientId = sessions.ClientIds.Single();
var clientInfo = await AuthenticationServiceApi.GetAuthSessionInfo(Client, token.Token, clientId);
var updateReq =
AuthRequestHelper.CreateMobileConfirmationRequest(1, clientId, mafile.SessionData.SteamId.Steam64,
mafile.SharedSecret);
await AuthenticationServiceApi.UpdateAuthSessionWithMobileConfirmation(Client, token.Token, updateReq);
var clientInfo = await SteamMobileAuthenticatorApi.GetAuthSessionInfo(Client, token.Token, clientId);
var updateReq = new UpdateAuthSessionWithMobileConfirmation_Request
{
ClientId = clientId,
Confirm = true,
Persistence = 1,
Steamid = mafile.SessionData.SteamId.Steam64.ToUlong(),
Version = 1
};
await SteamMobileAuthenticatorApi.UpdateAuthSessionStatus(Client, token.Token, mafile.SharedSecret, updateReq);
return new LoginConfirmationResult
{
Country = clientInfo.Country,
@@ -22,11 +22,6 @@ public static class NebulaSerializer
AllowDeviceIdGeneration = true,
AllowSessionIdGeneration = true,
ThrowIfInvalidSteamId = false
},
SerializationOptions =
{
Sign = true,
Formatting = Formatting.Indented
}
});
}
@@ -85,9 +80,9 @@ public static class NebulaSerializer
{
if (Settings.Instance.LegacyMode)
{
return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
return MafileSerializer.SerializeLegacy(data, Formatting.Indented, properties);
}
return Serializer.Serialize(data);
return MafileSerializer.Serialize(data);
}
}
@@ -7,7 +7,7 @@ using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NebulaAuth.View.Dialogs;
using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions;
namespace NebulaAuth.Model;
@@ -1,13 +1,12 @@
using System.Threading.Tasks;
using AchiesUtilities.Web.Models;
using NebulaAuth.Model.Entities;
using SteamLib.Account;
using SteamLib.Api.Mobile;
using SteamLib.Authentication;
using SteamLib.Authentication.LoginV2;
using SteamLib.Exceptions.Authorization;
using SteamLib.Factory.Helpers;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
using SteamLibForked.Models.Session;
namespace NebulaAuth.Model;
@@ -36,11 +35,11 @@ public partial class SessionHandler //API
public static async Task LoginAgain(HttpClientHandlerPair chp, Mafile mafile, string password, bool savePassword)
{
var sgGenerator = new SteamGuardCodeGenerator(mafile.SharedSecret);
var options = new LoginV2ExecutorOptions(StaticLoginConsumer.Instance, chp.Client)
var options = new LoginV2ExecutorOptions(LoginV2Executor.NullConsumer, chp.Client)
{
Logger = Shell.ExtensionsLogger,
AuthProviders = [sgGenerator],
DeviceDetails = DeviceDetailsDefaultBuilder.GetMobileDefaultDevice(),
SteamGuardProvider = sgGenerator,
DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
WebsiteId = "Mobile"
};
chp.Handler.CookieContainer.ClearMobileSessionCookies();
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows.Media;
@@ -13,15 +12,6 @@ public partial class Settings : ObservableObject
{
public static Settings Instance { get; }
private static IReadOnlyDictionary<ThemeType, string> ThemeNames { get; } = new Dictionary<ThemeType, string>
{
{ThemeType.Default, "DefaultTheme"},
{ThemeType.Light, "LightTheme"},
{ThemeType.Black, "BlackTheme"},
{ThemeType.Luxury, "LuxuryTheme"},
{ThemeType.Shadcn, "ShadcnTheme"}
};
static Settings()
{
if (File.Exists("settings.json") == false)
@@ -50,10 +40,6 @@ public partial class Settings : ObservableObject
private static void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
Save();
if (e.PropertyName == nameof(ThemeType))
{
ThemeManager.ApplyTheme(ThemeNames[Instance.ThemeType]);
}
}
public static void Save()
@@ -62,27 +48,12 @@ public partial class Settings : ObservableObject
File.WriteAllText("settings.json", json);
}
public static void ResetThemeDefaults()
{
Instance.BackgroundBlur = 0.0;
Instance.BackgroundOpacity = 1.0;
Instance.BackgroundGamma = 0.0;
Instance.LeftOpacity = 0.4;
Instance.RightOpacity = 0.8;
Instance.ApplyBlurBackground = true;
Save();
}
public string GetTheme()
{
return ThemeNames.TryGetValue(ThemeType, out var themeName) ? themeName : ThemeNames[ThemeType.Default];
}
#region Properties
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
[ObservableProperty] private bool _hideToTray;
[ObservableProperty] private int _timerSeconds = 60;
[ObservableProperty] private Color? _backgroundColor;
[ObservableProperty] private Color? _iconColor;
[ObservableProperty] private bool _isPasswordSet;
[ObservableProperty] private LocalizationLanguage _language = LocalizationLanguage.English;
@@ -91,15 +62,6 @@ public partial class Settings : ObservableObject
[ObservableProperty] private bool _useAccountNameAsMafileName;
[ObservableProperty] private bool _ignorePatchTuesdayErrors;
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
[ObservableProperty] private double _leftOpacity = 0.4;
[ObservableProperty] private double _rightOpacity = 1.0;
[ObservableProperty] private double _backgroundBlur;
[ObservableProperty] private double _backgroundOpacity = 1;
[ObservableProperty] private double _backgroundGamma;
[ObservableProperty] private bool _applyBlurBackground = true;
[ObservableProperty] private ThemeType _themeType = ThemeType.Default;
#endregion
}
@@ -108,13 +70,4 @@ public enum BackgroundMode
Default,
Custom,
Color
}
public enum ThemeType
{
Default = 0,
Black = 1,
Light = 2,
Luxury = 3,
Shadcn = 4
}
@@ -11,12 +11,11 @@ namespace NebulaAuth.Model;
public static class Shell
{
public static Logger Logger { get; private set; } = null!;
public static Logger Logger { get; } = LogManager.GetLogger("Logger");
public static ILogger ExtensionsLogger { get; private set; } = null!;
public static void Initialize()
{
Logger = LogManager.GetLogger("Logger");
var lp = new NLogLoggerProvider();
var logger = lp.CreateLogger("SteamLib");
SteamLibErrorMonitor.MonitorLogger = logger;
@@ -1,84 +1,71 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AchiesUtilities.Extensions;
using NebulaAuth.Model.Entities;
using NebulaAuth.Model.Exceptions;
using SteamLib;
using SteamLib.Exceptions.Authorization;
using SteamLib.Core.Models;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
namespace NebulaAuth.Model;
//RETHINK
public static class Storage
{
public const string MAFILE_F = "maFiles";
public const string REMOVED_F = "maFiles_removed";
private static int _duplicateFound;
public static int DuplicateFound => _duplicateFound;
public static readonly int DuplicateFound;
public static string MafileFolder { get; } = Path.GetFullPath(MAFILE_F);
public static string RemovedMafileFolder { get; } = Path.GetFullPath(REMOVED_F);
public static ObservableCollection<Mafile> MaFiles { get; private set; } = new();
public static ObservableCollection<Mafile> MaFiles { get; } = new();
static Storage()
{
}
public static async Task Initialize(int threadCount, CancellationToken token = default)
{
if (!Directory.Exists(MafileFolder))
Directory.CreateDirectory(MafileFolder);
if (!Directory.Exists(RemovedMafileFolder))
Directory.CreateDirectory(RemovedMafileFolder);
var comparer = new MafileNameComparer(Settings.Instance.UseAccountNameAsMafileName);
var files = Directory
.GetFiles(MafileFolder)
.Where(file => Path.GetExtension(file).EqualsIgnoreCase(".mafile"))
.Order(comparer)
.ToList();
var hashNames = new ConcurrentDictionary<string, byte>();
var hashIds = new ConcurrentDictionary<SteamId, byte>();
var localList = new ConcurrentBag<Mafile>();
var processed = 0;
await Task.Run(() =>
if (Directory.Exists(MafileFolder) == false)
{
return Parallel.ForEachAsync(files,
new ParallelOptions {CancellationToken = token, MaxDegreeOfParallelism = threadCount},
async (file, ct) =>
Directory.CreateDirectory(MafileFolder);
}
if (Directory.Exists(RemovedMafileFolder) == false)
{
Directory.CreateDirectory(RemovedMafileFolder);
}
var files = Directory.GetFiles(MafileFolder);
var hashNames = new HashSet<string>();
var hashIds = new HashSet<SteamId>();
var comparer = new MafileNameComparer(Settings.Instance.UseAccountNameAsMafileName);
var ordered = files.Order(comparer).ToList();
foreach (var file in ordered.Where(file => Path.GetExtension(file).EqualsIgnoreCase(".mafile")))
{
try
{
var data = ReadMafile(file);
if (hashNames.Contains(data.AccountName) || hashIds.Contains(data.SteamId))
{
try
{
var data = await ReadMafileAsync(file);
DuplicateFound++;
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
continue;
}
if (!hashNames.TryAdd(data.AccountName, 0) ||
(data.SessionData != null && !hashIds.TryAdd(data.SteamId, 0)))
{
Interlocked.Increment(ref _duplicateFound);
Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
}
hashNames.Add(data.AccountName);
if (data.SessionData != null) hashIds.Add(data.SteamId);
MaFiles.Add(data);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
}
}
localList.Add(data);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
}
});
}, token);
MaFiles = new ObservableCollection<Mafile>(localList.OrderBy(m => m.AccountName));
MaFiles = new ObservableCollection<Mafile>(MaFiles.OrderBy(m => m.AccountName));
}
/// <summary>
@@ -130,12 +117,6 @@ public static class Storage
return NebulaSerializer.Deserialize(str);
}
public static async Task<Mafile> ReadMafileAsync(string path)
{
var str = await File.ReadAllTextAsync(path);
return NebulaSerializer.Deserialize(str);
}
public static void SaveMafile(Mafile data)
{
var path = CreatePathForMafile(data);
@@ -221,35 +202,9 @@ public static class Storage
return null;
}
public static void BackupHandler(MobileDataExtended data)
{
if (Directory.Exists("mafiles_backup") == false)
{
Directory.CreateDirectory("mafiles_backup");
}
var json = NebulaSerializer.SerializeMafile(data, null);
File.WriteAllText(Path.Combine("mafiles_backup", data.AccountName + ".mafile"),
json);
}
public static void BackupHandlerStr(string accountName, string data)
{
if (Directory.Exists("mafiles_backup") == false)
{
Directory.CreateDirectory("mafiles_backup");
}
File.WriteAllText(Path.Combine("mafiles_backup", accountName + ".mafile"),
data);
}
}
//TODO: Refactor
//TODO: use numeric orderer when .net 10 released
internal class MafileNameComparer : IComparer<string>
{
private const string MAF_64_START = "765";
@@ -16,6 +16,7 @@
</layout>
<layout type='SimpleLayout' text="," />
</layout>
</target>
</targets>
+68
View File
@@ -0,0 +1,68 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>latest</LangVersion>
<SatelliteResourceLanguages>en;ru;ua</SatelliteResourceLanguages>
<ApplicationIcon>Theme\lock.ico</ApplicationIcon>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
<AssemblyVersion>1.5.7</AssemblyVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<None Remove="Theme\1140x641.jpg" />
<None Remove="Theme\Background.jpg" />
<None Remove="Theme\lock.ico" />
<None Remove="Theme\SplashScreen.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autoupdater.NET.Official" Version="1.9.2" />
<PackageReference Include="CodingSeb.Localization.JsonFileLoader" Version="1.3.1" />
<PackageReference Include="CodingSeb.Localization.WPF" Version="1.3.3" />
<PackageReference Include="CodingSebLocalization.Fody" Version="1.3.1" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="MaterialDesignColors" Version="2.1.4" />
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.122" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.14" />
</ItemGroup>
<ItemGroup>
<Resource Include="Theme\Background.jpg">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Resource>
<Resource Include="Theme\lock.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SteamLibForked\SteamLibForked.csproj" />
</ItemGroup>
<ItemGroup>
<SplashScreen Include="Theme\SplashScreen.png" />
</ItemGroup>
<ItemGroup>
<Compile Update="View\Dialogs\LoginAgainOnImportDialog.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="localization.loc.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -6,8 +6,4 @@
• Добавить запоминание пароля при привязке мафайла
• Функция переноса гуарда с мобильного устройства на ПК с созданием мафайла
• Добавить полное шифрование мафайлов по аналогии с SDA
• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
• Антик-окно как в MarketApp, возможность сразу открыть браузер напр. на CefSharp с залогиненым аккаунтом
• Стабильность авто-подтверждений, возможность задать пользователю порог времени когда льются ошибки и только тогда выключать авто-подтверждение
• Безопасное сохранение мафайлов через .tmp / .bak
• Создание механизма накопления ошибок, чтобы исправить Patch Tuesday, условно аккаунт может игнорировать ошибки 1-2 часа (настриавемо)
• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке

Before

Width:  |  Height:  |  Size: 713 KiB

After

Width:  |  Height:  |  Size: 713 KiB

+9
View File
@@ -0,0 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!--Card-->
<SolidColorBrush x:Key="MaterialDesignCardBackground" Color="#26292E" />
<SolidColorBrush x:Key="PrimaryHueMidBrush" Color="#FF9056B1" />
<SolidColorBrush x:Key="PrimaryHueLightBrush" Color="#FF9C70B5" />
<SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="#FF851BC1" />
</ResourceDictionary>
Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

@@ -17,8 +17,7 @@
Margin="{x:Static local:WindowChromeHelper.LayoutOffsetThickness}"
BorderBrush="Transparent"
BorderThickness="1"
Background="{DynamicResource Base200Brush}">
Background="{DynamicResource WindowBackground}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@@ -27,12 +26,11 @@
<Grid x:Name="TitleBar"
Grid.Row="0"
Height="28"
Background="{DynamicResource Base300Brush}">
Background="{DynamicResource WindowBackground}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}"
Foreground="{DynamicResource PrimaryHueMidBrush}"
Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}"
FontSize="17" />
<!-- Window Buttons -->
<StackPanel
HorizontalAlignment="Right"
@@ -61,7 +59,7 @@
<!-- Main Window Content -->
<Grid x:Name="MainGrid"
Grid.Row="1"
Background="{DynamicResource Base200Brush}">
Background="{DynamicResource MainBackgroundBrush}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

@@ -1,8 +1,8 @@
using CodingSeb.Localization;
using NebulaAuth.Core;
using SteamLib.Core.StatusCodes;
using SteamLib.Exceptions;
using SteamLib.Exceptions.Mobile;
using SteamLibForked.Exceptions.Authorization;
using SteamLib.ProtoCore.Enums;
namespace NebulaAuth.Utility;
@@ -14,10 +14,11 @@ public static class ErrorTranslatorHelper
return result ?? error.ToString();
}
public static string TranslateSteamStatusCode(SteamStatusCode statusCode)
public static string TranslateEResult(EResult eResult)
{
var result = GetMessage("EResult", statusCode.Name);
return result ?? statusCode.ToString();
var result = GetMessage("EResult", eResult.ToString());
return result ?? eResult.ToString();
}
public static string TranslateLinkerError(AuthenticatorLinkerError error)
@@ -4,9 +4,8 @@ using System.Threading.Tasks;
using NebulaAuth.Core;
using NebulaAuth.Model;
using SteamLib.Exceptions;
using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions.General;
using SteamLibForked.Exceptions.Authorization;
using SteamLib.ProtoCore.Exceptions;
namespace NebulaAuth.Utility;
@@ -17,58 +16,53 @@ public static class ExceptionHandler
public static bool Handle(Exception ex, string? prefix = null, string? postfix = null,
bool handleAllExceptions = false)
{
string msg;
Shell.Logger.Error(ex);
var msg = GetExceptionString(ex, handleAllExceptions);
if (msg == null) return false;
SnackbarController.SendSnackbar(prefix + msg + postfix);
return true;
}
public static string? GetExceptionString(Exception exception, bool handleAllExceptions = true)
{
switch (exception)
switch (ex)
{
case SessionPermanentlyExpiredException:
{
return "SessionExpiredException".GetCodeBehindLocalization();
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
case SessionInvalidException:
{
return "SessionExpiredException".GetCodeBehindLocalization();
msg = "SessionExpiredException".GetCodeBehindLocalization();
break;
}
case TaskCanceledException e:
{
return e.InnerException is TimeoutException
msg = e.InnerException is TimeoutException
? "TimeoutException".GetCodeBehindLocalization()
: "TaskCanceledException".GetCodeBehindLocalization();
break;
}
case HttpRequestException e:
{
var str = "RequestError".GetCommonLocalization() + ": ";
if (e.StatusCode != null)
{
str = str + e.StatusCode;
msg = str + e.StatusCode;
}
else if (e.InnerException != null)
{
str = str + e.InnerException.Message;
msg = str + e.InnerException.Message;
}
else
{
str = str + e.Message;
msg = str + e.Message;
}
return str;
break;
}
case UnsupportedResponseException:
{
return "UnsupportedResponseException".GetCodeBehindLocalization();
msg = "UnsupportedResponseException".GetCodeBehindLocalization();
break;
}
case CantLoadConfirmationsException e:
{
var msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), "Common");
if (e.Error == LoadConfirmationsError.Unknown)
{
@@ -82,25 +76,30 @@ public static class ExceptionHandler
nameof(CantLoadConfirmationsException), e.Error.ToString());
}
return msg;
break;
}
case SteamStatusCodeException e:
case EResultException e:
{
return "Error".GetCommonLocalization() + ": " +
ErrorTranslatorHelper.TranslateSteamStatusCode(e.StatusCode);
msg = "Error".GetCommonLocalization() + ": " + ErrorTranslatorHelper.TranslateEResult(e.Result);
break;
}
case LoginException e:
{
return "LoginException".GetCodeBehindLocalization() + ": " +
ErrorTranslatorHelper.TranslateLoginError(e.Error);
msg = "LoginException".GetCodeBehindLocalization() + ": " +
ErrorTranslatorHelper.TranslateLoginError(e.Error);
break;
}
case not null when handleAllExceptions:
{
return "UnknownException".GetCodeBehindLocalization() + exception.Message;
msg = "UnknownException".GetCodeBehindLocalization() + ex.Message;
break;
}
default:
return false;
}
return null;
SnackbarController.SendSnackbar(prefix + msg + postfix);
return true;
}
private static string GetCommonLocalization(this string key)
@@ -0,0 +1,48 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.LoginAgainDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
mc:Ignorable="d"
theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True"
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0"
HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding UserName}" />
</TextBlock>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<CheckBox Grid.Row="2" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
<Grid Grid.Row="3" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button IsDefault="True" IsEnabled="{Binding IsFormValid}" Margin="0,0,5,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}" />
<Button IsCancel="True" Grid.Column="1" Margin="5,0,0,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}" />
</Grid>
</Grid>
</UserControl>
@@ -0,0 +1,65 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.LoginAgainOnImportDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
xmlns:model="clr-namespace:NebulaAuth.Model"
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
mc:Ignorable="d"
theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True"
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainOnImportVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock theme:FontScaleWindow.Scale="0.9" theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0"
HorizontalAlignment="Left">
<Run Text="{Tr LoginAgainDialog.LoginFor, IsDynamic=False}" />
<Run FontWeight="Bold" Text="{Binding UserName}" />
</TextBlock>
<TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,0" Grid.Row="1"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
materialDesign:HintAssist.Hint="{Tr LoginAgainDialog.PasswordBox}" />
<ComboBox ToolTip="{Tr LoginAgainDialog.ProxyToolTip}" Grid.Row="2" Margin="10,18,10,0"
materialDesign:HintAssist.Hint="{Tr Common.Proxy}" ItemsSource="{Binding Proxies}"
SelectedItem="{Binding SelectedProxy}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type entities:MaProxy}">
<TextBlock Text="{Binding Converter={StaticResource ProxyTextConverter}, Mode=OneWay}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<UIElement.InputBindings>
<KeyBinding Key="Delete" Command="{Binding RemoveProxyCommand}" />
</UIElement.InputBindings>
</ComboBox>
<CheckBox Grid.Row="3" Margin="10,10,10,0" IsEnabled="{Binding Source={x:Static model:PHandler.IsPasswordSet}}"
IsChecked="{Binding SavePassword}" Content="{Tr LoginAgainDialog.SaveEncryptedPassword}" />
<CheckBox Grid.Row="4" Margin="10,10,10,0" IsEnabled="{Binding MafileHasProxy}"
Content="{Tr LoginAgainDialog.UseMafileProxy}" IsChecked="{Binding UseMafileProxy}" />
<Grid Grid.Row="5" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button IsEnabled="{Binding IsFormValid}" IsDefault="True" Margin="0,5,5,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource True}" Content="{Tr LoginAgainDialog.LoginButton}" />
<Button IsCancel="True" Grid.Column="1" Margin="5,5,0,5"
Style="{StaticResource MaterialDesignOutlinedButton}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
CommandParameter="{StaticResource False}" Content="{Tr LoginAgainDialog.CancelButton}" />
</Grid>
</Grid>
</UserControl>
@@ -1,4 +1,4 @@
<UserControl x:Class="NebulaAuth.View.Dialogs.SetCryptPasswordDialog"
<UserControl x:Class="NebulaAuth.View.Dialogs.SetCryptPasswordDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@@ -7,46 +7,25 @@
xmlns:theme="clr-namespace:NebulaAuth.Theme"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance other:LoginAgainVM}">
Foreground="WhiteSmoke"
d:DataContext="{d:DesignInstance other:LoginAgainVM}"
Background="{DynamicResource WindowBackground}">
<Grid MinHeight="100" MinWidth="300" MaxWidth="400">
<Grid MinHeight="100" MinWidth="300" MaxWidth="400" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Encryption" Width="20" Height="20" Margin="0,0,5,0"
VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr SetEncryptedPasswordDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" CommandParameter="{StaticResource False}"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Opacity="0.7" />
<TextBlock Grid.Row="2" IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
<TextBlock IsHitTestVisible="False" TextWrapping="Wrap" FontWeight="Normal"
Text="{Tr SetEncryptedPasswordDialog.DialogText}" theme:FontScaleWindow.Scale="0.8"
theme:FontScaleWindow.ResizeFont="True" Margin="10" HorizontalAlignment="Left" />
theme:FontScaleWindow.ResizeFont="True" Margin="10,0,0,0" HorizontalAlignment="Left" />
<PasswordBox FontSize="16"
materialDesign:PasswordBoxAssist.Password="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
Margin="10" Grid.Row="3" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
Margin="10" Grid.Row="1" Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SetEncryptedPasswordDialog.Password}" />
<Grid Grid.Row="4" Margin="10">
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
@@ -0,0 +1,71 @@
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using SteamLib.Core.Interfaces;
using SteamLib.Exceptions;
namespace NebulaAuth.View.Dialogs;
/// <summary>
/// Логика взаимодействия для WaitLoginDialog.xaml
/// </summary>
public partial class WaitLoginDialog : ICaptchaResolver
{
private TaskCompletionSource<string> _tcs = new();
public WaitLoginDialog()
{
InitializeComponent();
}
public async Task<string> Resolve(Uri imageUrl, HttpClient client)
{
CaptchaGrid.Visibility = Visibility.Visible;
var stream = await client.GetStreamAsync(imageUrl);
return await Application.Current.Dispatcher.Invoke(async () =>
{
var image = await LoadImage(stream);
CaptchaImage.Source = image;
try
{
return await _tcs.Task;
}
catch (TaskCanceledException)
{
throw new LoginException(LoginError.CaptchaRequired);
}
});
}
private async Task<BitmapImage> LoadImage(Stream stream)
{
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
ms.Position = 0;
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
await stream.DisposeAsync();
return image;
}
private void CancelButton_OnClick(object sender, RoutedEventArgs e)
{
_tcs.SetCanceled();
}
private void SendCaptchaBtn_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(CaptchaTB.Text)) return;
var oldTcs = _tcs;
_tcs = new TaskCompletionSource<string>();
oldTcs.SetResult(CaptchaTB.Text);
}
}
+166
View File
@@ -0,0 +1,166 @@
<UserControl x:Class="NebulaAuth.View.LinkerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
Foreground="WhiteSmoke"
FontFamily="{materialDesign:MaterialDesignFont}"
MinHeight="640"
MinWidth="400"
Background="{DynamicResource WindowBackground}"
d:DataContext="{d:DesignInstance other:LinkAccountVM}"
FontSize="18">
<d:DesignerProperties.DesignStyle>
<Style TargetType="UserControl">
<Setter Property="Background" Value="{DynamicResource WindowBackground}" />
</Style>
</d:DesignerProperties.DesignStyle>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="materialDesign:PackIcon">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="False">
<Setter Property="Foreground" Value="IndianRed" />
<Setter Property="Kind" Value="CheckBoxOutlineBlank" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="True">
<Setter Property="Foreground" Value="Green" />
<Setter Property="Kind" Value="CheckBoxOutline" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=Tag}"
Value="True">
<Setter Property="Foreground" Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr LinkerDialog.Title}" />
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="12">
<Hyperlink Command="{Binding OpenTroubleshootingCommand}">
<Run Text="{Tr LinkerDialog.GotErrorHyperlinkText, IsDynamic=False}" />
</Hyperlink>
</TextBlock>
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Background="DarkGray" Grid.Row="1" />
<Grid Grid.Row="2" Margin="10,20,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Padding="10" FontSize="16" Style="{StaticResource MaterialDesignOutlinedComboBox}"
SelectedValue="{Binding SelectedProxy}" ItemsSource="{Binding Proxies}"
materialDesign:HintAssist.Hint="{Tr LinkerDialog.Proxy}"
IsEnabled="{Binding IsPasswordFieldVisible}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Key, Mode=OneWay}" /><Run Text=":" />
<Run Text="{Binding Value.Address, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="1" IsEnabled="{Binding IsPasswordFieldVisible}" Margin="5,0,0,0"
Command="{Binding ResetProxyCommand}" Content="{materialDesign:PackIcon Trash}" />
</Grid>
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="7" Tag="{Binding IsLogin}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Authorization}" />
</StackPanel>
<StackPanel Grid.Row="4" Orientation="Horizontal" Margin="7" Tag="{Binding IsEmailCode}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailCode}" />
</StackPanel>
<StackPanel Grid.Row="5" Orientation="Horizontal" Margin="7" Tag="{Binding IsPhoneNumber}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.PhoneNumber}" />
</StackPanel>
<StackPanel Grid.Row="6" Orientation="Horizontal" Margin="7" Tag="{Binding IsEmailConfirmation}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.EmailLink}" />
</StackPanel>
<StackPanel Grid.Row="7" Orientation="Horizontal" Margin="7" Tag="{Binding IsLinkCode}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.SmsOrCode}" />
</StackPanel>
<StackPanel Grid.Row="8" Orientation="Horizontal" Margin="7" Tag="{Binding IsCompleted}">
<materialDesign:PackIcon Width="20" Height="20" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock FontSize="16" Text="{Tr LinkerDialog.Completed}" />
</StackPanel>
<Grid Grid.Row="9" Margin="10,20,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Padding="7" Text="{Binding FieldText}"
Visibility="{Binding IsFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16" Margin="0,0,0,10" />
<TextBox Grid.Row="1" Padding="7" Text="{Binding PassFieldText}"
Visibility="{Binding IsPasswordFieldVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
Style="{StaticResource MaterialDesignOutlinedTextBox}" FontSize="16" />
<GroupBox Grid.Row="2" MaxWidth="400" BorderBrush="{StaticResource PrimaryHueMidBrush}"
VerticalAlignment="Bottom" BorderThickness="1" Margin="0,10,0,0" Padding="5">
<GroupBox.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Tr LinkerDialog.Message}" FontSize="16" Foreground="GhostWhite" />
</DataTemplate>
</GroupBox.HeaderTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Foreground="GhostWhite" FontSize="16" Text="{Binding HintText}"
HorizontalAlignment="Stretch" TextWrapping="Wrap" />
<Button Command="{Binding CopyCodeCommand}"
Visibility="{Binding IsCompleted, Converter={StaticResource BooleanToVisibilityConverter}}"
Grid.Row="1">
<materialDesign:PackIcon Kind="ContentCopy" />
</Button>
</Grid>
</GroupBox>
</Grid>
<Button Grid.Row="10" Height="35" FontSize="17" Command="{Binding ProceedCommand}"
Content="{Tr LinkerDialog.ProceedButton}" />
</Grid>
</UserControl>
@@ -7,12 +7,13 @@
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="400"
Foreground="WhiteSmoke"
FontFamily="{md:MaterialDesignFont}"
MinHeight="500"
MinWidth="400"
MaxHeight="550"
d:DataContext="{d:DesignInstance other:ProxyManagerVM}"
Background="Transparent">
Background="{DynamicResource WindowBackground}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@@ -21,23 +22,19 @@
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="10,10,10,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="Proxy" Width="20" Height="20" Margin="0,0,5,0" VerticalAlignment="Center"
Foreground="{DynamicResource PrimaryContentBrush}" />
<TextBlock FontStyle="Normal" Foreground="{DynamicResource BaseContentBrush}"
HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr ProxyManagerDialog.Title}" />
</StackPanel>
<Button Grid.Column="1" Width="30" Height="30" Style="{StaticResource MaterialDesignIconForegroundButton}"
HorizontalAlignment="Right" Command="{x:Static md:DialogHost.CloseDialogCommand}"
IsCancel="True">
<TextBlock Margin="10" FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr ProxyManagerDialog.Title}" />
<Button Margin="0,0,10,0" IsCancel="True" Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right"
Command="{x:Static md:DialogHost.CloseDialogCommand}">
<md:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" />
<Grid Grid.Row="2">
+90
View File
@@ -0,0 +1,90 @@
<UserControl x:Class="NebulaAuth.View.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:other="clr-namespace:NebulaAuth.ViewModel.Other"
mc:Ignorable="d"
d:DesignHeight="650"
Foreground="WhiteSmoke"
FontFamily="{materialDesign:MaterialDesignFont}"
MinHeight="600"
MinWidth="400"
MaxWidth="200"
d:DataContext="{d:DesignInstance other:SettingsVM}"
Background="{DynamicResource WindowBackground}">
<Grid>
<Grid Margin="15,10,15,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock FontStyle="Normal" Foreground="DarkGray" HorizontalAlignment="Left"
VerticalAlignment="Center" FontSize="18" Text="{Tr SettingsDialog.Title}" />
<Button IsCancel="True" Grid.Column="1" Width="30" Height="30"
Style="{StaticResource MaterialDesignIconForegroundButton}" HorizontalAlignment="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">
<materialDesign:PackIcon Kind="Close" Width="24" Height="24" Foreground="IndianRed" />
</Button>
</Grid>
<Separator Grid.Row="1" Margin="0,10,0,0" />
<StackPanel Grid.Row="2" Margin="10,30,10,10" Orientation="Vertical" HorizontalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignOutlinedComboBox}" FontSize="16"
ItemsSource="{Binding BackgroundModes}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding BackgroundMode}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.BackgroundHint}" />
<ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" Margin="0,20,0,0" FontSize="16"
ItemsSource="{Binding Languages}" DisplayMemberPath="Value" SelectedValuePath="Key"
SelectedValue="{Binding Language}" materialDesign:HintAssist.Hint="{Tr LanguageWord}" />
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding HideToTray}"
Content="{Tr SettingsDialog.MinimizeToTray}" />
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseIcon}"
Content="{Tr SettingsDialog.UseIndicator}" ToolTip="{Tr SettingsDialog.UseIndicatorHint}" />
<materialDesign:ColorPicker IsEnabled="{Binding UseIcon}" Color="{Binding IconColor, Delay=50}" />
<CheckBox Margin="0,10,0,5" FontSize="16" IsChecked="{Binding UseBackground}"
Content="{Tr SettingsDialog.UseCustomColor}" />
<materialDesign:ColorPicker Height="100" IsEnabled="{Binding UseBackground}"
Color="{Binding BackgroundColor, Delay=50}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<PasswordBox MinWidth="250" materialDesign:PasswordBoxAssist.Password="{Binding Password}"
Height="Auto" VerticalAlignment="Center" FontSize="16" Margin="0,10,0,0"
Style="{StaticResource MaterialDesignFloatingHintRevealPasswordBox}"
materialDesign:HintAssist.Hint="{Tr SettingsDialog.PasswordBox.CurrentCryptPassword}"
materialDesign:HintAssist.HelperText="{Tr SettingsDialog.PasswordBox.Hint}" />
<Button Command="{Binding SetPasswordCommand}" Margin="5,0,0,0" VerticalAlignment="Bottom"
Grid.Column="1">
<materialDesign:PackIcon Kind="ContentSave" />
</Button>
</Grid>
<CheckBox Margin="0,20,0,0" FontSize="16" IsChecked="{Binding LegacyMode}"
Content="{Tr SettingsDialog.LegacyMafileMode}"
ToolTip="{Tr SettingsDialog.LegacyMafileModeHint}" />
<!--<CheckBox IsEnabled="False" Margin="0,10,0,0" FontSize="16" IsChecked="{Binding AllowAutoUpdate}" Content="{Tr SettingsDialog.AllowAutoUpdate}"/>-->
<CheckBox Margin="0,10,0,0" FontSize="16" IsChecked="{Binding UseAccountNameAsMafileName}">
<TextBlock TextWrapping="WrapWithOverflow" Text="{Tr SettingsDialog.UseAccountName}" />
</CheckBox>
<CheckBox IsChecked="{Binding IgnorePatchTuesdayErrors}" Margin="0,10,0,0" FontSize="16"
ToolTip="{Tr SettingsDialog.IgnorePatchTuesdayErrorsHint}">
<TextBlock TextWrapping="WrapWithOverflow" Text="{Tr SettingsDialog.IgnorePatchTuesdayErrors}" />
</CheckBox>
</StackPanel>
</Grid>
</Grid>
</UserControl>
+12
View File
@@ -0,0 +1,12 @@
namespace NebulaAuth.View;
/// <summary>
/// Логика взаимодействия для SettingsView.xaml
/// </summary>
public partial class SettingsView
{
public SettingsView()
{
InitializeComponent();
}
}
@@ -11,10 +11,9 @@ using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.Utility;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
using SteamLib.Exceptions;
using SteamLib.SteamMobile;
using SteamLibForked.Exceptions.Authorization;
namespace NebulaAuth.ViewModel;
@@ -30,12 +29,12 @@ public partial class MainVM : ObservableObject
}
public bool IsMafileSelected => SelectedMafile != null;
public DialogHost CurrentDialogHost { get; set; } = null!;
[ObservableProperty] private ObservableCollection<Mafile> _maFiles = Storage.MaFiles;
private Mafile? _selectedMafile;
public MainVM()
{
CreateCodeTimer();
@@ -52,12 +51,6 @@ public partial class MainVM : ObservableObject
}
}
[RelayCommand]
public async Task Debug()
{
Shell.Logger.Info("test");
}
private void SetMafile(Mafile? mafile)
{
@@ -97,7 +90,7 @@ public partial class MainVM : ObservableObject
var wait = DialogHost.Show(waitDialog);
try
{
await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword);
await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword, waitDialog);
SnackbarController.SendSnackbar(GetLocalization("SuccessfulLogin"));
}
catch (LoginException ex)
@@ -144,12 +137,6 @@ public partial class MainVM : ObservableObject
await DialogsController.ShowLinkerDialog();
}
[RelayCommand]
public async Task MoveAccount()
{
await DialogsController.ShowMafileMoverDialog();
}
[RelayCommand]
private async Task RemoveAuthenticator()
{
@@ -222,15 +209,6 @@ public partial class MainVM : ObservableObject
}
}
[RelayCommand]
private async Task OpenLinksView()
{
CurrentDialogHost.CloseOnClickAway = true;
var view = new LinksView();
await DialogHost.Show(view);
CurrentDialogHost.CloseOnClickAway = false;
}
private static string GetLocalization(string key)
{
@@ -22,36 +22,32 @@ public partial class MainVM
[MemberNotNull(nameof(_codeTimer))]
private void CreateCodeTimer()
{
CodeProgress = CalculateCodeProgress();
_codeTimer = new Timer(UpdateCode, null, 0, 1000);
}
private void UpdateCode(object? state = null)
{
var currentTime = TimeAligner.GetSteamTime();
var untilChange = currentTime % 30;
if (untilChange != 0) return;
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(() =>
Application.Current.Dispatcher.BeginInvoke((string? c) =>
{
CodeProgress = -1;
CodeProgress = 30;
if (Application.Current.MainWindow?.WindowState == WindowState.Minimized) return;
if (SelectedMafile == null) return;
Code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile.SharedSecret);
}, DispatcherPriority.Normal);
CodeProgress = codeProgress;
if (c != null) Code = c;
}, DispatcherPriority.DataBind, code);
}
private long CalculateCodeProgress()
{
var currentTime = TimeAligner.GetSteamTime();
var untilChange = currentTime % 30;
return 30 - untilChange;
}
[RelayCommand(AllowConcurrentExecutions = false)]
private async Task CopyCode()
{
@@ -17,7 +17,7 @@ using NebulaAuth.Utility;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel.Other;
using SteamLibForked.Exceptions.Authorization;
using SteamLib.Exceptions;
namespace NebulaAuth.ViewModel;
@@ -160,7 +160,7 @@ public partial class MainVM //File //TODO: Refactor
var wait = DialogHost.Show(waitDialog);
try
{
await MaClient.LoginAgain(data, password, loginAgainVm.SavePassword);
await MaClient.LoginAgain(data, password, loginAgainVm.SavePassword, waitDialog);
SnackbarController.SendSnackbar(GetLocalization("SuccessfulLogin"));
}
catch (LoginException ex)
@@ -217,7 +217,7 @@ public partial class MainVM //File //TODO: Refactor
private async Task OpenSettingsDialog()
{
var vm = new SettingsVM();
var view = new SettingsView(CurrentDialogHost)
var view = new SettingsView
{
DataContext = vm
};
@@ -37,7 +37,6 @@ public partial class MainVM
}
if (!system && SelectedMafile != null)
{
SelectedMafile.Proxy = SelectedProxy;
Storage.UpdateMafile(SelectedMafile);
+457
View File
@@ -0,0 +1,457 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using AchiesUtilities.Collections;
using AchiesUtilities.Web.Proxy;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model;
using NebulaAuth.Model.Entities;
using NebulaAuth.Utility;
using NLog;
using SteamLib;
using SteamLib.Account;
using SteamLib.Authentication;
using SteamLib.Authentication.LoginV2;
using SteamLib.Core.Interfaces;
using SteamLib.Exceptions;
using SteamLib.Exceptions.Mobile;
using SteamLib.ProtoCore.Exceptions;
using SteamLib.SteamMobile.AuthenticatorLinker;
using SteamLib.Web;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace NebulaAuth.ViewModel.Other;
public partial class LinkAccountVM : ObservableObject, IEmailProvider, IPhoneNumberProvider, ISmsCodeProvider
{
private const string LOCALIZATION_KEY = "LinkVM";
private static Logger Logger => Shell.Logger;
private static ILogger Logger2 => Shell.ExtensionsLogger;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public LinkAccountVM()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
if (MaClient.DefaultProxy != null)
{
var def = Proxies.FirstOrDefault(p => p.Value.Equals(MaClient.DefaultProxy));
if (def.Value != null!)
{
SelectedProxy = def;
}
}
}
[RelayCommand(AllowConcurrentExecutions = true, CanExecute = nameof(CanProceed))]
public async Task Proceed()
{
if (IsCompleted)
DialogHost.Close(null);
CanProceed = false;
#region Login
if (IsLogin == false)
{
SetProxy();
ClearCookies();
_loginV2ExecutorOptions = new LoginV2ExecutorOptions(LoginV2Executor.NullConsumer, Client)
{
DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
WebsiteId = "Mobile",
EmailAuthProvider = this,
Logger = Logger2
};
try
{
IsLogin = true;
var userName = FieldText;
var pass = PassFieldText;
_password = pass;
FieldText = string.Empty;
IsFieldVisible = false;
HintText = string.Empty;
_sessionData =
(MobileSessionData) await LoginV2Executor.DoLogin(_loginV2ExecutorOptions, userName, pass);
Handler.CookieContainer.SetSteamMobileCookiesWithMobileToken(_sessionData);
IsEmailCode = true;
}
catch (EResultException ex)
{
Logger.Error(ex, "Link exception on login");
HintText = GetLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateEResult(ex.Result);
InvokeOnDispatcher(ResetState);
return;
}
catch (LoginException ex)
{
Logger.Error(ex, "Link exception on login");
HintText = GetLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateLoginError(ex.Error);
InvokeOnDispatcher(ResetState);
return;
}
catch (Exception ex)
{
Logger.Error(ex, "Link exception on login");
HintText = GetLocalizationOrDefault("CantLogin") + ex.Message;
InvokeOnDispatcher(ResetState);
return;
}
}
if (IsEmailCode == false)
{
_emailCodeTcs.SetResult(FieldText);
HintText = string.Empty;
FieldText = string.Empty;
_emailCodeTcs = new TaskCompletionSource<string>();
IsFieldVisible = false;
return;
}
#endregion
if (_isLinkStarted)
goto linkStarted;
try
{
_isLinkStarted = true;
var linkOptions = new LinkOptions(Client, LoginV2Executor.NullConsumer, this,
null, this, this, Backup, Logger2);
_linker = new SteamAuthenticatorLinker(linkOptions);
var result = await _linker.LinkAccount(_sessionData);
IsLinkCode = true;
IsCompleted = true;
var mafile = Mafile.FromMobileDataExtended(result);
try
{
if (SelectedProxy.HasValue)
mafile.Proxy = new MaProxy(SelectedProxy.Value.Key, SelectedProxy.Value.Value);
if (Settings.Instance.IsPasswordSet)
mafile.Password = PHandler.Encrypt(_password);
}
catch (Exception ex)
{
Logger.Error(ex, "Error during saving Nebula data to mafile");
}
Storage.SaveMafile(mafile);
File.Delete(Path.Combine("mafiles_backup", mafile.AccountName + ".mafile"));
HintText =
string.Format(GetLocalizationOrDefault("MafileLinked"),
mafile.RevocationCode,
mafile.SessionData?.SteamId.Steam64);
_rCode = mafile.RevocationCode ?? string.Empty;
CanProceed = true;
return;
}
catch (AuthenticatorLinkerException ex)
{
Logger.Error(ex, "Link exception");
HintText = $"{GetLocalizationCommon("Error")}: {ErrorTranslatorHelper.TranslateLinkerError(ex.Error)}";
InvokeOnDispatcher(ResetState);
return;
}
catch (HttpRequestException ex)
{
var msg = ex.StatusCode?.ToString() ?? ex.Message;
HintText = $"{GetLocalizationCommon("RequestError")}: {msg}";
InvokeOnDispatcher(ResetState);
return;
}
catch (EResultException ex)
{
Logger.Error(ex, "Link exception");
HintText = GetLocalizationOrDefault("ErrorWithCode") + ErrorTranslatorHelper.TranslateEResult(ex.Result);
InvokeOnDispatcher(ResetState);
return;
}
catch (Exception ex)
{
Logger.Error(ex, "Link exception");
HintText = GetLocalizationOrDefault("UnknownError") + ex.Message;
InvokeOnDispatcher(ResetState);
return;
}
linkStarted:
if (IsPhoneNumber == false)
{
var phoneText = FieldText;
FieldText = string.Empty;
if (string.IsNullOrWhiteSpace(phoneText))
{
HintText = string.Empty;
IsFieldVisible = false;
_phoneNumberTcs.SetResult(null);
_phoneNumberTcs = new TaskCompletionSource<long?>();
return;
}
if (!string.IsNullOrWhiteSpace(phoneText) && phoneText.Length >= 4 &&
long.TryParse(phoneText, out var phone))
{
HintText = string.Empty;
IsFieldVisible = false;
_phoneNumberTcs.SetResult(phone);
_phoneNumberTcs = new TaskCompletionSource<long?>();
return;
}
HintText = GetLocalizationOrDefault("PleaseEnterCorrectPhone");
CanProceed = true;
return;
}
if (IsEmailConfirmation == false)
{
HintText = string.Empty;
_emailConfTcs.SetResult();
_emailConfTcs = new TaskCompletionSource();
CanProceed = false;
return;
}
if (IsLinkCode == false)
{
var linkCode = FieldText;
FieldText = string.Empty;
if (!string.IsNullOrWhiteSpace(linkCode) && linkCode.Length >= 4)
{
HintText = string.Empty;
IsFieldVisible = false;
_linkCodeTcs.SetResult(linkCode);
_linkCodeTcs = new TaskCompletionSource<string>();
}
else
{
HintText = GetLocalizationOrDefault("PleaseEnterCorrectCode");
CanProceed = true;
}
}
}
[RelayCommand]
public void ResetProxy()
{
if (IsPasswordFieldVisible == false) return;
SelectedProxy = null;
}
private void InvokeOnDispatcher(Action action)
{
Application.Current.Dispatcher.BeginInvoke(action, null);
}
private void ResetState()
{
PassFieldText = string.Empty;
IsLogin = false;
IsFieldVisible = true;
IsEmailCode = false;
_isLinkStarted = false;
IsPhoneNumber = false;
IsEmailConfirmation = false;
CanProceed = true;
_emailCodeTcs = new TaskCompletionSource<string>();
_rCode = string.Empty;
_password = string.Empty;
}
private void Backup(MobileDataExtended data)
{
if (Directory.Exists("mafiles_backup") == false)
{
Directory.CreateDirectory("mafiles_backup");
}
var json = NebulaSerializer.SerializeMafile(data, null);
File.WriteAllText(Path.Combine("mafiles_backup", data.AccountName + ".mafile"),
json); //TODO: Move logic to Storage
}
[RelayCommand]
private void OpenTroubleshooting()
{
const string troubleshootingURI =
"https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/docs/{0}/LinkingTroubleshooting";
var localized = string.Format(troubleshootingURI, LocManager.GetCurrentLanguageCode());
Process.Start(new ProcessStartInfo(new Uri(localized).ToString())
{
UseShellExecute = true
});
}
[RelayCommand]
private void CopyCode()
{
try
{
Clipboard.SetText(_rCode);
}
catch (Exception ex)
{
Shell.Logger.Error(ex, "Error whily copying RCode");
}
}
private static string GetLocalizationOrDefault(string key)
{
return LocManager.GetCodeBehindOrDefault(key, LOCALIZATION_KEY, key);
}
private static string GetLocalizationCommon(string key)
{
return LocManager.GetCommonOrDefault(key, key);
}
#region Properties
[ObservableProperty] [NotifyPropertyChangedFor(nameof(IsPasswordFieldVisible))]
private bool _isLogin;
[ObservableProperty] private bool _isEmailCode;
[ObservableProperty] private bool _isPhoneNumber;
[ObservableProperty] private bool _isEmailConfirmation;
[ObservableProperty] private bool _isLinkCode;
[ObservableProperty] private bool _isCompleted;
[ObservableProperty] private bool _isFieldVisible = true;
[ObservableProperty] private string _fieldText;
[ObservableProperty] private string _passFieldText;
[ObservableProperty] private string _hintText = GetLocalizationOrDefault("EnterLoginAndPassword");
private TaskCompletionSource<string> _emailCodeTcs = new();
private TaskCompletionSource<long?> _phoneNumberTcs = new();
private TaskCompletionSource _emailConfTcs = new();
private TaskCompletionSource<string> _linkCodeTcs = new();
private bool _isLinkStarted;
private string _rCode = string.Empty;
private string _password = string.Empty;
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ProceedCommand))]
private bool _canProceed = true;
public bool IsPasswordFieldVisible => !IsLogin;
private LoginV2ExecutorOptions _loginV2ExecutorOptions;
private SteamAuthenticatorLinker _linker;
private MobileSessionData _sessionData;
#endregion
#region HttpClient
private static HttpClient Client { get; }
private static HttpClientHandler Handler { get; }
private static DynamicProxy Proxy { get; }
public ObservableDictionary<int, ProxyData> Proxies => ProxyStorage.Proxies;
public KeyValuePair<int, ProxyData>? SelectedProxy
{
get => _selectedProxy;
set
{
SetProperty(ref _selectedProxy, value);
SetProxy();
}
}
private KeyValuePair<int, ProxyData>? _selectedProxy;
#endregion
#region Providers
public int MaxRetryCount { get; }
public Task<string> GetEmailAuthCode(ILoginConsumer caller)
{
CanProceed = true;
HintText = GetLocalizationOrDefault("EnterEmailCode");
IsFieldVisible = true;
return _emailCodeTcs.Task;
}
public Task<string> GetAddAuthenticatorCode(ILoginConsumer caller)
{
IsPhoneNumber = true;
IsEmailConfirmation = true;
CanProceed = true;
HintText = GetLocalizationOrDefault("EnterEmailCode");
IsFieldVisible = true;
return _linkCodeTcs.Task;
}
public Task ConfirmEmailLink(ILoginConsumer caller, EmailConfirmationType confirmationType)
{
IsPhoneNumber = true;
CanProceed = true;
HintText = GetLocalizationOrDefault("ClickOnEmailLink");
return _emailConfTcs.Task;
}
public Task<long?> GetPhoneNumber(ILoginConsumer caller)
{
CanProceed = true;
HintText = GetLocalizationOrDefault("EnterPhoneNumber");
IsFieldVisible = true;
return _phoneNumberTcs.Task;
}
public async Task<int> GetSmsCode(ILoginConsumer caller, long? phoneNumber, string? hint)
{
IsPhoneNumber = true;
IsEmailConfirmation = true;
CanProceed = true;
HintText = string.Format(GetLocalizationOrDefault("PhoneHint"), hint);
IsFieldVisible = true;
var code = await _linkCodeTcs.Task;
return int.Parse(code);
}
#endregion
#region Client
static LinkAccountVM()
{
Proxy = new DynamicProxy();
var clientPair = ClientBuilder.BuildMobileClient(Proxy, null);
Client = clientPair.Client;
Handler = clientPair.Handler;
}
private void ClearCookies()
{
Handler.CookieContainer.ClearMobileSessionCookies();
}
private void SetProxy()
{
Proxy.SetData(SelectedProxy?.Value);
}
#endregion
}
@@ -11,6 +11,11 @@ public partial class SettingsVM : ObservableObject
{
public Settings Settings => Settings.Instance;
public BackgroundMode BackgroundMode
{
get => Settings.BackgroundMode;
set => Settings.BackgroundMode = value;
}
public bool HideToTray
{
@@ -25,15 +30,6 @@ public partial class SettingsVM : ObservableObject
{BackgroundMode.Color, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "NoBackground")}
};
public Dictionary<ThemeType, string> ThemeTypes => new()
{
{ThemeType.Default, "Default"},
{ThemeType.Black, "Black"},
{ThemeType.Light, "Light"},
{ThemeType.Luxury, "Luxury"},
{ThemeType.Shadcn, "Shadcn"}
};
public Dictionary<LocalizationLanguage, string> Languages { get; } = new()
{
{LocalizationLanguage.English, "English"},
@@ -41,6 +37,12 @@ public partial class SettingsVM : ObservableObject
{LocalizationLanguage.Ukrainian, "Українська"}
};
public Color? BackgroundColor
{
get => Settings.BackgroundColor;
set => Settings.BackgroundColor = value;
}
public Color? IconColor
{
get => Settings.IconColor;
@@ -62,6 +64,21 @@ public partial class SettingsVM : ObservableObject
}
}
public bool UseBackground
{
get => BackgroundColor != null;
set
{
if (value == false)
BackgroundColor = null;
else
BackgroundColor = Color.FromRgb(202, 39, 39);
OnPropertyChanged();
OnPropertyChanged(nameof(BackgroundColor));
}
}
public LocalizationLanguage Language
{
@@ -105,69 +122,4 @@ public partial class SettingsVM : ObservableObject
{
Settings.IsPasswordSet = PHandler.SetPassword(Password);
}
[RelayCommand]
private void ResetThemeDefaults()
{
Settings.ResetThemeDefaults();
OnPropertyChanged(nameof(BackgroundBlur));
OnPropertyChanged(nameof(BackgroundOpacity));
OnPropertyChanged(nameof(BackgroundGamma));
OnPropertyChanged(nameof(LeftOpacity));
OnPropertyChanged(nameof(RightOpacity));
OnPropertyChanged(nameof(ApplyBlurBackground));
}
#region Theme
public BackgroundMode BackgroundMode
{
get => Settings.BackgroundMode;
set => Settings.BackgroundMode = value;
}
public double BackgroundBlur
{
get => Settings.BackgroundBlur;
set => Settings.BackgroundBlur = value;
}
public double BackgroundOpacity
{
get => Settings.BackgroundOpacity;
set => Settings.BackgroundOpacity = value;
}
public double BackgroundGamma
{
get => Settings.BackgroundGamma;
set => Settings.BackgroundGamma = value;
}
public double LeftOpacity
{
get => Settings.LeftOpacity;
set => Settings.LeftOpacity = value;
}
public double RightOpacity
{
get => Settings.RightOpacity;
set => Settings.RightOpacity = value;
}
public bool ApplyBlurBackground
{
get => Settings.ApplyBlurBackground;
set => Settings.ApplyBlurBackground = value;
}
public ThemeType ThemeType
{
get => Settings.ThemeType;
set => Settings.ThemeType = value;
}
#endregion
}
@@ -68,6 +68,14 @@
"en": "Loading...",
"ru": "Загрузка...",
"ua": "Завантаження..."
},
"StartTip": {
"ru":
"Чтобы начать пользоваться программой вы можете привязать аккаунт через меню \"Аккаунт\", либо импортировать существующие мафайлы одним из способов:\n1. Скопировать их в папку mafiles и перезапустить приложение\n2. Перетянуть файлы прямо в окно программы\n3. Скопировать файлы и нажать CTRL+V в окне программы\n4. Через меню \"Файл\" - \"Импорт\"",
"en":
"To start using the program, you can link an account through the \"Account\" menu, or import existing mafiles in one of the following ways:\n1. Copy them to the mafiles folder and restart the application\n2. Drag files directly into the program window\n3. Copy files and press CTRL+V in the program window\n4. Through the \"File\" - \"Import\" menu",
"ua":
"Щоб почати користуватися програмою, ви можете прив'язати акаунт через меню \"Акаунт\", або імпортувати існуючі мафайли одним із способів:\n1. Скопіювати їх у папку mafiles та перезапустити програму\n2. Перетягнути файли безпосередньо в вікно програми\n3. Скопіювати файли та натиснути CTRL+V в вікні програми\n4. Через меню \"Файл\" - \"Імпорт\""
}
},
"Menu": {
@@ -109,11 +117,6 @@
"ru": "Привязать",
"ua": "Прив'язати"
},
"MoveSteamGuard": {
"en": "Move Steam Guard",
"ru": "Перенести Steam Guard",
"ua": "Перенести Steam Guard"
},
"Unlink": {
"en": "Unlink",
"ru": "Отвязать",
@@ -204,11 +207,6 @@
"en": "Search",
"ru": "Поиск",
"ua": "Пошук"
},
"NoMafiles": {
"en": "No mafiles found..",
"ru": "Мафайлы не найдены..",
"ua": "Мафайли не знайдено.."
}
},
"RightPart": {
@@ -315,58 +313,6 @@
"ru": "Настройки",
"ua": "Налаштування"
},
"MainSettings": {
"en": "Main",
"ru": "Основные",
"ua": "Основні"
},
"ThemeSettings": {
"en": "Theme",
"ru": "Тема",
"ua": "Тема"
},
"Theme": {
"BackgroundBlur": {
"en": "Background Blur",
"ru": "Размытие фона",
"ua": "Розмиття фону"
},
"BackgroundOpacity": {
"en": "Background Opacity",
"ru": "Непрозрачность фона",
"ua": "Непрозорість фону"
},
"Gamma": {
"en": "Gamma",
"ru": "Гамма",
"ua": "Гама"
},
"LeftOpacity": {
"en": "Left Opacity",
"ru": "Непрозрачность слева",
"ua": "Непрозорість зліва"
},
"RightOpacity": {
"en": "Right Opacity",
"ru": "Непрозрачность справа",
"ua": "Непрозорість справа"
},
"CurrentTheme": {
"en": "Current Theme",
"ru": "Текущая тема",
"ua": "Поточна тема"
},
"DialogBlur": {
"en": "Blur on Dialog",
"ru": "Размытие при открытии диалог. окна",
"ua": "Розмиття при відкритті діалог. вікна"
},
"Reset": {
"en": "Reset",
"ru": "Сбросить",
"ua": "Скинути"
}
},
"BackgroundHint": {
"en": "Background",
"ru": "Фон",
@@ -422,15 +368,14 @@
}
},
"LegacyMafileMode": {
"en": "Common mafiles format",
"ru": "Общепринятый формат мафайлов",
"ua": "Загальноприйнятий формат мафайлів"
"en": "Legacy mafile mode",
"ru": "Режим старых мафайлов",
"ua": "Режим старих мафайлів"
},
"LegacyMafileModeHint": {
"en": "Save mafiles in compatibility format with Steam Desktop Authenticator and other applications",
"ru":
"Сохранять мафайлы в старом формате для совместимости со Steam Desktop Authenticator и другими приложениями",
"ua": "Зберігати мафайли у старому форматі для сумісності зі Steam Desktop Authenticator та іншими додатками"
"en": "Use old mafile format for compatibility with old versions of Steam Desktop Authenticator",
"ru": "Использовать старый формат мафайлов для совместимости со старыми версиями Steam Desktop Authenticator",
"ua": "Використовувати старий формат мафайлів для сумісності зі старими версіями Steam Desktop Authenticator"
},
"AllowAutoUpdate": {
"en": "Allow auto update",
@@ -542,8 +487,8 @@
},
"Authorization": {
"en": "Authorization",
"ru": "Вход в аккаунт",
"ua": "Вхід в акаунт"
"ru": "Авторизация",
"ua": "Авторизація"
},
"EmailCode": {
"en": "Email code",
@@ -579,54 +524,9 @@
"en": "Proceed",
"ru": "Продолжить",
"ua": "Продовжити"
},
"CancelButton": {
"en": "Cancel",
"ru": "Отмена",
"ua": "Відміна"
},
"MafileLinked": {
"en": "Mafile successfully linked",
"ru": "Мафайл успешно привязан",
"ua": "Мафайл успішно прив'язано"
},
"FinishButton": {
"en": "Finish",
"ru": "Завершить",
"ua": "Завершити"
},
"CopyRCodeButton": {
"en": "Copy RCode",
"ru": "Скопировать RCode",
"ua": "Скопіювати RCode"
},
"Login": {
"en": "Login",
"ru": "Логин",
"ua": "Логін"
},
"Password": {
"en": "Password",
"ru": "Пароль",
"ua": "Пароль"
},
"Code": {
"en": "Code",
"ru": "Код",
"ua": "Код"
},
"SmsCode": {
"en": "SMS code",
"ru": "СМС код",
"ua": "СМС код"
}
},
"SetEncryptedPasswordDialog": {
"Title": {
"en": "Encryption password",
"ru": "Пароль шифрования",
"ua": "Пароль шифрування"
},
"DialogText": {
"en":
"You have previously set an encryption password for passwords in mafiles, specify it so that the application can automatically log in in case of problems with the session. (Optional)",
@@ -651,30 +551,6 @@
"ua": "Пароль"
}
},
"LinksView": {
"UsefulLinks": {
"en": "Useful links",
"ru": "Полезные ссылки",
"ua": "Корисні посилання"
},
"Documentation": {
"en": "Documentation",
"ru": "Документация",
"ua": "Документація"
}
},
"MafileMoverView": {
"Title": {
"en": "Move Steam Guard",
"ru": "Перенести Steam Guard",
"ua": "Перенести Steam Guard"
},
"Done": {
"en": "Steam Guard moved",
"ru": "Steam Guard перенесен",
"ua": "Steam Guard перенесено"
}
},
"CodeBehind": {
"MainVM": {
"SuccessfulLogin": {
@@ -941,11 +817,6 @@
"ua": "Скасовано (52)"
},
"InvalidLoginAuthCode": {
"ru": "Неверный код авторизации (65)",
"en": "Invalid login auth code (65)",
"ua": "Невірний код авторизації (65)"
},
"ExpiredLoginAuthCode": {
"ru": "Истекло время кода (71)",
"en": "Expired login auth code (71)",
@@ -1191,15 +1062,10 @@
"en": "Can't login: ",
"ua": "Не вдалося залогінитися: "
},
"UnsupportedGuardType": {
"ru": "Steam Guard уже активирован. Был запрошен код с мобильного устройства",
"en": "Steam Guard already activated. Mobile device code was requested",
"ua": "Steam Guard вже активовано. Був запрошений код з мобільного пристрою"
},
"MafileLinked": {
"ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
"en": "RCode: {0}\r\nFile name: {1}.mafile",
"ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
"ru": "Мафайл успешно привязан. RCode: {0}\r\nИмя файла: {1}.mafile",
"en": "Mafile successfully linked. RCode: {0}\r\nFile name: {1}.mafile",
"ua": "Мафайл успішно прив'язано. RCode: {0}\r\nІм'я файлу: {1}.mafile"
},
"ErrorWithCode": {
"ru": "Ошибка с кодом: ",
@@ -1211,23 +1077,25 @@
"en": "Unknown error: ",
"ua": "Невідома помилка: "
},
"PleaseEnterCorrectPhone": {
"ru": "Пожалуйста, введите корректный номер телефона",
"en": "Please enter correct phone number",
"ua": "Будь ласка, введіть коректний номер телефону"
},
"PleaseEnterCorrectCode": {
"ru": "Пожалуйста, введите корректный код",
"en": "Please enter correct code",
"ua": "Будь ласка, введіть коректний код"
},
"EnterEmailCode": {
"ru": "Введите код, отправленный на вашу почту",
"en": "Enter the code sent to your email",
"ua": "Введіть код, надісланий на вашу пошту"
"ru": "Введите код из письма",
"en": "Enter code from email",
"ua": "Введіть код з листа"
},
"ClickOnEmailLink": {
"ru": "На почту было отправлено письмо, откройте ссылку из письма, а затем нажмите — 'Продолжить'",
"en": "An email has been sent. Open the link from the email, then click 'Proceed'",
"ua": "На пошту надіслано лист. Відкрийте посилання з листа, а потім натисніть — 'Продовжити'"
},
"ClickOnEmailLinkRetry": {
"ru":
"Не удалось подтвердить переход по ссылке. Убедитесь, что вы открыли ссылку из письма, затем нажмите — 'Продолжить'",
"en":
"We couldnt verify that you clicked the link. Make sure you opened the link from the email, then click 'Proceed'",
"ua":
"Не вдалося підтвердити перехід за посиланням. Переконайтесь, що ви відкрили посилання з листа, а потім натисніть — 'Продовжити'"
"ru": "На почту было отправлено письмо, нажмите по ссылке затем - 'Продолжить'",
"en": "Email was sent, click on link and then - 'Proceed'",
"ua": "На пошту було відправлено лист, натисніть по посиланню потім - 'Продовжити'"
},
"PhoneHint": {
"ru": "На телефон {0} была отправлена СМС",
@@ -1235,84 +1103,39 @@
"ua": "На телефон {0} було відправлено СМС"
},
"EnterPhoneNumber": {
"ru":
"Введите номер в международном формате, только цифры (без '+', пробелов и скобок), или оставьте поле пустым, чтобы привязать без номера",
"en":
"Enter number in international format, digits only (no '+', spaces or brackets), or leave the field empty to link without a number",
"ua":
"Введіть номер у міжнародному форматі, лише цифри (без '+', пробілів і дужок), або залиште поле порожнім, щоб прив’язати без номера"
"ru": "Введите номер телефона (без знака '+' и др. символов). По-желанию.",
"en": "Enter phone number (without '+' and other symbols). Optional",
"ua": "Введіть номер телефону (без знака '+' та ін. символів). За бажанням"
}
},
"MafileMoverVM": {
"EnterGuardCode": {
"en": "Enter Steam Guard code or confirm login and click 'Proceed'",
"ru": "Введите код Steam Guard либо подтвердите вход и нажмите \"Продолжить\"",
"ua": "Введіть код Steam Guard або підтвердіть вхід і натисніть 'Продовжити'"
"MAAC": {
"TimerConfirmed": {
"ru": "Авто: подтверждено ",
"en": "Auto: confirmed ",
"ua": "Авто: підтверджено "
},
"EnterGuardCodeRetrying": {
"en": "Failed to confirm login. Enter Steam Guard code or try again",
"ru": "Не удалось подтвердить вход. Введите код Steam Guard или попробуйте еще раз",
"ua": "Не вдалося підтвердити вхід. Введіть код Steam Guard або спробуйте ще раз"
"TimerNotConfirmed": {
"ru": "Авто: подтверждение не сработало",
"en": "Auto: confirmation was unsuccessful",
"ua": "Авто: підтвердження не спрацювало"
},
"SmsCodeStepTip": {
"en": "Enter the code from the SMS sent to your phone number",
"ru": "Введите код из СМС, отправленный на ваш номер телефона",
"ua": "Введіть код з СМС, надісланий на ваш номер телефону"
"TimerSessionError": {
"ru": "необходимо обновить сессию или перелогиниться",
"en": "need to refresh session or relogin",
"ua": "необхідно оновити сесію або перелогінитися"
},
"DoneStepTip": {
"ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
"en": "RCode: {0}\r\nFile name: {1}.mafile",
"ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
"TimerPrefix": {
"ru": "Авто ",
"en": "Auto ",
"ua": "Авто "
},
"GuardIsNotActive": {
"ru":
"Steam Guard установлен на данном аккаунте. Чтобы привязать mafile к аккаунту, воспользуйтесь окном \"Привязать\"",
"en": "Steam Guard is set on this account. To link mafile to the account, use the 'Link' window",
"ua":
"Steam Guard встановлено на цьому акаунті. Щоб прив'язати mafile до акаунту, скористайтеся вікном 'Прив'язати'"
},
"SeemsNoPhoneNumber": {
"en": "The account has no phone number linked, returned Fail code (2)",
"ru": "На аккаунте не привязан номер телефона, был возвращен код Fail (2)",
"ua": "На акаунті не прив'язано номер телефону, повернуто код Fail (2)"
},
"SmsCodeFailed": {
"en": "SMS code failed, try again",
"ru": "Ошибка SMS-кода, попробуйте еще раз",
"ua": "Помилка SMS-коду, спробуйте ще раз"
"TimerPreventedOverlap": {
"ru": "Авто: таймер подтверждений пытался начать новый цикл, когда предыдущий еще не завершился. Советуем увеличить задержку",
"en": "Auto: confirmation timer tried to start new cycle when previous one was not finished yet. We recommend to increase delay",
"ua": "Авто: таймер підтверджень намагався запустити новий цикл, коли попередній ще не закінчився. Рекомендуємо збільшити затримку"
}
}
},
"MAAC": {
"TimerConfirmed": {
"ru": "Авто: подтверждено ",
"en": "Auto: confirmed ",
"ua": "Авто: підтверджено "
},
"TimerNotConfirmed": {
"ru": "Авто: подтверждение не сработало",
"en": "Auto: confirmation was unsuccessful",
"ua": "Авто: підтвердження не спрацювало"
},
"TimerSessionError": {
"ru": "необходимо обновить сессию или перелогиниться",
"en": "need to refresh session or relogin",
"ua": "необхідно оновити сесію або перелогінитися"
},
"TimerPrefix": {
"ru": "Авто ",
"en": "Auto ",
"ua": "Авто "
},
"TimerPreventedOverlap": {
"ru":
"Авто: таймер подтверждений пытался начать новый цикл, когда предыдущий еще не завершился. Советуем увеличить задержку",
"en":
"Auto: confirmation timer tried to start new cycle when previous one was not finished yet. We recommend to increase delay",
"ua":
"Авто: таймер підтверджень намагався запустити новий цикл, коли попередній ще не закінчився. Рекомендуємо збільшити затримку"
}
},
"CantAlignTimeError": {
"ru":
"Не удается синхронизировать время со Steam. Возможно отсутствует подключение к интернету или Steam недоступен. Подробная ошибка сохранена в log.log",
+3 -3
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>1.5.6.0</version>
<url>https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.6/NebulaAuth.1.5.6.zip</url>
<changelog>https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.6.html</changelog>
<version>1.5.7.0</version>
<url>https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.7/NebulaAuth.1.5.7.zip</url>
<changelog>https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.7.html</changelog>
<mandatory>false</mandatory>
</item>

Some files were not shown because too many files have changed in this diff Show More