diff --git a/NebulaAuth.sln b/NebulaAuth.sln
index 2db9a5a..361999a 100644
--- a/NebulaAuth.sln
+++ b/NebulaAuth.sln
@@ -3,15 +3,6 @@ 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
@@ -28,27 +19,33 @@ 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
+ changelog\1.7.1.html = changelog\1.7.1.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
- {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
+ {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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/NebulaAuth/App.xaml.cs b/NebulaAuth/App.xaml.cs
deleted file mode 100644
index 9ae9dc1..0000000
--- a/NebulaAuth/App.xaml.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-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;
- }
- }
-}
\ No newline at end of file
diff --git a/NebulaAuth/NebulaAuth.csproj b/NebulaAuth/NebulaAuth.csproj
deleted file mode 100644
index a8eff3f..0000000
--- a/NebulaAuth/NebulaAuth.csproj
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
- WinExe
- net8.0-windows7.0
- enable
- true
- true
- latest
- en;ru;ua
- Theme\lock.ico
- 7.0
- 1.5.7
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Never
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Code
-
-
-
-
-
-
- Always
-
-
- Always
-
-
-
-
diff --git a/NebulaAuth/Theme/Brushes.xaml b/NebulaAuth/Theme/Brushes.xaml
deleted file mode 100644
index d96edc1..0000000
--- a/NebulaAuth/Theme/Brushes.xaml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NebulaAuth/Theme/SplashScreen.png b/NebulaAuth/Theme/SplashScreen.png
deleted file mode 100644
index 3255bc0..0000000
Binary files a/NebulaAuth/Theme/SplashScreen.png and /dev/null differ
diff --git a/NebulaAuth/Theme/lock small-detailed.png b/NebulaAuth/Theme/lock small-detailed.png
deleted file mode 100644
index a88ff31..0000000
Binary files a/NebulaAuth/Theme/lock small-detailed.png and /dev/null differ
diff --git a/NebulaAuth/Theme/lock.ico b/NebulaAuth/Theme/lock.ico
deleted file mode 100644
index 3397e22..0000000
Binary files a/NebulaAuth/Theme/lock.ico and /dev/null differ
diff --git a/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml b/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml
deleted file mode 100644
index dfbeaf4..0000000
--- a/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml b/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml
deleted file mode 100644
index 379dfab..0000000
--- a/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs b/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs
deleted file mode 100644
index bc1268f..0000000
--- a/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-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;
-
-///
-/// Логика взаимодействия для WaitLoginDialog.xaml
-///
-public partial class WaitLoginDialog : ICaptchaResolver
-{
- private TaskCompletionSource _tcs = new();
-
- public WaitLoginDialog()
- {
- InitializeComponent();
- }
-
- public async Task 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 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();
- oldTcs.SetResult(CaptchaTB.Text);
- }
-}
\ No newline at end of file
diff --git a/NebulaAuth/View/LinkerView.xaml b/NebulaAuth/View/LinkerView.xaml
deleted file mode 100644
index 970d539..0000000
--- a/NebulaAuth/View/LinkerView.xaml
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NebulaAuth/View/SettingsView.xaml b/NebulaAuth/View/SettingsView.xaml
deleted file mode 100644
index 0e98086..0000000
--- a/NebulaAuth/View/SettingsView.xaml
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NebulaAuth/View/SettingsView.xaml.cs b/NebulaAuth/View/SettingsView.xaml.cs
deleted file mode 100644
index 183e3a7..0000000
--- a/NebulaAuth/View/SettingsView.xaml.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace NebulaAuth.View;
-
-///
-/// Логика взаимодействия для SettingsView.xaml
-///
-public partial class SettingsView
-{
- public SettingsView()
- {
- InitializeComponent();
- }
-}
\ No newline at end of file
diff --git a/NebulaAuth/ViewModel/Other/LinkAccountVM.cs b/NebulaAuth/ViewModel/Other/LinkAccountVM.cs
deleted file mode 100644
index 62f7ec2..0000000
--- a/NebulaAuth/ViewModel/Other/LinkAccountVM.cs
+++ /dev/null
@@ -1,457 +0,0 @@
-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();
- 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();
- 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();
- 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();
- }
- 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();
- _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 _emailCodeTcs = new();
- private TaskCompletionSource _phoneNumberTcs = new();
- private TaskCompletionSource _emailConfTcs = new();
- private TaskCompletionSource _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 Proxies => ProxyStorage.Proxies;
-
- public KeyValuePair? SelectedProxy
- {
- get => _selectedProxy;
- set
- {
- SetProperty(ref _selectedProxy, value);
- SetProxy();
- }
- }
-
- private KeyValuePair? _selectedProxy;
-
- #endregion
-
- #region Providers
-
- public int MaxRetryCount { get; }
-
- public Task GetEmailAuthCode(ILoginConsumer caller)
- {
- CanProceed = true;
- HintText = GetLocalizationOrDefault("EnterEmailCode");
- IsFieldVisible = true;
- return _emailCodeTcs.Task;
- }
-
- public Task 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 GetPhoneNumber(ILoginConsumer caller)
- {
- CanProceed = true;
- HintText = GetLocalizationOrDefault("EnterPhoneNumber");
- IsFieldVisible = true;
- return _phoneNumberTcs.Task;
- }
-
- public async Task 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
-}
\ No newline at end of file
diff --git a/NebulaAuth/update.xml b/NebulaAuth/update.xml
index 9c85715..8f82293 100644
--- a/NebulaAuth/update.xml
+++ b/NebulaAuth/update.xml
@@ -1,8 +1,8 @@
-
- 1.5.7.0
- https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.7/NebulaAuth.1.5.7.zip
- https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.7.html
+ 1.7.1.0
+ https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.7.1/NebulaAuth.1.7.1.zip
+ https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.7.1.html
false
\ No newline at end of file
diff --git a/SteamLibForked/Api/Mobile/SteamMobileAuthenticatorApi.cs b/SteamLibForked/Api/Mobile/SteamMobileAuthenticatorApi.cs
deleted file mode 100644
index 327846a..0000000
--- a/SteamLibForked/Api/Mobile/SteamMobileAuthenticatorApi.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System.Net;
-using SteamLib.Core;
-using SteamLib.Exceptions;
-using SteamLib.ProtoCore;
-using SteamLib.ProtoCore.Services;
-
-namespace SteamLib.Api.Mobile;
-
-public static class SteamMobileAuthenticatorApi
-{
- public static async Task GetAuthSessionsForAccount(HttpClient client,
- string accessToken, CancellationToken cancellationToken = default)
- {
- var req = SteamConstants.STEAM_API + "IAuthenticationService/GetAuthSessionsForAccount/v1?access_token=" +
- accessToken;
-
- try
- {
- return await client.GetProto(req, new EmptyMessage(),
- cancellationToken);
- }
- catch (HttpRequestException ex)
- when (ex.StatusCode == HttpStatusCode.Unauthorized)
- {
- throw new SessionInvalidException(SessionInvalidException.GOT_401_MSG, ex);
- }
- }
-
- public static async Task GetAuthSessionInfo(HttpClient client, string accessToken,
- ulong clientId, CancellationToken cancellationToken = default)
- {
- var req = SteamConstants.STEAM_API + "IAuthenticationService/GetAuthSessionInfo/v1?access_token=" + accessToken;
- var reqData = new GetAuthSessionInfo_Request
- {
- ClientId = clientId
- };
- try
- {
- return await client.PostProto(req, reqData, cancellationToken);
- }
- catch (HttpRequestException ex)
- when (ex.StatusCode == HttpStatusCode.Unauthorized)
- {
- throw new SessionInvalidException(SessionInvalidException.GOT_401_MSG, ex);
- }
- }
-
-
- public static async Task UpdateAuthSessionStatus(HttpClient client, string accessToken, string sharedSecret,
- UpdateAuthSessionWithMobileConfirmation_Request request)
- {
- var req = SteamConstants.STEAM_API +
- "IAuthenticationService/UpdateAuthSessionWithMobileConfirmation/v1?access_token=" + accessToken;
-
- request.ComputeSignature(sharedSecret);
- await client.PostProtoEnsureSuccess(req, request);
- return true;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Api/SteamGlobalApi.cs b/SteamLibForked/Api/SteamGlobalApi.cs
deleted file mode 100644
index 226781c..0000000
--- a/SteamLibForked/Api/SteamGlobalApi.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using AchiesUtilities.Models;
-using AchiesUtilities.Newtonsoft.JSON.Converters.Special;
-using Newtonsoft.Json;
-using SteamLib.Authentication;
-using SteamLib.Core;
-using SteamLib.Core.Enums;
-using SteamLib.Core.StatusCodes;
-using SteamLib.Exceptions;
-using SteamLib.Exceptions.General;
-
-namespace SteamLib.Api;
-
-public static class SteamGlobalApi
-{
- ///
- /// Raw AccessToken value
- ///
- ///
- ///
- ///
- ///
- ///
- public static async Task RefreshJwt(HttpClient client, SteamDomain domain,
- CancellationToken cancellationToken = default)
- {
- var domainUri = SteamDomains.GetDomain(domain);
- var data = new Dictionary
- {
- {"redir", domainUri}
- };
- var cont = new FormUrlEncodedContent(data);
- var resp = await client.PostAsync("https://login.steampowered.com/jwt/ajaxrefresh", cont, cancellationToken);
- var respStr = await resp.EnsureSuccessStatusCode().Content.ReadAsStringAsync(cancellationToken);
-
- JwtRefreshJson? jwtRefresh;
- try
- {
- jwtRefresh = JsonConvert.DeserializeObject(respStr);
- }
- catch (Exception ex)
- {
- throw new UnsupportedResponseException(respStr, ex);
- }
-
- if (jwtRefresh?.Success != true)
- {
- Exception? inner = null;
- if (jwtRefresh?.Error != null)
- {
- var errorCode = jwtRefresh.Error.Value;
- var translated = SteamStatusCode.Translate(errorCode, out _);
- inner = new SteamStatusCodeException(translated, respStr);
- }
-
- throw new SessionInvalidException(
- "AjaxRefresh was not successful. 'steamRefresh_steam' cookie is missing or refresh token is invalid",
- inner);
- }
-
- data = new Dictionary
- {
- {"steamID", jwtRefresh.SteamId.ToString()},
- {"nonce", jwtRefresh.Nonce},
- {"redir", jwtRefresh.Redir},
- {"auth", jwtRefresh.Auth}
- };
-
- cont = new FormUrlEncodedContent(data);
- var update = await client.PostAsync(jwtRefresh.LoginUrl, cont, cancellationToken);
- var updateResp = await update.Content.ReadAsStringAsync(cancellationToken);
- JwtUpdateJson result;
- try
- {
- result = JsonConvert.DeserializeObject(updateResp) ?? throw new NullReferenceException();
- }
- catch (Exception ex)
- {
- throw new UnsupportedResponseException(updateResp, ex);
- }
-
- var resultStatus = SteamStatusCode.Translate(result.Result, out _);
- if (resultStatus.Equals(SteamStatusCode.Ok) == false)
- {
- throw new SessionInvalidException(
- "AjaxRefresh (set-token) response was not successful. Response string stored in Exception.Data")
- {
- Data = {{"Response", updateResp}}
- };
- }
-
- return SteamTokenHelper.ExtractJwtFromSetCookiesHeader(update.Headers);
- }
-
-
- private class JwtRefreshJson
- {
- [JsonProperty("success")] public bool Success { get; set; }
- [JsonProperty("login_url")] public string LoginUrl { get; set; } = string.Empty;
- [JsonProperty("steamID")] public long SteamId { get; set; }
- [JsonProperty("nonce")] public string Nonce { get; set; } = string.Empty;
- [JsonProperty("redir")] public string Redir { get; set; } = string.Empty;
- [JsonProperty("auth")] public string Auth { get; set; } = string.Empty;
- [JsonProperty("error")] public int? Error { get; set; }
- }
-
- private class JwtUpdateJson
- {
- [JsonProperty("result")] public int Result { get; set; }
-
- [JsonProperty("rtExpiry")]
- [JsonConverter(typeof(UnixTimeStampConverter))]
- public UnixTimeStamp RtExpiry { get; set; }
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/LoginExecutor.cs b/SteamLibForked/Authentication/Default/LoginExecutor.cs
deleted file mode 100644
index 90e7154..0000000
--- a/SteamLibForked/Authentication/Default/LoginExecutor.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using Microsoft.Extensions.Logging;
-using SteamLib.Authentication;
-using SteamLib.Core.Interfaces;
-using SteamLib.Exceptions;
-
-namespace SteamLib.Login.Default;
-
-[Obsolete("Method removed from Steam")]
-public class LoginExecutor
-{
- public static ILoginConsumer NullConsumer { get; } = new NullLoginConsumer();
- public ILoginConsumer Caller { get; }
- public HttpClient HttpClient { get; }
- public ILogger? Logger { get; init; }
- public IEmailProvider? EmailAuthProvider { get; init; }
- public ICaptchaResolver? CaptchaResolver { get; init; }
- public ISteamGuardProvider? SteamGuardProvider { get; init; }
-
- private LoginExecutor(LoginExecutorOptions options)
- {
- Caller = options.Consumer;
- HttpClient = options.HttpClient;
- Logger = options.Logger;
- EmailAuthProvider = options.EmailAuthProvider;
- SteamGuardProvider = options.SteamGuardProvider;
- CaptchaResolver = options.CaptchaResolver;
- }
-
-
- public static async Task DoLogin(LoginExecutorOptions options, string username, string password,
- CancellationToken cancellationToken = default) //TODO: logs
- {
- var executor = new LoginExecutor(options);
- var client = executor.HttpClient;
-
- LoginStage loginStage = new GetRsaStage(username);
- loginStage = await ((GetRsaStage) loginStage).Proceed(client, cancellationToken);
- cancellationToken.ThrowIfCancellationRequested();
-
- if (loginStage is ReadyToLoginStage rdyToLoginStage)
- {
- loginStage = await rdyToLoginStage.Proceed(client, password, string.Empty, cancellationToken);
- }
-
- cancellationToken.ThrowIfCancellationRequested();
- var twoFactorTry = 0;
- var emailTry = 0;
- while (loginStage.GetType() != typeof(LoginErrorStage) && loginStage is not LoginSuccessStage)
- {
- cancellationToken.ThrowIfCancellationRequested();
- switch (loginStage)
- {
- case CaptchaNeededStage captchaNeededStage:
- {
- if (executor.CaptchaResolver == null) throw new LoginException(LoginError.CaptchaRequired);
- var captchaText = await executor.CaptchaResolver.Resolve(captchaNeededStage.CaptchaImage, client);
- loginStage = await captchaNeededStage.Proceed(client, captchaText, cancellationToken);
- break;
- }
- case EmailAuthStage emailAuthStage:
- {
- if (executor.EmailAuthProvider == null) throw new LoginException(LoginError.EmailAuthRequired);
- if (emailTry > executor.EmailAuthProvider.MaxRetryCount)
- throw new LoginException(LoginError.InvalidEmailAuthCode);
- var code = await executor.EmailAuthProvider.GetEmailAuthCode(executor.Caller);
- loginStage = await emailAuthStage.Proceed(client, code, cancellationToken);
- emailTry++;
- break;
- }
- case TwoFactorStage twoFactorStage:
- {
- if (executor.SteamGuardProvider == null) throw new LoginException(LoginError.SteamGuardRequired);
- if (twoFactorTry > executor.SteamGuardProvider.MaxRetryCount)
- throw new LoginException(LoginError.InvalidTwoFactorCode);
- var twoFactor = await executor.SteamGuardProvider.GetSteamGuardCode(executor.Caller);
- loginStage = await twoFactorStage.Proceed(client, twoFactor, cancellationToken);
- twoFactorTry++;
- break;
- }
- case ReadyToLoginStage readyToLoginStage: //When captcha proceeded, stage goes there
- {
- loginStage = await readyToLoginStage.Proceed(client, password, string.Empty, cancellationToken);
- break;
- }
- default:
- throw new ArgumentOutOfRangeException(nameof(loginStage));
- }
- }
-
- if (loginStage is LoginErrorStage error)
- {
- var content = await error.Response.Content.ReadAsStringAsync(cancellationToken);
- if (content.Contains("The account name or password that you have entered is incorrect"))
- {
- throw new LoginException(LoginError.InvalidCredentials);
- }
-
- throw new LoginException(content);
- }
-
-
- if (loginStage is not LoginSuccessStage successStage)
- {
- throw new InvalidOperationException("Unexpected login stage at this point. " + loginStage.GetType())
- {
- Data = {{"stage", loginStage}}
- };
- }
-
- return successStage.TransferParameters;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/LoginExecutorOptions.cs b/SteamLibForked/Authentication/Default/LoginExecutorOptions.cs
deleted file mode 100644
index b8f93a4..0000000
--- a/SteamLibForked/Authentication/Default/LoginExecutorOptions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.Extensions.Logging;
-using SteamLib.Core.Interfaces;
-
-namespace SteamLib.Login.Default;
-
-public class LoginExecutorOptions
-{
- public ILoginConsumer Consumer { get; }
- public HttpClient HttpClient { get; }
- public ILogger? Logger { get; init; }
- public IEmailProvider? EmailAuthProvider { get; init; }
- public ICaptchaResolver? CaptchaResolver { get; init; }
- public ISteamGuardProvider? SteamGuardProvider { get; init; }
-
- public LoginExecutorOptions(ILoginConsumer consumer, HttpClient httpClient)
- {
- Consumer = consumer;
- HttpClient = httpClient;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/LoginResultJson.cs b/SteamLibForked/Authentication/Default/LoginResultJson.cs
deleted file mode 100644
index 47d3a8e..0000000
--- a/SteamLibForked/Authentication/Default/LoginResultJson.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Newtonsoft.Json;
-
-namespace SteamLib.Login.Default;
-
-#pragma warning disable CS8618
-///
-/// Class to Deserialize the json response strings after the login/>
-///
-internal class LoginResultJson
-{
- [JsonProperty("success")] public bool Success { get; set; }
- [JsonProperty("message")] public string Message { get; set; }
- [JsonProperty("captcha_needed")] public bool CaptchaNeeded { get; set; }
- [JsonProperty("captcha_gid")] public string CaptchaGid { get; set; }
- [JsonProperty("emailauth_needed")] public bool EmailAuthNeeded { get; set; }
- [JsonProperty("emailsteamid")] public string EmailSteamId { get; set; }
- [JsonProperty("requires_twofactor")] public bool RequiresTwoFactor { get; set; }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/LoginStage.cs b/SteamLibForked/Authentication/Default/LoginStage.cs
deleted file mode 100644
index bdcb1a8..0000000
--- a/SteamLibForked/Authentication/Default/LoginStage.cs
+++ /dev/null
@@ -1,252 +0,0 @@
-using AchiesUtilities.Web.Extensions;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using SteamLib.Authentication;
-using SteamLib.Utility;
-
-namespace SteamLib.Login.Default;
-
-internal abstract class LoginStage
-{
- protected Dictionary Data { get; }
-
- protected LoginStage()
- {
- Data = new Dictionary();
- }
-
- protected LoginStage(Dictionary data)
- {
- Data = data;
- }
-
- protected bool CheckIfLoginCompleted(LoginResultJson json)
- {
- return !json.CaptchaNeeded && !json.EmailAuthNeeded && !json.RequiresTwoFactor && json.Success;
- }
-
- protected async Task ConvertJson(HttpResponseMessage response)
- {
- response.EnsureSuccessStatusCode();
- var webResponseString = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject(webResponseString)!;
- }
-
- protected async Task CompleteLogin(HttpResponseMessage response)
- {
- var jsonStr = await response.Content.ReadAsStringAsync();
- var json = JObject.Parse(jsonStr);
- var transferParameters = json["transfer_parameters"]!.ToObject()!;
- return new LoginSuccessStage(transferParameters);
- }
-
- protected async Task LoginRequest(HttpClient client,
- CancellationToken cancellationToken = default)
- {
- return await client.PostAsync("https://steamcommunity.com/login/dologin", new FormUrlEncodedContent(Data),
- cancellationToken);
- }
-}
-
-internal class LoginErrorStage : LoginStage
-{
- public readonly int ErrorCode;
- public readonly string ErrorString;
- public readonly HttpResponseMessage Response;
- public readonly LoginStage Stage;
-
- public LoginErrorStage(string errorString, HttpResponseMessage responseMessage, LoginStage stage)
- {
- ErrorString = errorString;
- Stage = stage;
- ErrorCode = Utilities.GetSuccessCode(responseMessage.Content.ReadAsStringSync());
- Response = responseMessage;
- }
-}
-
-internal class GetRsaStage : LoginStage
-{
- public GetRsaStage(Dictionary data) : base(data)
- {
- }
-
- public GetRsaStage(string userName)
- {
- Data["username"] = userName;
- }
-
-
- ///
- ///
- ///
- ///
- /// if success
- public async Task Proceed(HttpClient client, CancellationToken cancellationToken = default)
- {
- var content = new FormUrlEncodedContent(Data);
- var response = await client.PostAsync("https://steamcommunity.com/login/getrsakey", content, cancellationToken);
- var responseString = await response.Content.ReadAsStringAsync(cancellationToken);
- var rsaJson = JsonConvert.DeserializeObject(responseString)!;
- if (!rsaJson.success)
- return new LoginErrorStage("Can't get RSA", response, this);
-
- Data["rsatimestamp"] = rsaJson.timestamp;
- return new ReadyToLoginStage(Data, rsaJson.publickey_exp, rsaJson.publickey_mod);
- }
-}
-
-internal class ReadyToLoginStage : LoginStage
-{
- private readonly string _publicKeyExp;
- private readonly string _publicKeyMod;
-
- internal ReadyToLoginStage(Dictionary data, string publicKeyExp, string publicKeyMod) : base(data)
- {
- _publicKeyExp = publicKeyExp;
- _publicKeyMod = publicKeyMod;
- }
-
- public async Task Proceed(HttpClient client, string password, string loginFriendlyName,
- CancellationToken cancellationToken = default)
- {
- var encryptedBase64Password =
- EncryptionHelper.ToBase64EncryptedPassword(_publicKeyExp, _publicKeyMod, password);
- var unixTimestamp = (int) DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
- Data["password"] = encryptedBase64Password;
- Data["remember_login"] = "true";
- Data["loginfriendlyname"] = loginFriendlyName;
- Data["donotcache"] =
- unixTimestamp + "000"; // Added three "0"'s because Steam has a weird unix timestamp interpretation.
-
- _ = await client.GetAsync("https://steamcommunity.com/", cancellationToken);
- var webResponse = await LoginRequest(client, cancellationToken);
- var result = await ConvertJson(webResponse);
-
- if (CheckIfLoginCompleted(result))
- {
- return await CompleteLogin(webResponse);
- }
-
- if (result.CaptchaNeeded)
- {
- return new CaptchaNeededStage(Data, result.CaptchaGid);
- }
-
- if (result.EmailAuthNeeded)
- {
- return new EmailAuthStage(Data);
- }
-
- if (result.RequiresTwoFactor)
- {
- return new TwoFactorStage(Data);
- }
-
- return new LoginErrorStage("Can't proceed login.", webResponse, this);
- }
-}
-
-internal class TwoFactorStage : LoginStage
-{
- internal TwoFactorStage(Dictionary data) : base(data)
- {
- }
-
- public async Task Proceed(HttpClient client, string twoFactorCode,
- CancellationToken cancellationToken = default)
- {
- Data["twofactorcode"] = twoFactorCode;
- var webResponse = await LoginRequest(client, cancellationToken);
- var result = await ConvertJson(webResponse);
-
- if (CheckIfLoginCompleted(result))
- {
- return await CompleteLogin(webResponse);
- }
-
- if (result.CaptchaNeeded)
- {
- return new CaptchaNeededStage(Data, result.CaptchaGid);
- }
-
- if (result.RequiresTwoFactor)
- {
- return new TwoFactorStage(Data);
- }
-
- return new LoginErrorStage("Can't proceed login. Bad TwoFactor code", webResponse, this);
- }
-}
-
-internal class EmailAuthStage : LoginStage
-{
- internal EmailAuthStage(Dictionary data) : base(data)
- {
- }
-
- public async Task Proceed(HttpClient client, string emailCode,
- CancellationToken cancellationToken = default)
- {
- Data["emailauth"] = emailCode;
- var webResponse = await LoginRequest(client, cancellationToken);
- var result = await ConvertJson(webResponse);
-
- if (CheckIfLoginCompleted(result))
- {
- return await CompleteLogin(webResponse);
- }
-
- if (result.CaptchaNeeded)
- {
- return new CaptchaNeededStage(Data, result.CaptchaGid);
- }
-
- if (result.EmailAuthNeeded)
- {
- return new EmailAuthStage(Data);
- }
-
-
- return new LoginErrorStage("Can't proceed login. Bad Email code", webResponse, this);
- }
-}
-
-internal class CaptchaNeededStage : LoginStage
-{
- internal Uri CaptchaImage { get; }
-
- public CaptchaNeededStage(Dictionary data, string captchaGid) : base(data)
- {
- captchaGid = Uri.EscapeDataString(captchaGid);
- Data["captchagid"] = captchaGid;
- CaptchaImage = new Uri("https://steamcommunity.com/login/rendercaptcha?gid=" + captchaGid);
- }
-
- ///
- ///
- ///
- ///
- ///
- /// or
- public async Task Proceed(HttpClient client, string captchaText,
- CancellationToken cancellationToken = default)
- {
- Data["captcha_text"] = captchaText;
- //When captcha required we need to do login from start
-
- var rsaStage = new GetRsaStage(Data);
- var res = await rsaStage.Proceed(client, cancellationToken);
-
- return res;
- }
-}
-
-internal class LoginSuccessStage : LoginStage
-{
- public TransferParameters TransferParameters { get; }
-
- public LoginSuccessStage(TransferParameters transferParameters)
- {
- TransferParameters = transferParameters;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/NullLoginConsumer.cs b/SteamLibForked/Authentication/Default/NullLoginConsumer.cs
deleted file mode 100644
index 0d23b9f..0000000
--- a/SteamLibForked/Authentication/Default/NullLoginConsumer.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using SteamLib.Core.Interfaces;
-
-namespace SteamLib.Login.Default;
-
-internal class NullLoginConsumer : ILoginConsumer
-{
- public string FriendlyName { get; } = "null";
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/Default/RsaKeyJson.cs b/SteamLibForked/Authentication/Default/RsaKeyJson.cs
deleted file mode 100644
index aea1a0a..0000000
--- a/SteamLibForked/Authentication/Default/RsaKeyJson.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// ReSharper disable InconsistentNaming
-// ReSharper disable IdentifierTypo
-
-#pragma warning disable CS8618
-
-namespace SteamLib.Login.Default;
-
-///
-/// Class to Deserialize the json response strings of the getResKey request/>
-///
-internal class RsaKeyJson
-{
- public bool success { get; set; }
- public string publickey_mod { get; set; }
- public string publickey_exp { get; set; }
- public string timestamp { get; set; }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs b/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs
deleted file mode 100644
index 1582f2e..0000000
--- a/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs
+++ /dev/null
@@ -1,254 +0,0 @@
-using AchiesUtilities.Web.Extensions;
-using Microsoft.Extensions.Logging;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using SteamLib.Account;
-using SteamLib.Core;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
-using SteamLib.Core.Models;
-using SteamLib.Core.StatusCodes;
-using SteamLib.Exceptions;
-using SteamLib.Login.Default;
-using SteamLib.ProtoCore;
-using SteamLib.ProtoCore.Enums;
-using SteamLib.ProtoCore.Exceptions;
-using SteamLib.ProtoCore.Services;
-using SteamLib.Utility;
-using SteamLib.Web;
-
-namespace SteamLib.Authentication.LoginV2;
-
-public class LoginV2Executor
-{
- public static ILoginConsumer NullConsumer { get; } = new NullLoginConsumer();
- public ILoginConsumer Caller { get; }
- public HttpClient HttpClient { get; }
- public ILogger? Logger { get; init; }
- public IEmailProvider? EmailAuthProvider { get; init; }
- public ICaptchaResolver? CaptchaResolver { get; init; }
- public ISteamGuardProvider? SteamGuardProvider { get; init; }
- public string WebsiteId { get; init; }
- public DeviceDetails DeviceDetails { get; init; }
-
- private LoginV2Executor(LoginV2ExecutorOptions options)
- {
- Caller = options.Consumer;
- HttpClient = options.HttpClient;
- Logger = options.Logger;
- EmailAuthProvider = options.EmailAuthProvider;
- SteamGuardProvider = options.SteamGuardProvider;
- WebsiteId = options.GetWebsiteIdOrDefault();
- DeviceDetails = options.DeviceDetails ?? DeviceDetails.CreateDefault();
- }
-
-
- ///
- /// Do log in on SteamCommunity.
- /// Some functions require proper SessionId. But contains only SteamCommunity related
- /// SessionId and some functions on other services may not work
- ///
- ///
- ///
- ///
- ///
- /// or depending on which token type is returned
- ///
- ///
- ///
- ///
- public static async Task DoLogin(LoginV2ExecutorOptions options, string username, string password,
- CancellationToken cancellationToken = default) //TODO: logs
- {
- var executor = new LoginV2Executor(options);
- var client = executor.HttpClient;
-
- var sessionId = await SteamWebApi.GetLoginSessionId(client, cancellationToken);
- var rsgMsg = new GetPasswordRSAPublicKey_Request
- {
- AccountName = username
- };
- var rsaResp = await client.GetProto(
- "https://api.steampowered.com/IAuthenticationService/GetPasswordRSAPublicKey/v1", rsgMsg,
- cancellationToken);
-
-
- var encodedPassword =
- EncryptionHelper.ToBase64EncryptedPassword(rsaResp.PublickKeyExp, rsaResp.PublickKeyMod, password);
-
-
- var beginAuthMsg = new BeginAuthSessionViaCredentials_Request
- {
- DeviceFriendlyName = string.Empty,
- AccountName = username,
- EncryptedPassword = encodedPassword,
- EncryptionTimestamp = rsaResp.Timestamp,
- RememberLogin = true,
- PlatformType = executor.DeviceDetails.PlatformType,
- Persistence = 1,
- WebsiteId = executor.WebsiteId,
- DeviceDetails = executor.DeviceDetails
- };
-
- BeginAuthSessionViaCredentials_Response beginAuthResp;
- try
- {
- beginAuthResp = await client.PostProto(
- "https://api.steampowered.com/IAuthenticationService/BeginAuthSessionViaCredentials/v1", beginAuthMsg,
- cancellationToken);
- }
- catch (EResultException ex)
- when (ex.Result == EResult.InvalidPassword)
- {
- throw new LoginException(LoginError.InvalidCredentials);
- }
-
-
- var clientId = beginAuthResp.ClientId;
- var steamId = (long) beginAuthResp.Steamid;
-
- var conf = beginAuthResp.AllowedConfirmations.FirstOrDefault(c =>
- c.ConfirmationType is EAuthSessionGuardType.EmailCode or EAuthSessionGuardType.DeviceCode);
-
- conf ??= beginAuthResp.AllowedConfirmations.FirstOrDefault();
-
- switch (conf?.ConfirmationType)
- {
- case EAuthSessionGuardType.None:
- break;
- case EAuthSessionGuardType.DeviceCode:
- case EAuthSessionGuardType.EmailCode:
- await UpdateWithCode(executor, clientId, (ulong) steamId, conf.ConfirmationType);
- break;
- case EAuthSessionGuardType.Unknown:
- case EAuthSessionGuardType.DeviceConfirmation:
- case EAuthSessionGuardType.EmailConfirmation:
- case EAuthSessionGuardType.MachineToken:
- case EAuthSessionGuardType.LegacyMachineAuth:
- throw new NotSupportedException(
- $"Auth confirmation type of {conf.ConfirmationType} is not implemented yet");
- default:
- throw new ArgumentOutOfRangeException(nameof(conf.ConfirmationType), conf?.ConfirmationType,
- "Unknown confirmation type or null");
- }
-
- var pollSessionMsg = new PollAuthSessionStatus_Request
- {
- ClientId = clientId,
- RequestId = beginAuthResp.RequestId
- };
-
- var pollResp =
- await client.PostProto(
- "https://api.steampowered.com/IAuthenticationService/PollAuthSessionStatus/v1", pollSessionMsg,
- cancellationToken);
-
- SteamAuthToken refreshToken;
- try
- {
- refreshToken = SteamTokenHelper.Parse(pollResp.RefreshToken);
- if (refreshToken.Type is not (SteamAccessTokenType.Refresh or SteamAccessTokenType.MobileRefresh))
- throw new ArgumentException(
- "Refresh token must be of type Refresh or MobileRefresh. No 'renew' audience found in JWT.",
- nameof(pollResp.RefreshToken)); //Argument exception for less code
- }
- catch (ArgumentException ex)
- {
- throw new LoginException(null,
- "Steam returned invalid refresh token or it's schema was unsupported. See inner exception for more details",
- LoginError.UndefinedError, ex);
- }
-
- var data = new Dictionary
- {
- {"nonce", pollResp.RefreshToken},
- {"sessionid", sessionId}
- };
-
- var finalize = await client.PostAsync("https://login.steampowered.com/jwt/finalizelogin",
- new FormUrlEncodedContent(data), cancellationToken);
- var finalizeContent = await finalize.EnsureSuccessStatusCode().Content.ReadAsStringAsync(cancellationToken);
-
- var finalizeResp =
- SteamLibErrorMonitor.HandleResponse(finalizeContent,
- () => JsonConvert.DeserializeObject(finalizeContent)!);
-
-
- List tokens = new();
- foreach (var transferInfo in finalizeResp.TransferInfo)
- {
- var transferData = new Dictionary
- {
- {"nonce", transferInfo.TransferInfoParams.Nonce},
- {"auth", transferInfo.TransferInfoParams.Auth},
- {"steamID", steamId.ToString()}
- };
-
-
- try
- {
- var req = new HttpRequestMessage(HttpMethod.Post, transferInfo.Url);
- req.Content = new FormUrlEncodedContent(transferData);
- req.Headers.Referrer = SteamDomains.GetDomainUri(SteamDomain.Store);
- var transferResp = await client.SendAsync(req, cancellationToken);
- var transferContent = await transferResp.ReadAsStringEnsureSuccessAsync(cancellationToken);
- var status = JObject.Parse(transferContent);
- var result = status["result"]?.Value();
- if (result != null)
- SteamStatusCode
- .ValidateSuccessOrThrow(result
- .Value); //TODO: Fix steam.tv token transfer (result always 8). But who really cares..
-
- var tokenStr = SteamTokenHelper.ExtractJwtFromSetCookiesHeader(transferResp.Headers);
- var token = SteamTokenHelper.Parse(tokenStr);
- tokens.Add(token);
- }
- catch (Exception ex)
- {
- executor.Logger?.Log(LogLevel.Warning, ex, "Can't transfer tokens for URI: {uri}", transferInfo.Url);
- }
- }
-
- var accessToken = SteamTokenHelper.Parse(pollResp.AccessToken);
-
- if (accessToken.Type == SteamAccessTokenType.Mobile)
- {
- return new MobileSessionData(sessionId, SteamId.FromSteam64(steamId), refreshToken, accessToken, tokens);
- }
-
- return new SessionData(sessionId, SteamId.FromSteam64(steamId), refreshToken, tokens);
- }
-
- private static async Task UpdateWithCode(LoginV2Executor executor, ulong clientId, ulong steamId,
- EAuthSessionGuardType guardType)
- {
- string? code;
- if (guardType == EAuthSessionGuardType.DeviceCode)
- {
- if (executor.SteamGuardProvider != null)
- code = await executor.SteamGuardProvider.GetSteamGuardCode(executor.Caller);
- else
- {
- throw new LoginException(LoginError.SteamGuardRequired);
- }
- }
- else
- {
- var t = executor.EmailAuthProvider?.GetEmailAuthCode(executor.Caller) ??
- throw new LoginException(LoginError.EmailAuthRequired);
- code = await t;
- }
-
- var updateCodeMsg = new UpdateAuthSessionWithSteamGuardCode_Request
- {
- ClientId = clientId,
- Code = code,
- CodeType = guardType,
- Steamid = steamId
- };
-
- await executor.HttpClient.PostProtoEnsureSuccess(
- new Uri("https://api.steampowered.com/IAuthenticationService/UpdateAuthSessionWithSteamGuardCode/v1"),
- updateCodeMsg);
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Enums/Country.cs b/SteamLibForked/Core/Enums/Country.cs
deleted file mode 100644
index 737e437..0000000
--- a/SteamLibForked/Core/Enums/Country.cs
+++ /dev/null
@@ -1,757 +0,0 @@
-// ReSharper disable All
-
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-
-namespace SteamLib.Core.Enums;
-
-public enum Country
-{
- Afghanistan,
- Aland_Islands,
- Albania,
- Algeria,
- American_Samoa,
- Andorra,
- Angola,
- Anguilla,
- Antigua_and_Barbuda,
- Argentina,
- Armenia,
- Aruba,
- Australia,
- Austria,
- Azerbaijan,
- Bahamas,
- Bahrain,
- Bangladesh,
- Barbados,
- Belarus,
- Belgium,
- Belize,
- Bhutan,
- Bolivia,
- Bosnia_and_Herzegovina,
- Botswana,
- Brazil,
- Brunei_Darussalam,
- Bulgaria,
- Burundi,
- Cambodia,
- Cameroon,
- Canada,
- Cape_Verde,
- Cayman_Islands,
- Chad,
- Chile,
- China,
- Colombia,
- Congo,
- Costa_Rica,
- Cote_d_Ivoire,
- Croatia,
- Cyprus,
- Czech_Republic,
- Denmark,
- Dominica,
- Dominican_Republic,
- Ecuador,
- Egypt,
- El_Salvador,
- Estonia,
- Eswatini,
- Ethiopia,
- Faroe_Islands,
- Finland,
- France,
- French_Guiana,
- French_Polynesia,
- Gabon,
- Georgia,
- Germany,
- Ghana,
- Gibraltar,
- Greece,
- Greenland,
- Grenada,
- Guadeloupe,
- Guam,
- Guatemala,
- Guernsey,
- Guyana,
- Haiti,
- Honduras,
- Hong_Kong,
- Hungary,
- Iceland,
- India,
- Indonesia,
- Iran,
- Iraq,
- Ireland,
- Isle_of_Man,
- Israel,
- Italy,
- Jamaica,
- Japan,
- Jersey,
- Jordan,
- Kazakhstan,
- Kenya,
- Korea,
- Kuwait,
- Kyrgyzstan,
- Laos,
- Latvia,
- Lebanon,
- Libya,
- Liechtenstein,
- Lithuania,
- Luxembourg,
- Macau,
- Macedonia,
- Madagascar,
- Malaysia,
- Maldives,
- Mali,
- Malta,
- Martinique,
- Mauritius,
- Mayotte,
- Mexico,
- Moldova,
- Monaco,
- Mongolia,
- Montenegro,
- Morocco,
- Mozambique,
- Myanmar,
- Namibia,
- Nepal,
- Netherlands,
- New_Zealand,
- Nicaragua,
- Nigeria,
- Northern_Mariana_Islands,
- Norway,
- Oman,
- Pakistan,
- Palestinian_Territory,
- Panama,
- Papua_New_Guinea,
- Paraguay,
- Peru,
- Philippines,
- Poland,
- Portugal,
- Puerto_Rico,
- Qatar,
- Reunion,
- Romania,
- Russian_Federation,
- Rwanda,
- Saint_Kitts_and_Nevis,
- Saint_Lucia,
- Saint_Vincent_and_the_Grenadines,
- Saudi_Arabia,
- Senegal,
- Serbia,
- Seychelles,
- Singapore,
- Slovakia,
- Slovenia,
- South_Africa,
- Spain,
- Sri_Lanka,
- Sudan,
- Suriname,
- Sweden,
- Switzerland,
- Taiwan,
- Tajikistan,
- Tanzania,
- Thailand,
- Togo,
- Trinidad_and_Tobago,
- Tunisia,
- Turkey,
- Turkmenistan,
- Turks_and_Caicos_Islands,
- Uganda,
- Ukraine,
- United_Arab_Emirates,
- United_Kingdom,
- United_States,
- Uruguay,
- Uzbekistan,
- Venezuela,
- Viet_Nam,
- Virgin_Islands,
- Yemen,
- Zambia,
- Zimbabwe
-}
-
-public static class CountryResolver
-{
- public static IReadOnlyDictionary ResolveByCountryCode = new ReadOnlyDictionary(
- new Dictionary()
- {
- {"US", Country.United_States},
- {"CA", Country.Canada},
- {"AF", Country.Afghanistan},
- {"AX", Country.Aland_Islands},
- {"AL", Country.Albania},
- {"DZ", Country.Algeria},
- {"AS", Country.American_Samoa},
- {"AD", Country.Andorra},
- {"AO", Country.Angola},
- {"AI", Country.Anguilla},
- {"AG", Country.Antigua_and_Barbuda},
- {"AR", Country.Argentina},
- {"AM", Country.Armenia},
- {"AW", Country.Aruba},
- {"AU", Country.Australia},
- {"AT", Country.Austria},
- {"AZ", Country.Azerbaijan},
- {"BS", Country.Bahamas},
- {"BH", Country.Bahrain},
- {"BD", Country.Bangladesh},
- {"BB", Country.Barbados},
- {"BY", Country.Belarus},
- {"BE", Country.Belgium},
- {"BZ", Country.Belize},
- {"BT", Country.Bhutan},
- {"BO", Country.Bolivia},
- {"BA", Country.Bosnia_and_Herzegovina},
- {"BW", Country.Botswana},
- {"BR", Country.Brazil},
- {"BN", Country.Brunei_Darussalam},
- {"BG", Country.Bulgaria},
- {"BI", Country.Burundi},
- {"KH", Country.Cambodia},
- {"CM", Country.Cameroon},
- {"CV", Country.Cape_Verde},
- {"KY", Country.Cayman_Islands},
- {"TD", Country.Chad},
- {"CL", Country.Chile},
- {"CN", Country.China},
- {"CO", Country.Colombia},
- {"CD", Country.Congo},
- {"CR", Country.Costa_Rica},
- {"CI", Country.Cote_d_Ivoire},
- {"HR", Country.Croatia},
- {"CY", Country.Cyprus},
- {"CZ", Country.Czech_Republic},
- {"DK", Country.Denmark},
- {"DM", Country.Dominica},
- {"DO", Country.Dominican_Republic},
- {"EC", Country.Ecuador},
- {"EG", Country.Egypt},
- {"SV", Country.El_Salvador},
- {"EE", Country.Estonia},
- {"ET", Country.Ethiopia},
- {"FO", Country.Faroe_Islands},
- {"FI", Country.Finland},
- {"FR", Country.France},
- {"GF", Country.French_Guiana},
- {"PF", Country.French_Polynesia},
- {"GA", Country.Gabon},
- {"GE", Country.Georgia},
- {"DE", Country.Germany},
- {"GH", Country.Ghana},
- {"GI", Country.Gibraltar},
- {"GR", Country.Greece},
- {"GL", Country.Greenland},
- {"GD", Country.Grenada},
- {"GP", Country.Guadeloupe},
- {"GU", Country.Guam},
- {"GT", Country.Guatemala},
- {"GG", Country.Guernsey},
- {"GY", Country.Guyana},
- {"HT", Country.Haiti},
- {"HN", Country.Honduras},
- {"HK", Country.Hong_Kong},
- {"HU", Country.Hungary},
- {"IS", Country.Iceland},
- {"IN", Country.India},
- {"ID", Country.Indonesia},
- {"IQ", Country.Iraq},
- {"IE", Country.Ireland},
- {"IR", Country.Iran},
- {"IM", Country.Isle_of_Man},
- {"IL", Country.Israel},
- {"IT", Country.Italy},
- {"JM", Country.Jamaica},
- {"JP", Country.Japan},
- {"JE", Country.Jersey},
- {"JO", Country.Jordan},
- {"KZ", Country.Kazakhstan},
- {"KE", Country.Kenya},
- {"KR", Country.Korea},
- {"KW", Country.Kuwait},
- {"KG", Country.Kyrgyzstan},
- {"LA", Country.Laos},
- {"LV", Country.Latvia},
- {"LB", Country.Lebanon},
- {"LY", Country.Libya},
- {"LI", Country.Liechtenstein},
- {"LT", Country.Lithuania},
- {"LU", Country.Luxembourg},
- {"MO", Country.Macau},
- {"MK", Country.Macedonia},
- {"MG", Country.Madagascar},
- {"MY", Country.Malaysia},
- {"MV", Country.Maldives},
- {"ML", Country.Mali},
- {"MT", Country.Malta},
- {"MQ", Country.Martinique},
- {"MU", Country.Mauritius},
- {"YT", Country.Mayotte},
- {"MX", Country.Mexico},
- {"MD", Country.Moldova},
- {"MC", Country.Monaco},
- {"MN", Country.Mongolia},
- {"ME", Country.Montenegro},
- {"MA", Country.Morocco},
- {"MZ", Country.Mozambique},
- {"MM", Country.Myanmar},
- {"NA", Country.Namibia},
- {"NP", Country.Nepal},
- {"NL", Country.Netherlands},
- {"NZ", Country.New_Zealand},
- {"NI", Country.Nicaragua},
- {"NG", Country.Nigeria},
- {"MP", Country.Northern_Mariana_Islands},
- {"NO", Country.Norway},
- {"OM", Country.Oman},
- {"PK", Country.Pakistan},
- {"PS", Country.Palestinian_Territory},
- {"PA", Country.Panama},
- {"PG", Country.Papua_New_Guinea},
- {"PY", Country.Paraguay},
- {"PE", Country.Peru},
- {"PH", Country.Philippines},
- {"PL", Country.Poland},
- {"PT", Country.Portugal},
- {"PR", Country.Puerto_Rico},
- {"QA", Country.Qatar},
- {"RE", Country.Reunion},
- {"RO", Country.Romania},
- {"RU", Country.Russian_Federation},
- {"RW", Country.Rwanda},
- {"LC", Country.Saint_Lucia},
- {"SA", Country.Saudi_Arabia},
- {"SN", Country.Senegal},
- {"RS", Country.Serbia},
- {"SC", Country.Seychelles},
- {"SG", Country.Singapore},
- {"SK", Country.Slovakia},
- {"SI", Country.Slovenia},
- {"ZA", Country.South_Africa},
- {"ES", Country.Spain},
- {"LK", Country.Sri_Lanka},
- {"KN", Country.Saint_Kitts_and_Nevis},
- {"PM", Country.Saint_Vincent_and_the_Grenadines},
- {"SD", Country.Sudan},
- {"SR", Country.Suriname},
- {"SE", Country.Sweden},
- {"CH", Country.Switzerland},
- {"TW", Country.Taiwan},
- {"TJ", Country.Tajikistan},
- {"TZ", Country.Tanzania},
- {"TH", Country.Thailand},
- {"TG", Country.Togo},
- {"TT", Country.Trinidad_and_Tobago},
- {"TN", Country.Tunisia},
- {"TR", Country.Turkey},
- {"TM", Country.Turkmenistan},
- {"TC", Country.Turks_and_Caicos_Islands},
- {"UG", Country.Uganda},
- {"UA", Country.Ukraine},
- {"GB", Country.United_Kingdom},
- {"VI", Country.Virgin_Islands},
- {"AE", Country.United_Arab_Emirates},
- {"UY", Country.Uruguay},
- {"UZ", Country.Uzbekistan},
- {"VE", Country.Venezuela},
- {"VN", Country.Viet_Nam},
- {"YE", Country.Yemen},
- {"ZM", Country.Zambia},
- {"ZW", Country.Zimbabwe}
- });
-
- public static IReadOnlyDictionary ResolveString { get; } = new Dictionary
- {
- {Country.Afghanistan, "Afghanistan"},
- {Country.Aland_Islands, "Aland Islands"},
- {Country.Albania, "Albania"},
- {Country.Algeria, "Algeria"},
- {Country.American_Samoa, "American Samoa"},
- {Country.Andorra, "Andorra"},
- {Country.Angola, "Angola"},
- {Country.Anguilla, "Anguilla"},
- {Country.Antigua_and_Barbuda, "Antigua and Barbuda"},
- {Country.Argentina, "Argentina"},
- {Country.Armenia, "Armenia"},
- {Country.Aruba, "Aruba"},
- {Country.Australia, "Australia"},
- {Country.Austria, "Austria"},
- {Country.Azerbaijan, "Azerbaijan"},
- {Country.Bahamas, "Bahamas"},
- {Country.Bahrain, "Bahrain"},
- {Country.Bangladesh, "Bangladesh"},
- {Country.Barbados, "Barbados"},
- {Country.Belarus, "Belarus"},
- {Country.Belgium, "Belgium"},
- {Country.Belize, "Belize"},
- {Country.Bhutan, "Bhutan"},
- {Country.Bolivia, "Bolivia"},
- {Country.Bosnia_and_Herzegovina, "Bosnia and Herzegovina"},
- {Country.Botswana, "Botswana"},
- {Country.Brazil, "Brazil"},
- {Country.Brunei_Darussalam, "Brunei Darussalam"},
- {Country.Bulgaria, "Bulgaria"},
- {Country.Burundi, "Burundi"},
- {Country.Cambodia, "Cambodia"},
- {Country.Cameroon, "Cameroon"},
- {Country.Canada, "Canada"},
- {Country.Cape_Verde, "Cape Verde"},
- {Country.Cayman_Islands, "Cayman Islands"},
- {Country.Chad, "Chad"},
- {Country.Chile, "Chile"},
- {Country.China, "China"},
- {Country.Colombia, "Colombia"},
- {Country.Congo, "Congo, the Democratic Republic of the"},
- {Country.Costa_Rica, "Costa Rica"},
- {Country.Cote_d_Ivoire, "Cote d'Ivoire"},
- {Country.Croatia, "Croatia"},
- {Country.Cyprus, "Cyprus"},
- {Country.Czech_Republic, "Czech Republic"},
- {Country.Denmark, "Denmark"},
- {Country.Dominica, "Dominica"},
- {Country.Dominican_Republic, "Dominican Republic"},
- {Country.Ecuador, "Ecuador"},
- {Country.Egypt, "Egypt"},
- {Country.El_Salvador, "El Salvador"},
- {Country.Estonia, "Estonia"},
- {Country.Eswatini, "Eswatini"},
- {Country.Ethiopia, "Ethiopia"},
- {Country.Faroe_Islands, "Faroe Islands"},
- {Country.Finland, "Finland"},
- {Country.France, "France"},
- {Country.French_Guiana, "French Guiana"},
- {Country.French_Polynesia, "French Polynesia"},
- {Country.Gabon, "Gabon"},
- {Country.Georgia, "Georgia"},
- {Country.Germany, "Germany"},
- {Country.Ghana, "Ghana"},
- {Country.Gibraltar, "Gibraltar"},
- {Country.Greece, "Greece"},
- {Country.Greenland, "Greenland"},
- {Country.Grenada, "Grenada"},
- {Country.Guadeloupe, "Guadeloupe"},
- {Country.Guam, "Guam"},
- {Country.Guatemala, "Guatemala"},
- {Country.Guernsey, "Guernsey"},
- {Country.Guyana, "Guyana"},
- {Country.Haiti, "Haiti"},
- {Country.Honduras, "Honduras"},
- {Country.Hong_Kong, "Hong Kong"},
- {Country.Hungary, "Hungary"},
- {Country.Iceland, "Iceland"},
- {Country.India, "India"},
- {Country.Indonesia, "Indonesia"},
- {Country.Iran, "Iran"},
- {Country.Iraq, "Iraq"},
- {Country.Ireland, "Ireland"},
- {Country.Isle_of_Man, "Isle of Man"},
- {Country.Israel, "Israel"},
- {Country.Italy, "Italy"},
- {Country.Jamaica, "Jamaica"},
- {Country.Japan, "Japan"},
- {Country.Jersey, "Jersey"},
- {Country.Jordan, "Jordan"},
- {Country.Kazakhstan, "Kazakhstan"},
- {Country.Kenya, "Kenya"},
- {Country.Korea, "Korea, Republic of"},
- {Country.Kuwait, "Kuwait"},
- {Country.Kyrgyzstan, "Kyrgyzstan"},
- {Country.Laos, "Lao People's Democratic Republic"},
- {Country.Latvia, "Latvia"},
- {Country.Lebanon, "Lebanon"},
- {Country.Libya, "Libya"},
- {Country.Liechtenstein, "Liechtenstein"},
- {Country.Lithuania, "Lithuania"},
- {Country.Luxembourg, "Luxembourg"},
- {Country.Macau, "Macau"},
- {Country.Macedonia, "Macedonia, the former Yugoslav Republic of"},
- {Country.Madagascar, "Madagascar"},
- {Country.Malaysia, "Malaysia"},
- {Country.Maldives, "Maldives"},
- {Country.Mali, "Mali"},
- {Country.Malta, "Malta"},
- {Country.Martinique, "Martinique"},
- {Country.Mauritius, "Mauritius"},
- {Country.Mayotte, "Mayotte"},
- {Country.Mexico, "Mexico"},
- {Country.Moldova, "Moldova, Republic of"},
- {Country.Monaco, "Monaco"},
- {Country.Mongolia, "Mongolia"},
- {Country.Montenegro, "Montenegro"},
- {Country.Morocco, "Morocco"},
- {Country.Mozambique, "Mozambique"},
- {Country.Myanmar, "Myanmar"},
- {Country.Namibia, "Namibia"},
- {Country.Nepal, "Nepal"},
- {Country.Netherlands, "Netherlands"},
- {Country.New_Zealand, "New Zealand"},
- {Country.Nicaragua, "Nicaragua"},
- {Country.Nigeria, "Nigeria"},
- {Country.Northern_Mariana_Islands, "Northern Mariana Islands"},
- {Country.Norway, "Norway"},
- {Country.Oman, "Oman"},
- {Country.Pakistan, "Pakistan"},
- {Country.Palestinian_Territory, "Palestinian Territory, Occupied"},
- {Country.Panama, "Panama"},
- {Country.Papua_New_Guinea, "Papua New Guinea"},
- {Country.Paraguay, "Paraguay"},
- {Country.Peru, "Peru"},
- {Country.Philippines, "Philippines"},
- {Country.Poland, "Poland"},
- {Country.Portugal, "Portugal"},
- {Country.Puerto_Rico, "Puerto Rico"},
- {Country.Qatar, "Qatar"},
- {Country.Reunion, "Reunion"},
- {Country.Romania, "Romania"},
- {Country.Russian_Federation, "Russian Federation"},
- {Country.Rwanda, "Rwanda"},
- {Country.Saint_Kitts_and_Nevis, "Saint Kitts and Nevis"},
- {Country.Saint_Lucia, "Saint Lucia"},
- {Country.Saint_Vincent_and_the_Grenadines, "Saint Vincent and the Grenadines"},
- {Country.Saudi_Arabia, "Saudi Arabia"},
- {Country.Senegal, "Senegal"},
- {Country.Serbia, "Serbia"},
- {Country.Seychelles, "Seychelles"},
- {Country.Singapore, "Singapore"},
- {Country.Slovakia, "Slovakia"},
- {Country.Slovenia, "Slovenia"},
- {Country.South_Africa, "South Africa"},
- {Country.Spain, "Spain"},
- {Country.Sri_Lanka, "Sri Lanka"},
- {Country.Sudan, "Sudan"},
- {Country.Suriname, "Suriname"},
- {Country.Sweden, "Sweden"},
- {Country.Switzerland, "Switzerland"},
- {Country.Taiwan, "Taiwan"},
- {Country.Tajikistan, "Tajikistan"},
- {Country.Tanzania, "Tanzania, United Republic of"},
- {Country.Thailand, "Thailand"},
- {Country.Togo, "Togo"},
- {Country.Trinidad_and_Tobago, "Trinidad and Tobago"},
- {Country.Tunisia, "Tunisia"},
- {Country.Turkey, "Turkey"},
- {Country.Turkmenistan, "Turkmenistan"},
- {Country.Turks_and_Caicos_Islands, "Turks and Caicos Islands"},
- {Country.Uganda, "Uganda"},
- {Country.Ukraine, "Ukraine"},
- {Country.United_Arab_Emirates, "United Arab Emirates"},
- {Country.United_Kingdom, "United Kingdom"},
- {Country.United_States, "United States"},
- {Country.Uruguay, "Uruguay"},
- {Country.Uzbekistan, "Uzbekistan"},
- {Country.Venezuela, "Venezuela"},
- {Country.Viet_Nam, "Viet Nam"},
- {Country.Virgin_Islands, "Virgin Islands, U.S."},
- {Country.Yemen, "Yemen"},
- {Country.Zambia, "Zambia"},
- {Country.Zimbabwe, "Zimbabwe"}
- };
-
- public static IReadOnlyDictionary ResolveCountry { get; } = new Dictionary()
- {
- {"Afghanistan", Country.Afghanistan},
- {"Aland Islands", Country.Aland_Islands},
- {"Albania", Country.Albania},
- {"Algeria", Country.Algeria},
- {"American Samoa", Country.American_Samoa},
- {"Andorra", Country.Andorra},
- {"Angola", Country.Angola},
- {"Anguilla", Country.Anguilla},
- {"Antigua and Barbuda", Country.Antigua_and_Barbuda},
- {"Argentina", Country.Argentina},
- {"Armenia", Country.Armenia},
- {"Aruba", Country.Aruba},
- {"Australia", Country.Australia},
- {"Austria", Country.Austria},
- {"Azerbaijan", Country.Azerbaijan},
- {"Bahamas", Country.Bahamas},
- {"Bahrain", Country.Bahrain},
- {"Bangladesh", Country.Bangladesh},
- {"Barbados", Country.Barbados},
- {"Belarus", Country.Belarus},
- {"Belgium", Country.Belgium},
- {"Belize", Country.Belize},
- {"Bhutan", Country.Bhutan},
- {"Bolivia", Country.Bolivia},
- {"Bosnia and Herzegovina", Country.Bosnia_and_Herzegovina},
- {"Botswana", Country.Botswana},
- {"Brazil", Country.Brazil},
- {"Brunei Darussalam", Country.Brunei_Darussalam},
- {"Bulgaria", Country.Bulgaria},
- {"Burundi", Country.Burundi},
- {"Cambodia", Country.Cambodia},
- {"Cameroon", Country.Cameroon},
- {"Canada", Country.Canada},
- {"Cape Verde", Country.Cape_Verde},
- {"Cayman Islands", Country.Cayman_Islands},
- {"Chad", Country.Chad},
- {"Chile", Country.Chile},
- {"China", Country.China},
- {"Colombia", Country.Colombia},
- {"Congo, the Democratic Republic of the", Country.Congo},
- {"Costa Rica", Country.Costa_Rica},
- {"Cote d'Ivoire", Country.Cote_d_Ivoire},
- {"Croatia", Country.Croatia},
- {"Cyprus", Country.Cyprus},
- {"Czech Republic", Country.Czech_Republic},
- {"Denmark", Country.Denmark},
- {"Dominica", Country.Dominica},
- {"Dominican Republic", Country.Dominican_Republic},
- {"Ecuador", Country.Ecuador},
- {"Egypt", Country.Egypt},
- {"El Salvador", Country.El_Salvador},
- {"Estonia", Country.Estonia},
- {"Eswatini", Country.Eswatini},
- {"Ethiopia", Country.Ethiopia},
- {"Faroe Islands", Country.Faroe_Islands},
- {"Finland", Country.Finland},
- {"France", Country.France},
- {"French Guiana", Country.French_Guiana},
- {"French Polynesia", Country.French_Polynesia},
- {"Gabon", Country.Gabon},
- {"Georgia", Country.Georgia},
- {"Germany", Country.Germany},
- {"Ghana", Country.Ghana},
- {"Gibraltar", Country.Gibraltar},
- {"Greece", Country.Greece},
- {"Greenland", Country.Greenland},
- {"Grenada", Country.Grenada},
- {"Guadeloupe", Country.Guadeloupe},
- {"Guam", Country.Guam},
- {"Guatemala", Country.Guatemala},
- {"Guernsey", Country.Guernsey},
- {"Guyana", Country.Guyana},
- {"Haiti", Country.Haiti},
- {"Honduras", Country.Honduras},
- {"Hong Kong", Country.Hong_Kong},
- {"Hungary", Country.Hungary},
- {"Iceland", Country.Iceland},
- {"India", Country.India},
- {"Indonesia", Country.Indonesia},
- {"Iran", Country.Iran},
- {"Iraq", Country.Iraq},
- {"Ireland", Country.Ireland},
- {"Isle of Man", Country.Isle_of_Man},
- {"Israel", Country.Israel},
- {"Italy", Country.Italy},
- {"Jamaica", Country.Jamaica},
- {"Japan", Country.Japan},
- {"Jersey", Country.Jersey},
- {"Jordan", Country.Jordan},
- {"Kazakhstan", Country.Kazakhstan},
- {"Kenya", Country.Kenya},
- {"Korea, Republic of", Country.Korea},
- {"Kuwait", Country.Kuwait},
- {"Kyrgyzstan", Country.Kyrgyzstan},
- {"Lao People's Democratic Republic", Country.Laos},
- {"Latvia", Country.Latvia},
- {"Lebanon", Country.Lebanon},
- {"Libya", Country.Libya},
- {"Liechtenstein", Country.Liechtenstein},
- {"Lithuania", Country.Lithuania},
- {"Luxembourg", Country.Luxembourg},
- {"Macau", Country.Macau},
- {"Macedonia, the former Yugoslav Republic of", Country.Macedonia},
- {"Madagascar", Country.Madagascar},
- {"Malaysia", Country.Malaysia},
- {"Maldives", Country.Maldives},
- {"Mali", Country.Mali},
- {"Malta", Country.Malta},
- {"Martinique", Country.Martinique},
- {"Mauritius", Country.Mauritius},
- {"Mayotte", Country.Mayotte},
- {"Mexico", Country.Mexico},
- {"Moldova, Republic of", Country.Moldova},
- {"Monaco", Country.Monaco},
- {"Mongolia", Country.Mongolia},
- {"Montenegro", Country.Montenegro},
- {"Morocco", Country.Morocco},
- {"Mozambique", Country.Mozambique},
- {"Myanmar", Country.Myanmar},
- {"Namibia", Country.Namibia},
- {"Nepal", Country.Nepal},
- {"Netherlands", Country.Netherlands},
- {"New Zealand", Country.New_Zealand},
- {"Nicaragua", Country.Nicaragua},
- {"Nigeria", Country.Nigeria},
- {"Northern Mariana Islands", Country.Northern_Mariana_Islands},
- {"Norway", Country.Norway},
- {"Oman", Country.Oman},
- {"Pakistan", Country.Pakistan},
- {"Palestinian Territory, Occupied", Country.Palestinian_Territory},
- {"Panama", Country.Panama},
- {"Papua New Guinea", Country.Papua_New_Guinea},
- {"Paraguay", Country.Paraguay},
- {"Peru", Country.Peru},
- {"Philippines", Country.Philippines},
- {"Poland", Country.Poland},
- {"Portugal", Country.Portugal},
- {"Puerto Rico", Country.Puerto_Rico},
- {"Qatar", Country.Qatar},
- {"Reunion", Country.Reunion},
- {"Romania", Country.Romania},
- {"Russian Federation", Country.Russian_Federation},
- {"Rwanda", Country.Rwanda},
- {"Saint Kitts and Nevis", Country.Saint_Kitts_and_Nevis},
- {"Saint Lucia", Country.Saint_Lucia},
- {"Saint Vincent and the Grenadines", Country.Saint_Vincent_and_the_Grenadines},
- {"Saudi Arabia", Country.Saudi_Arabia},
- {"Senegal", Country.Senegal},
- {"Serbia", Country.Serbia},
- {"Seychelles", Country.Seychelles},
- {"Singapore", Country.Singapore},
- {"Slovakia", Country.Slovakia},
- {"Slovenia", Country.Slovenia},
- {"South Africa", Country.South_Africa},
- {"Spain", Country.Spain},
- {"Sri Lanka", Country.Sri_Lanka},
- {"Sudan", Country.Sudan},
- {"Suriname", Country.Suriname},
- {"Sweden", Country.Sweden},
- {"Switzerland", Country.Switzerland},
- {"Taiwan", Country.Taiwan},
- {"Tajikistan", Country.Tajikistan},
- {"Tanzania, United Republic of", Country.Tanzania},
- {"Thailand", Country.Thailand},
- {"Togo", Country.Togo},
- {"Trinidad and Tobago", Country.Trinidad_and_Tobago},
- {"Tunisia", Country.Tunisia},
- {"Turkey", Country.Turkey},
- {"Turkmenistan", Country.Turkmenistan},
- {"Turks and Caicos Islands", Country.Turks_and_Caicos_Islands},
- {"Uganda", Country.Uganda},
- {"Ukraine", Country.Ukraine},
- {"United Arab Emirates", Country.United_Arab_Emirates},
- {"United Kingdom", Country.United_Kingdom},
- {"United States", Country.United_States},
- {"Uruguay", Country.Uruguay},
- {"Uzbekistan", Country.Uzbekistan},
- {"Venezuela", Country.Venezuela},
- {"Viet Nam", Country.Viet_Nam},
- {"Virgin Islands, U.S.", Country.Virgin_Islands},
- {"Yemen", Country.Yemen},
- {"Zambia", Country.Zambia},
- {"Zimbabwe", Country.Zimbabwe}
- };
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Enums/Currency.cs b/SteamLibForked/Core/Enums/Currency.cs
deleted file mode 100644
index ed7c6e5..0000000
--- a/SteamLibForked/Core/Enums/Currency.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-// ReSharper disable InconsistentNaming
-
-namespace SteamLib.Core.Enums;
-
-public enum Currency
-{
- None = 0,
- USD = 1,
- GBP = 2,
- EUR = 3,
- CHF = 4,
- RUB = 5,
- PLN = 6,
- BRL = 7,
- JPY = 8,
- NOK = 9,
- IDR = 10,
- MYR = 11,
- PHP = 12,
- SGD = 13,
- THB = 14,
- VND = 15,
- KRW = 16,
- TRY = 17,
- UAH = 18,
- MXN = 19,
- CAD = 20,
- AUD = 21,
- NZD = 22,
- CNY = 23,
- INR = 24,
- CLP = 25,
- PEN = 26,
- COP = 27,
- ZAR = 28,
- HKD = 29,
- TWD = 30,
- SAR = 31,
- AED = 32,
- ARS = 34,
- ILS = 35,
- KZT = 37,
- KWD = 38,
- QAR = 39,
- CRC = 40,
- UYU = 41
-}
-
-public static class CurrencyInfo
-{
- public static IReadOnlyDictionary CurrencySymbols { get; } = new Dictionary
- {
- {Currency.USD, "$"},
- {Currency.GBP, "£"},
- {Currency.EUR, "€"},
- {Currency.CHF, "CHF"},
- {Currency.RUB, "pуб."},
- {Currency.PLN, "zł"},
- {Currency.BRL, "R$"},
- {Currency.JPY, "¥"},
- {Currency.NOK, "kr"},
- {Currency.IDR, "Rp"},
- {Currency.MYR, "RM"},
- {Currency.PHP, "P"},
- {Currency.SGD, "S$"},
- {Currency.THB, "฿"},
- {Currency.VND, "₫"},
- {Currency.KRW, "₩"},
- {Currency.TRY, "TL"},
- {Currency.UAH, "₴"},
- {Currency.MXN, "Mex$"},
- {Currency.CAD, "CDN$"},
- {Currency.AUD, "A$"},
- {Currency.NZD, "NZ$"},
- {Currency.CNY, "¥"},
- {Currency.INR, "₹"},
- {Currency.CLP, "CLP$"},
- {Currency.PEN, "S/."},
- {Currency.COP, "COL$"},
- {Currency.ZAR, "R"},
- {Currency.HKD, "HK$"},
- {Currency.TWD, "NT$"},
- {Currency.SAR, "SR"},
- {Currency.AED, "AED"},
- {Currency.ARS, "ARS$"},
- {Currency.ILS, "₪"},
- {Currency.KZT, "₸"},
- {Currency.KWD, "KD"},
- {Currency.QAR, "QR"},
- {Currency.CRC, "₡"},
- {Currency.UYU, "$U"}
- };
-
- public static int ToInt(this Currency currency)
- {
- return (int) currency;
- }
-
- public static string ToIntString(this Currency currency)
- {
- return currency.ToInt().ToString();
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Enums/SteamDomain.cs b/SteamLibForked/Core/Enums/SteamDomain.cs
deleted file mode 100644
index ea87a28..0000000
--- a/SteamLibForked/Core/Enums/SteamDomain.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace SteamLib.Core.Enums;
-
-public enum SteamDomain
-{
- Undefined = 0,
- Community = 1,
- Store = 2,
- Help = 3,
- TV = 4,
- Checkout = 5
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Interfaces/ICaptchaResolver.cs b/SteamLibForked/Core/Interfaces/ICaptchaResolver.cs
deleted file mode 100644
index a2d75d5..0000000
--- a/SteamLibForked/Core/Interfaces/ICaptchaResolver.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace SteamLib.Core.Interfaces;
-
-public interface ICaptchaResolver
-{
- public Task Resolve(Uri imageUrl, HttpClient client);
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Interfaces/IEmailAuthProvider.cs b/SteamLibForked/Core/Interfaces/IEmailAuthProvider.cs
deleted file mode 100644
index 6d12ef0..0000000
--- a/SteamLibForked/Core/Interfaces/IEmailAuthProvider.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace SteamLib.Core.Interfaces;
-
-public enum EmailConfirmationType
-{
- AttachPhoneAuthenticator
-}
-
-public interface IEmailProvider
-{
- public int MaxRetryCount { get; }
- public Task GetEmailAuthCode(ILoginConsumer caller);
- public Task GetAddAuthenticatorCode(ILoginConsumer caller);
-
- public Task ConfirmEmailLink(ILoginConsumer caller, EmailConfirmationType confirmationType);
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Interfaces/ILoginConsumer.cs b/SteamLibForked/Core/Interfaces/ILoginConsumer.cs
deleted file mode 100644
index 82dacd5..0000000
--- a/SteamLibForked/Core/Interfaces/ILoginConsumer.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace SteamLib.Core.Interfaces;
-
-public interface ILoginConsumer
-{
- public string FriendlyName { get; }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Interfaces/ISteamGuardProvider.cs b/SteamLibForked/Core/Interfaces/ISteamGuardProvider.cs
deleted file mode 100644
index dacbb88..0000000
--- a/SteamLibForked/Core/Interfaces/ISteamGuardProvider.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace SteamLib.Core.Interfaces;
-
-public interface ISteamGuardProvider
-{
- public int MaxRetryCount { get; }
- public ValueTask GetSteamGuardCode(ILoginConsumer caller);
-}
\ No newline at end of file
diff --git a/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs b/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs
deleted file mode 100644
index 3c9cc69..0000000
--- a/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs
+++ /dev/null
@@ -1,174 +0,0 @@
-using System.Collections.ObjectModel;
-using AchiesUtilities.Models;
-using SteamLib.Exceptions;
-using SteamLib.Utility;
-
-namespace SteamLib.Core.StatusCodes;
-
-public partial class SteamStatusCode : Enumeration
-{
- public static IReadOnlyDictionary StatusCodes { get; }
-
- static SteamStatusCode()
- {
- StatusCodes =
- new ReadOnlyDictionary(GetAll()
- .ToDictionary(ssc => ssc.Id, ssc => ssc));
- }
-
- protected SteamStatusCode(int id, string name) : base(id, name)
- {
- }
-
- ///
- /// Tries to translate status code. If no status code was found with
- /// will be thrown
- ///
- ///
- ///
- ///
- ///
- /// if value is universal. if value is
- /// specific
- ///
- ///
- public static SteamStatusCode Translate(string response, out bool isUniversal) where T : SteamStatusCode
- {
- int statusCode;
- try
- {
- statusCode = Utilities.GetSuccessCode(response);
- }
- catch
- {
- throw new SteamStatusCodeException(Undefined, response);
- }
-
- return Translate(statusCode, out isUniversal);
- }
-
-
- ///
- /// Translate to specific or
- ///
- ///
- ///
- ///
- ///
- /// if value is universal. if value is
- /// specific
- ///
- ///
- public static SteamStatusCode Translate(int statusCode, out bool isUniversal) where T : SteamStatusCode
- {
- if (statusCode < 2)
- {
- var status = StatusCodes[statusCode];
- isUniversal = true;
- return status;
- }
-
- var allSpecific = GetAll();
- var translated = allSpecific.FirstOrDefault(s => s.Id == statusCode);
-
- isUniversal = translated == null;
-
- if (translated != null)
- {
- return translated;
- }
-
- if (translated == null && StatusCodes.TryGetValue(statusCode, out var universal))
- {
- return universal;
- }
-
- return translated ?? new SteamStatusCode(statusCode, nameof(Unknown));
- }
-
-
- public override bool Equals(object? obj)
- {
- if (obj is not SteamStatusCode translated)
- return false;
-
- if (Id < 2)
- {
- return translated.Id == Id;
- }
-
- return base.Equals(translated);
- }
-
- public override int GetHashCode()
- {
- return base.GetHashCode();
- }
-
-
- ///
- ///
- ///
- ///
- public static void ValidateSuccessOrThrow(string response) where T : SteamStatusCode
- {
- var translated = Translate(response, out _);
- if (translated.Id != 1)
- throw new SteamStatusCodeException(translated, response);
- }
-
- ///
- /// Same as with generic parameter
- ///
- /// (Used in case when steam status code is not defined for this operation)
- ///
- ///
- ///
- public static void ValidateSuccessOrThrow(string response)
- {
- ValidateSuccessOrThrow(response);
- }
-
- ///
- ///
- ///
- ///
- public static void ValidateSuccessOrThrow(int statusCode) where T : SteamStatusCode
- {
- if (statusCode == 1) return;
- var translated = Translate(statusCode, out _);
- throw new SteamStatusCodeException(translated, statusCode.ToString());
- }
-
-
- ///
- /// Same as with generic parameter
- /// (Used in case when steam status code is not defined for this operation)
- ///
- ///
- ///
- public static void ValidateSuccessOrThrow(int statusCode)
- {
- ValidateSuccessOrThrow(statusCode);
- }
-
- ///
- /// Validates that status code is or specific
- ///
- ///
- ///
- ///
- ///
- public static SteamStatusCode TranslateOrThrow(string response, out bool isUniversal) where T : SteamStatusCode
- {
- var translated = Translate(response, out isUniversal);
- if (translated.Id < 1)
- throw new SteamStatusCodeException(translated, response);
- return translated;
- }
-
- public override string ToString()
- {
- return $"{Name} ({Id})";
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Exceptions/LoginException.cs b/SteamLibForked/Exceptions/LoginException.cs
deleted file mode 100644
index 8a39f64..0000000
--- a/SteamLibForked/Exceptions/LoginException.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using SteamLib.Core.Interfaces;
-
-namespace SteamLib.Exceptions;
-
-public class LoginException : Exception
-{
- public LoginError Error { get; }
- public string? Response { get; }
-
- public LoginException(LoginError error)
- : base($"Login was unsuccessful. Error {error}")
- {
- Error = error;
- }
-
- public LoginException(string response)
- {
- Error = LoginError.UndefinedError;
- Response = response;
- }
-
- public LoginException(string? response, string? message, LoginError? error, Exception? innerException) : base(
- message, innerException)
- {
- Response = response;
- Error = error ?? LoginError.UndefinedError;
- }
-}
-
-public enum LoginError
-{
- CaptchaRequired,
- InvalidCredentials,
- InvalidEmailAuthCode,
- InvalidTwoFactorCode,
-
- ///
- /// SteamEmail authentication is required to login but no was provided
- ///
- EmailAuthRequired,
-
- ///
- /// SteamGuard is required to login but no was provided
- ///
- SteamGuardRequired,
-
- ///
- /// Some error occurred while trying to login.
- ///
- UndefinedError
-}
\ No newline at end of file
diff --git a/SteamLibForked/Exceptions/SteamStatusCodeException.cs b/SteamLibForked/Exceptions/SteamStatusCodeException.cs
deleted file mode 100644
index fc8199c..0000000
--- a/SteamLibForked/Exceptions/SteamStatusCodeException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using SteamLib.Core.StatusCodes;
-
-namespace SteamLib.Exceptions;
-
-public class SteamStatusCodeException : Exception
-{
- public SteamStatusCode StatusCode { get; }
- public string? Response { get; }
-
- public SteamStatusCodeException(SteamStatusCode statusCode, string? response, Exception? innerException = null)
- : base($"Steam return not successful status code {statusCode}", innerException)
- {
- StatusCode = statusCode;
- Response = response;
- }
-
- public SteamStatusCodeException(string message, SteamStatusCode statusCode, string? response = null,
- Exception? innerException = null)
- : base(message, innerException)
- {
- StatusCode = statusCode;
- Response = response;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/ProtoCore/Exceptions/EResutException.cs b/SteamLibForked/ProtoCore/Exceptions/EResutException.cs
deleted file mode 100644
index 81dadf4..0000000
--- a/SteamLibForked/ProtoCore/Exceptions/EResutException.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using SteamLib.ProtoCore.Enums;
-
-namespace SteamLib.ProtoCore.Exceptions;
-
-[Serializable]
-public class EResultException : Exception
-{
- public EResult Result { get; }
-
- public EResultException()
- {
- }
-
- public EResultException(EResult result) : base("EResult error: " + result)
- {
- Result = result;
- }
-
- public EResultException(string message, EResult result, Exception inner) : base(message, inner)
- {
- Result = result;
- }
-
- public EResultException(EResult result, Exception inner) : base("EResult error: " + result, inner)
- {
- Result = result;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/ProtoCore/Exceptions/UnknownEResultException.cs b/SteamLibForked/ProtoCore/Exceptions/UnknownEResultException.cs
deleted file mode 100644
index 099c2d8..0000000
--- a/SteamLibForked/ProtoCore/Exceptions/UnknownEResultException.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace SteamLib.ProtoCore.Exceptions;
-
-[Serializable]
-public class UnknownEResultException : Exception
-{
- public int EResult { get; }
-
- public UnknownEResultException()
- {
- }
-
- public UnknownEResultException(int eResult) : base("Got unknown EResult: " + eResult)
- {
- EResult = eResult;
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/SteamLibForked.csproj b/SteamLibForked/SteamLibForked.csproj
deleted file mode 100644
index 7d959fe..0000000
--- a/SteamLibForked/SteamLibForked.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs b/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs
deleted file mode 100644
index 1e346d5..0000000
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-namespace SteamLib.Utility.MafileSerialization;
-
-public partial class MafileSerializer //Write
-{
- private const string CREDITS_PROPERTY_NAME = "Credits";
-
- public static string Serialize(MobileDataExtended mobileData, Formatting formatting = Formatting.Indented,
- bool sign = true, MafileCredits? credits = null)
- {
- using var w = new StringWriter();
- using var write = new JsonTextWriter(w);
- write.Formatting = formatting;
- var j = JObject.FromObject(mobileData);
- j.Add(SIGNATURE_PROPERTY_NAME, MAFILE_VERSION);
- if (sign)
- {
- credits ??= MafileCredits.Instance;
- var obj = JObject.FromObject(credits);
- j.Add(CREDITS_PROPERTY_NAME, obj);
- }
-
- j.WriteTo(write);
- return w.ToString();
- }
-
- public static async Task SerializeAsync(MobileDataExtended mobileData,
- Formatting formatting = Formatting.Indented, bool sign = true, MafileCredits? credits = null)
- {
- await using var w = new StringWriter();
- await using var write = new JsonTextWriter(w);
- write.Formatting = formatting;
- var j = JObject.FromObject(mobileData);
- j.Add(SIGNATURE_PROPERTY_NAME, j);
- if (sign)
- {
- credits ??= MafileCredits.Instance;
- var obj = JObject.FromObject(credits);
- j.Add(CREDITS_PROPERTY_NAME, obj);
- }
-
-
- await j.WriteToAsync(write);
- return w.ToString();
- }
-
- public static string SerializeLegacy(MobileData mobileData, Formatting formatting,
- Dictionary? additionalProperties = null, bool sign = true, MafileCredits? credits = null)
- {
- var result = new LegacyMafile
- {
- SharedSecret = mobileData.SharedSecret,
- IdentitySecret = mobileData.IdentitySecret,
- DeviceId = mobileData.DeviceId
- };
-
- if (mobileData is MobileDataExtended ext)
- {
- result.RevocationCode = ext.RevocationCode ?? string.Empty;
- result.AccountName = ext.AccountName;
- result.SessionData = ext.SessionData == null
- ? null
- : new
- {
- AccessToken = ext.SessionData?.MobileToken?.Token,
- steamLoginSecure = ext.SessionData?.MobileToken?.SignedToken,
- RefreshToken = ext.SessionData?.RefreshToken.Token,
- SteamID = ext.SessionData?.SteamId.Steam64.Id,
- SessionID = ext.SessionData?.SessionId
- };
- result.ServerTime = ext.ServerTime;
- result.SerialNumber = ext.SerialNumber.ToString();
- result.Uri = ext.Uri;
- result.TokenGid = ext.TokenGid;
- result.Secret1 = ext.Secret1;
- result.SteamId = ext.SteamId.Steam64.Id;
- }
-
-
- using var w = new StringWriter();
- using var write = new JsonTextWriter(w);
- write.Formatting = formatting;
- var j = JObject.FromObject(result);
- if (additionalProperties != null)
- {
- foreach (var (name, value) in additionalProperties)
- {
- JToken? jToken = null;
- if (value != null)
- {
- jToken = JToken.FromObject(value);
- }
-
- j.Add(name, jToken);
- }
- }
-
- if (sign)
- {
- credits ??= MafileCredits.Instance;
- var obj = JObject.FromObject(credits);
- j.Add(CREDITS_PROPERTY_NAME, obj);
- }
-
- j.WriteTo(write);
- return w.ToString();
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Web/Converters/StringToLongIfNeededConverter.cs b/SteamLibForked/Web/Converters/StringToLongIfNeededConverter.cs
deleted file mode 100644
index 0f06f41..0000000
--- a/SteamLibForked/Web/Converters/StringToLongIfNeededConverter.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Newtonsoft.Json;
-
-namespace SteamLib.Web.Converters;
-
-public class StringToLongIfNeededConverter : JsonConverter
-{
- public override void WriteJson(JsonWriter writer, string? value, JsonSerializer serializer)
- {
- writer.WriteValue(value);
- }
-
- public override string ReadJson(JsonReader reader, Type objectType, string? existingValue, bool hasExistingValue,
- JsonSerializer serializer)
- {
- return reader.Value?.ToString() ?? "null";
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Web/Models/GlobalMarketInfo/GlobalInfoModel.cs b/SteamLibForked/Web/Models/GlobalMarketInfo/GlobalInfoModel.cs
deleted file mode 100644
index d0da1cf..0000000
--- a/SteamLibForked/Web/Models/GlobalMarketInfo/GlobalInfoModel.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using JetBrains.Annotations;
-
-#pragma warning disable CS8618
-
-namespace SteamLib.Web.Models.GlobalMarketInfo;
-
-[PublicAPI]
-public class GlobalInfoModel
-{
- [MemberNotNullWhen(true, nameof(SteamId))]
- public bool IsLoggedIn { get; set; }
-
- ///
- /// if is or wallet doesn't exist
- ///
- public MarketWalletSchema? WalletInfo { get; set; }
-
- public bool RequiresBillingInfo { get; set; }
- public bool HasBillingStates { get; set; }
- public string CountryCode { get; set; }
- public string Language { get; set; }
- public long? SteamId { get; set; }
- public string SessionId { get; set; }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Web/Models/GlobalMarketInfo/MarketWalletSchema.cs b/SteamLibForked/Web/Models/GlobalMarketInfo/MarketWalletSchema.cs
deleted file mode 100644
index 617707c..0000000
--- a/SteamLibForked/Web/Models/GlobalMarketInfo/MarketWalletSchema.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using AchiesUtilities.Newtonsoft.JSON.Converters.Common;
-using Newtonsoft.Json;
-using SteamLib.Core.Enums;
-
-#pragma warning disable CS8618
-
-namespace SteamLib.Web.Models.GlobalMarketInfo;
-
-public class MarketWalletSchema
-{
- [JsonProperty("wallet_currency")] public Currency WalletCurrency { get; set; }
-
- [JsonProperty("wallet_country")] public string WalletCountry { get; set; }
-
- [JsonProperty("wallet_state")] public string WalletState { get; set; }
-
- [JsonProperty("wallet_fee")]
- [JsonConverter(typeof(IntToStringConverter))]
- public int WalletFee { get; set; }
-
- [JsonProperty("wallet_fee_minimum")]
- [JsonConverter(typeof(IntToStringConverter))]
- public int WalletFeeMinimum { get; set; }
-
- [JsonProperty("wallet_fee_percent")]
- [JsonConverter(typeof(DecimalToStringConverter))]
- public decimal WalletFeePercent { get; set; }
-
- [JsonProperty("wallet_publisher_fee_percent_default")]
- [JsonConverter(typeof(DecimalToStringConverter))]
- public decimal WalletPublisherFeePercentDefault { get; set; }
-
- [JsonProperty("wallet_fee_base")]
- [JsonConverter(typeof(IntToStringConverter))]
- public int WalletFeeBase { get; set; }
-
- [JsonProperty("wallet_balance")]
- [JsonConverter(typeof(LongToStringConverter))]
- public long WalletBalance { get; set; }
-
- [JsonProperty("wallet_delayed_balance")]
- [JsonConverter(typeof(LongToStringConverter))]
- public long WalletDelayedBalance { get; set; }
-
- [JsonProperty("wallet_max_balance")]
- [JsonConverter(typeof(LongToStringConverter))]
- public long WalletMaxBalance { get; set; }
-
- [JsonProperty("wallet_trade_max_balance")]
- [JsonConverter(typeof(LongToStringConverter))]
- public long WalletTradeMaxBalance { get; set; }
-
- [JsonProperty("success")] public int Success { get; set; }
-
- [JsonProperty("rwgrsn")] public int Rwgrsn { get; set; }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Web/Scrappers/HTML/MarketGlobalInfoScrapper.cs b/SteamLibForked/Web/Scrappers/HTML/MarketGlobalInfoScrapper.cs
deleted file mode 100644
index 5634c33..0000000
--- a/SteamLibForked/Web/Scrappers/HTML/MarketGlobalInfoScrapper.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System.Text.RegularExpressions;
-using HtmlAgilityPack;
-using Newtonsoft.Json;
-using SteamLib.Web.Models.GlobalMarketInfo;
-
-namespace SteamLib.Web.Scrappers.HTML;
-
-public static class MarketGlobalInfoScrapper
-{
- private static readonly Regex LoggedInRegex = new("var g_bLoggedIn = (.+);", RegexOptions.Compiled);
-
- private static readonly Regex ReqBillingInfoRegex =
- new("var g_bRequiresBillingInfo = (.+);", RegexOptions.Compiled);
-
- private static readonly Regex CountryCodeRegex = new("var g_strCountryCode = \"(.+)\";", RegexOptions.Compiled);
- private static readonly Regex HasBillingStates = new("var g_bHasBillingStates = (.+);", RegexOptions.Compiled);
- private static readonly Regex LanguageRegex = new("var g_strLanguage = \"(.+)\";", RegexOptions.Compiled);
- private static readonly Regex WalletInfoRegex = new("var g_rgWalletInfo = (.+);", RegexOptions.Compiled);
-
- private static readonly Regex SessionIdRegex = new("g_sessionID = \"(.+)\";", RegexOptions.Compiled);
- private static readonly Regex SteamIdRegex = new("g_steamID = \"(.+)\";", RegexOptions.Compiled);
-
- public static GlobalInfoModel Scrap(string html)
- {
- var document = new HtmlDocument();
- document.LoadHtml(html);
-
- var scriptNodes = document.DocumentNode.SelectNodes("//*[@id=\"responsive_page_template_content\"]/script");
- var index = scriptNodes.Count > 2
- ? 1
- : 0; //If account is limited or market unavailable elements will be displaced
-
- var scriptNode = scriptNodes[index];
- var script = scriptNode.InnerText!;
-
- var logged = GetBool(script, LoggedInRegex);
- var hasBillingStates = GetBool(script, HasBillingStates);
- var reqBillingInfo = GetBool(script, ReqBillingInfoRegex);
-
- var country = CountryCodeRegex.Match(html).Groups[1].Value;
- var language = LanguageRegex.Match(html).Groups[1].Value;
-
-
- var walletInfoStr = WalletInfoRegex.Match(html).Groups[1].Value;
- MarketWalletSchema? wallet = null;
-
- var sessionScriptNode =
- document.DocumentNode.SelectSingleNode("//div[@class='responsive_page_content']/script");
- var sessionScript = sessionScriptNode.InnerText!;
-
- var sessionId = SessionIdRegex.Match(sessionScript).Groups[1].Value;
- long? steamId = null;
-
-
- if (logged)
- {
- wallet = JsonConvert.DeserializeObject(walletInfoStr);
- var steamIdStr = SteamIdRegex.Match(sessionScript).Groups[1].Value;
- steamId = long.Parse(new string(steamIdStr.Where(char.IsDigit).ToArray()));
- }
-
-
- return new GlobalInfoModel
- {
- CountryCode = country,
- HasBillingStates = hasBillingStates,
- IsLoggedIn = logged,
- Language = language,
- RequiresBillingInfo = reqBillingInfo,
- WalletInfo = wallet,
- SessionId = sessionId,
- SteamId = steamId
- };
- }
-
- private static bool GetBool(string script, Regex regex)
- {
- var value = regex.Match(script).Groups[1].Value;
- return bool.Parse(value);
- }
-}
\ No newline at end of file
diff --git a/SteamLibForked/Web/SteamWebApi[folder]/SteamApi_Market.cs b/SteamLibForked/Web/SteamWebApi[folder]/SteamApi_Market.cs
deleted file mode 100644
index 66c26a0..0000000
--- a/SteamLibForked/Web/SteamWebApi[folder]/SteamApi_Market.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Text.RegularExpressions;
-using SteamLib.Core;
-using SteamLib.Exceptions.General;
-using SteamLib.Web.Models.GlobalMarketInfo;
-using SteamLib.Web.Scrappers.HTML;
-using System.Threading;
-using JetBrains.Annotations;
-using HtmlAgilityPack;
-using SteamLib.Core.Models;
-
-namespace SteamLib.Web;
-
-public static class SteamWebApi
-{
- ///
- /// Login is not required
- ///
- ///
- ///
- ///
- public static async Task GetMarketGlobalInfo(HttpClient client,
- CancellationToken cancellationToken = default)
- {
- var resp = await client.GetStringAsync(SteamConstants.STEAM_MARKET, cancellationToken);
- try
- {
- return MarketGlobalInfoScrapper.Scrap(resp);
- }
- catch (Exception ex)
- {
- throw new UnsupportedResponseException(resp, ex);
- }
- }
-
-
- [RegexPattern]
- [SuppressMessage("ReSharper", "UseRawString")]
- [SuppressMessage("ReSharper", "StringLiteralTypo")]
- private static readonly string _regexTip =
- @"g_sessionID = ""(?.*)"";"
- + @"\s*g_steamID = (?.*);";
-
- private static readonly Regex Regex = new(_regexTip, RegexOptions.Compiled);
- private const string XPATH = "//div[@class='responsive_page_content']/script";
-
- public static async Task GetLoginSessionId(HttpClient client, CancellationToken cancellationToken = default)
- {
- var resp = await client.GetStringAsync("https://steamcommunity.com/login/home", cancellationToken);
-
- var document = new HtmlDocument();
- document.LoadHtml(resp);
- var scriptNode = document.DocumentNode.SelectSingleNode(XPATH) ?? throw new NullReferenceException("Script Node was null");
- var script = scriptNode.InnerText;
- var match = Regex.Match(script);
- if (!match.Success)
- throw new UnsupportedResponseException(script, "Page contains script but regex was unsuccessful");
- return match.Groups["g_sessionID"].Value;
- }
-}
\ No newline at end of file
diff --git a/changelog/1.7.1.html b/changelog/1.7.1.html
new file mode 100644
index 0000000..9a7fab9
--- /dev/null
+++ b/changelog/1.7.1.html
@@ -0,0 +1,89 @@
+
+
+
+
+
+ Changelog
+
+
+
+
+
+
+
+
Version 1.7.1
+
09.07.2025
+
+
+ -
+ NEWS: Official Telegram group now available! Join us at
+
+ t.me/nebulaauth
+
+
+ - UPDATE: Added support for a new confirmation type — Purchase.
+ - UPDATE: Merged Global 1.7.0 updates into the release version (patch notes).
+ - FIX: Fixed a crash occurring during confirmation loading.
+ - ENHANCEMENT: Improved localization and system messages.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/misc/update.xml b/misc/update.xml
new file mode 100644
index 0000000..0d26b50
--- /dev/null
+++ b/misc/update.xml
@@ -0,0 +1,8 @@
+
+
+-
+ 1.5.6.0
+ https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/releases/download/1.5.6/NebulaAuth.1.5.6.zip
+ https://achiez.github.io/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/changelog/1.5.6.html
+ false
+
\ No newline at end of file
diff --git a/NebulaAuth.LegacyConverter/EncryptedManifest.cs b/src/NebulaAuth.LegacyConverter/EncryptedManifest.cs
similarity index 100%
rename from NebulaAuth.LegacyConverter/EncryptedManifest.cs
rename to src/NebulaAuth.LegacyConverter/EncryptedManifest.cs
diff --git a/NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj b/src/NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj
similarity index 86%
rename from NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj
rename to src/NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj
index fa02bbb..e1632f6 100644
--- a/NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj
+++ b/src/NebulaAuth.LegacyConverter/NebulaAuth.LegacyConverter.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net9.0
enable
enable
diff --git a/NebulaAuth.LegacyConverter/Program.cs b/src/NebulaAuth.LegacyConverter/Program.cs
similarity index 100%
rename from NebulaAuth.LegacyConverter/Program.cs
rename to src/NebulaAuth.LegacyConverter/Program.cs
diff --git a/NebulaAuth.LegacyConverter/SDADecryptor.cs b/src/NebulaAuth.LegacyConverter/SDADecryptor.cs
similarity index 100%
rename from NebulaAuth.LegacyConverter/SDADecryptor.cs
rename to src/NebulaAuth.LegacyConverter/SDADecryptor.cs
diff --git a/NebulaAuth/App.xaml b/src/NebulaAuth/App.xaml
similarity index 67%
rename from NebulaAuth/App.xaml
rename to src/NebulaAuth/App.xaml
index ef12067..1253945 100644
--- a/NebulaAuth/App.xaml
+++ b/src/NebulaAuth/App.xaml
@@ -4,13 +4,11 @@
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"
- StartupUri="MainWindow.xaml">
+ xmlns:background="clr-namespace:NebulaAuth.Converters.Background">
- #1E2025
- pack://application:,,,/Fonts/Roboto/#Roboto
- pack://application:,,,/Fonts/Roboto/#Roboto Symbols
+
+
@@ -19,32 +17,50 @@
+
+
+
+
+
+
True
False
-
-
+
+ Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NebulaAuth/App.xaml.cs b/src/NebulaAuth/App.xaml.cs
new file mode 100644
index 0000000..53c3e81
--- /dev/null
+++ b/src/NebulaAuth/App.xaml.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using AchiesUtilities.Extensions;
+using NebulaAuth.Core;
+using NebulaAuth.Model;
+using NebulaAuth.Model.Exceptions;
+
+namespace NebulaAuth;
+
+public partial class App
+{
+ protected override async void OnStartup(StartupEventArgs e)
+ {
+ try
+ {
+ var splashScreen = new SplashScreen("Theme\\SplashScreen.png");
+ splashScreen.Show(false, true);
+ base.OnStartup(e);
+ LocManager.Init();
+ LocManager.SetApplicationLocalization(Settings.Instance.Language);
+ Shell.Initialize();
+
+ var files = 0;
+ if (Directory.Exists(Storage.MAFILE_F))
+ files = Directory.GetFiles(Storage.MafileFolder)
+ .Count(f => Path.GetExtension(f).EqualsIgnoreCase(".mafile"));
+
+ var threads = files > 0 ? files / 100 + 1 : 1;
+ await Storage.Initialize(threads);
+ var mainWindow = new MainWindow();
+ Current.MainWindow = mainWindow;
+ mainWindow.Show();
+ splashScreen.Close(TimeSpan.Zero);
+ }
+ 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);
+
+ Shell.Logger.Fatal(ex, "Application startup failed");
+ Current.Shutdown(1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/AssemblyInfo.cs b/src/NebulaAuth/AssemblyInfo.cs
similarity index 100%
rename from NebulaAuth/AssemblyInfo.cs
rename to src/NebulaAuth/AssemblyInfo.cs
diff --git a/NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs b/src/NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs
similarity index 87%
rename from NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs
rename to src/NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs
index 0ef92fa..016bcb0 100644
--- a/NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs
+++ b/src/NebulaAuth/Converters/AnyMafilesToVisibilityConverter.cs
@@ -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)
{
diff --git a/NebulaAuth/Converters/Background/BackgroundImageVisibleConverter.cs b/src/NebulaAuth/Converters/Background/BackgroundImageVisibleConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/Background/BackgroundImageVisibleConverter.cs
rename to src/NebulaAuth/Converters/Background/BackgroundImageVisibleConverter.cs
diff --git a/NebulaAuth/Converters/Background/BackgroundSourceConverter.cs b/src/NebulaAuth/Converters/Background/BackgroundSourceConverter.cs
similarity index 97%
rename from NebulaAuth/Converters/Background/BackgroundSourceConverter.cs
rename to src/NebulaAuth/Converters/Background/BackgroundSourceConverter.cs
index e4a5255..3dcef44 100644
--- a/NebulaAuth/Converters/Background/BackgroundSourceConverter.cs
+++ b/src/NebulaAuth/Converters/Background/BackgroundSourceConverter.cs
@@ -18,7 +18,7 @@ public class BackgroundSourceConverter : IValueConverter
}
- return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.jpg"));
+ return new BitmapImage(new Uri("pack://application:,,,/Theme/Background.png"));
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
diff --git a/NebulaAuth/Converters/CoefficientConverter.cs b/src/NebulaAuth/Converters/CoefficientConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/CoefficientConverter.cs
rename to src/NebulaAuth/Converters/CoefficientConverter.cs
diff --git a/NebulaAuth/Converters/ColorToBrushConverter.cs b/src/NebulaAuth/Converters/ColorToBrushConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/ColorToBrushConverter.cs
rename to src/NebulaAuth/Converters/ColorToBrushConverter.cs
diff --git a/src/NebulaAuth/Converters/Converters.xaml b/src/NebulaAuth/Converters/Converters.xaml
new file mode 100644
index 0000000..5b35f4c
--- /dev/null
+++ b/src/NebulaAuth/Converters/Converters.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ False
+
+
\ No newline at end of file
diff --git a/NebulaAuth/Converters/MultiCommandParamaterConverter.cs b/src/NebulaAuth/Converters/MultiCommandParamaterConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/MultiCommandParamaterConverter.cs
rename to src/NebulaAuth/Converters/MultiCommandParamaterConverter.cs
diff --git a/src/NebulaAuth/Converters/NullableToBooleanConverter.cs b/src/NebulaAuth/Converters/NullableToBooleanConverter.cs
new file mode 100644
index 0000000..06897f7
--- /dev/null
+++ b/src/NebulaAuth/Converters/NullableToBooleanConverter.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace NebulaAuth.Converters;
+
+public class NullableToBooleanConverter : IValueConverter
+{
+ public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ return value != null;
+ }
+
+ public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs b/src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
similarity index 99%
rename from NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
rename to src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
index 6e84920..89acb45 100644
--- a/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
+++ b/src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
@@ -14,6 +14,7 @@ public class PortableMaClientStatusToColorConverter : IValueConverter
return new SolidColorBrush(Color.FromRgb(187, 224, 139));
}
+
return new SolidColorBrush(Color.FromRgb(224, 139, 139));
}
diff --git a/NebulaAuth/Converters/ProxyTextConverter.cs b/src/NebulaAuth/Converters/ProxyTextConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/ProxyTextConverter.cs
rename to src/NebulaAuth/Converters/ProxyTextConverter.cs
diff --git a/NebulaAuth/Converters/ReverseBooleanConverter.cs b/src/NebulaAuth/Converters/ReverseBooleanConverter.cs
similarity index 100%
rename from NebulaAuth/Converters/ReverseBooleanConverter.cs
rename to src/NebulaAuth/Converters/ReverseBooleanConverter.cs
diff --git a/NebulaAuth/Converters/ValueConverterGroup.cs b/src/NebulaAuth/Converters/ValueConverterGroup.cs
similarity index 100%
rename from NebulaAuth/Converters/ValueConverterGroup.cs
rename to src/NebulaAuth/Converters/ValueConverterGroup.cs
diff --git a/NebulaAuth/Core/DialogsController.cs b/src/NebulaAuth/Core/DialogsController.cs
similarity index 75%
rename from NebulaAuth/Core/DialogsController.cs
rename to src/NebulaAuth/Core/DialogsController.cs
index 6d41807..36c778e 100644
--- a/NebulaAuth/Core/DialogsController.cs
+++ b/src/NebulaAuth/Core/DialogsController.cs
@@ -5,6 +5,8 @@ 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;
@@ -86,11 +88,37 @@ public static class DialogsController
public static async Task ShowLinkerDialog()
{
- var vm = new LinkAccountVM();
- var view = new LinkerView
+ LinkAccountVM? vm = null;
+ try
{
- DataContext = vm
- };
- await DialogHost.Show(view);
+ 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();
+ }
}
}
\ No newline at end of file
diff --git a/NebulaAuth/Core/LocalizationManager.cs b/src/NebulaAuth/Core/LocalizationManager.cs
similarity index 98%
rename from NebulaAuth/Core/LocalizationManager.cs
rename to src/NebulaAuth/Core/LocalizationManager.cs
index fd01f0d..d805052 100644
--- a/NebulaAuth/Core/LocalizationManager.cs
+++ b/src/NebulaAuth/Core/LocalizationManager.cs
@@ -38,7 +38,7 @@ public static class LocManager
public static void Init()
{
- Loc.LogOutMissingTranslations = true;
+ Loc.Instance.LogOutMissingTranslations = true;
LocalizationLoader.Instance.FileLanguageLoaders.Add(new JsonFileLoader());
diff --git a/NebulaAuth/Core/SnackbarController.cs b/src/NebulaAuth/Core/SnackbarController.cs
similarity index 97%
rename from NebulaAuth/Core/SnackbarController.cs
rename to src/NebulaAuth/Core/SnackbarController.cs
index 8404c7f..976822c 100644
--- a/NebulaAuth/Core/SnackbarController.cs
+++ b/src/NebulaAuth/Core/SnackbarController.cs
@@ -44,7 +44,7 @@ public class SnackbarController
private static TimeSpan GetSnackbarTime(string str)
{
- var duration = str.Length / 0.03;
+ var duration = str.Length / 0.022;
if (duration < MIN_SNACKBAR_TIME)
{
duration = MIN_SNACKBAR_TIME;
diff --git a/NebulaAuth/Core/ThemeManager.cs b/src/NebulaAuth/Core/ThemeManager.cs
similarity index 63%
rename from NebulaAuth/Core/ThemeManager.cs
rename to src/NebulaAuth/Core/ThemeManager.cs
index 81b123f..22ab707 100644
--- a/NebulaAuth/Core/ThemeManager.cs
+++ b/src/NebulaAuth/Core/ThemeManager.cs
@@ -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,7 +14,6 @@ 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()
@@ -24,11 +23,7 @@ public static class ThemeManager
private static void SettingsOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
- if (e.PropertyName == nameof(Settings.BackgroundColor))
- {
- UpdateBackground();
- }
- else if (e.PropertyName == nameof(Settings.IconColor))
+ if (e.PropertyName == nameof(Settings.IconColor))
{
UpdateIcon();
}
@@ -58,15 +53,40 @@ public static class ThemeManager
}
}
- private static void UpdateBackground()
+
+ public static void ApplyTheme(string themeName)
{
- var color = Settings.Instance.BackgroundColor ?? DefaultBackgroundColor;
- Application.Current.Resources["WindowBackground"] = new SolidColorBrush(color);
+ 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);
}
+
public static void InitializeTheme()
{
UpdateIcon();
- UpdateBackground();
+ ApplyTheme(Settings.Instance.GetTheme());
}
}
\ No newline at end of file
diff --git a/NebulaAuth/Core/TrayManager.cs b/src/NebulaAuth/Core/TrayManager.cs
similarity index 100%
rename from NebulaAuth/Core/TrayManager.cs
rename to src/NebulaAuth/Core/TrayManager.cs
diff --git a/NebulaAuth/Core/UpdateManager.cs b/src/NebulaAuth/Core/UpdateManager.cs
similarity index 96%
rename from NebulaAuth/Core/UpdateManager.cs
rename to src/NebulaAuth/Core/UpdateManager.cs
index 3415a49..dc8db72 100644
--- a/NebulaAuth/Core/UpdateManager.cs
+++ b/src/NebulaAuth/Core/UpdateManager.cs
@@ -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/NebulaAuth/update.xml";
+ "https://raw.githubusercontent.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies/master/misc/update.xml";
public static void CheckForUpdates()
{
diff --git a/NebulaAuth/FodyWeavers.xml b/src/NebulaAuth/FodyWeavers.xml
similarity index 100%
rename from NebulaAuth/FodyWeavers.xml
rename to src/NebulaAuth/FodyWeavers.xml
diff --git a/NebulaAuth/MainWindow.xaml b/src/NebulaAuth/MainWindow.xaml
similarity index 56%
rename from NebulaAuth/MainWindow.xaml
rename to src/NebulaAuth/MainWindow.xaml
index 41e64c2..df97241 100644
--- a/NebulaAuth/MainWindow.xaml
+++ b/src/NebulaAuth/MainWindow.xaml
@@ -9,12 +9,14 @@
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" Foreground="#FFF5F5F5"
+ Title="NebulaAuth" Height="800" Width="730"
+ Style="{StaticResource MainWindow}"
+ RenderOptions.BitmapScalingMode="HighQuality"
FontFamily="{md:MaterialDesignFont}"
- TextElement.Foreground="{DynamicResource MaterialDesignBody}"
+ TextElement.Foreground="{DynamicResource BaseContentBrush}"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance viewModel:MainVM}">
@@ -28,20 +30,31 @@
-
+
+
-
-
+ Source="{Binding Settings.BackgroundMode, Mode=OneWay, Converter={StaticResource BackgroundSourceConverter}}">
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
-
+
+
@@ -334,47 +369,50 @@
-
-
-
-
-
-
-
+
+
+ Width="{Binding Path=ActualWidth, Converter={StaticResource CoefficientConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource AncestorType=md:Card}}" />
-
+
-
+
-
+
-
@@ -382,19 +420,21 @@
+
+
+ Foreground="{DynamicResource AccentBrush}"
+ Command="{Binding OpenLinksViewCommand}">
by achies
-
+
diff --git a/NebulaAuth/MainWindow.xaml.cs b/src/NebulaAuth/MainWindow.xaml.cs
similarity index 89%
rename from NebulaAuth/MainWindow.xaml.cs
rename to src/NebulaAuth/MainWindow.xaml.cs
index 036123e..29a5a19 100644
--- a/NebulaAuth/MainWindow.xaml.cs
+++ b/src/NebulaAuth/MainWindow.xaml.cs
@@ -1,10 +1,8 @@
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;
@@ -30,10 +28,13 @@ public partial class MainWindow
private async void OnApplicationStarted(object? sender, EventArgs e)
{
+ ((MainVM) DataContext).CurrentDialogHost = DialogHostInstance;
if (Settings.Instance.IsPasswordSet == false) return;
- await Dispatcher.BeginInvoke(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
+ Topmost = false;
+ await Dispatcher.InvokeAsync(ShowSetPasswordDialog, DispatcherPriority.ContextIdle);
}
+
private async Task ShowSetPasswordDialog()
{
var vm = new SetEncryptPasswordVM();
@@ -41,6 +42,7 @@ public partial class MainWindow
{
DataContext = vm
};
+
var result = await DialogHost.Show(dialog);
var pass = vm.Password;
if (result is true && string.IsNullOrWhiteSpace(pass) == false)
@@ -49,15 +51,6 @@ 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)
diff --git a/NebulaAuth/Model/Comparers/ProxyComparer.cs b/src/NebulaAuth/Model/Comparers/ProxyComparer.cs
similarity index 100%
rename from NebulaAuth/Model/Comparers/ProxyComparer.cs
rename to src/NebulaAuth/Model/Comparers/ProxyComparer.cs
diff --git a/NebulaAuth/Model/Entities/LoginConfirmationResult.cs b/src/NebulaAuth/Model/Entities/LoginConfirmationResult.cs
similarity index 100%
rename from NebulaAuth/Model/Entities/LoginConfirmationResult.cs
rename to src/NebulaAuth/Model/Entities/LoginConfirmationResult.cs
diff --git a/NebulaAuth/Model/Entities/MaProxy.cs b/src/NebulaAuth/Model/Entities/MaProxy.cs
similarity index 100%
rename from NebulaAuth/Model/Entities/MaProxy.cs
rename to src/NebulaAuth/Model/Entities/MaProxy.cs
diff --git a/NebulaAuth/Model/Entities/Mafile.cs b/src/NebulaAuth/Model/Entities/Mafile.cs
similarity index 97%
rename from NebulaAuth/Model/Entities/Mafile.cs
rename to src/NebulaAuth/Model/Entities/Mafile.cs
index 8773f08..8d3c2a2 100644
--- a/NebulaAuth/Model/Entities/Mafile.cs
+++ b/src/NebulaAuth/Model/Entities/Mafile.cs
@@ -2,7 +2,7 @@
using NebulaAuth.Model.MAAC;
using Newtonsoft.Json;
using SteamLib;
-using SteamLib.Account;
+using SteamLibForked.Models.Session;
namespace NebulaAuth.Model.Entities;
diff --git a/NebulaAuth/Model/Entities/MarketMultiConfirmation.cs b/src/NebulaAuth/Model/Entities/MarketMultiConfirmation.cs
similarity index 100%
rename from NebulaAuth/Model/Entities/MarketMultiConfirmation.cs
rename to src/NebulaAuth/Model/Entities/MarketMultiConfirmation.cs
diff --git a/NebulaAuth/Model/Exceptions/CantAlignTime.cs b/src/NebulaAuth/Model/Exceptions/CantAlignTime.cs
similarity index 100%
rename from NebulaAuth/Model/Exceptions/CantAlignTime.cs
rename to src/NebulaAuth/Model/Exceptions/CantAlignTime.cs
diff --git a/NebulaAuth/Model/Exceptions/MafileNeedReloginException.cs b/src/NebulaAuth/Model/Exceptions/MafileNeedReloginException.cs
similarity index 100%
rename from NebulaAuth/Model/Exceptions/MafileNeedReloginException.cs
rename to src/NebulaAuth/Model/Exceptions/MafileNeedReloginException.cs
diff --git a/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs b/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
similarity index 98%
rename from NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
rename to src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
index 63894c3..eb9823b 100644
--- a/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
+++ b/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
@@ -8,7 +8,6 @@ using System.Threading.Tasks;
using AchiesUtilities.Extensions;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
-using NLog;
namespace NebulaAuth.Model.MAAC;
@@ -16,6 +15,8 @@ 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 Clients { get; }
private static Timer Timer { get; }
@@ -27,12 +28,10 @@ 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)
{
- bool isHeld = false;
+ var isHeld = false;
try
{
isHeld = await ExecutionLock.WaitAsync(0);
@@ -41,8 +40,8 @@ public static class MultiAccountAutoConfirmer
SnackbarController.SendSnackbar(GetLocalization("TimerPreventedOverlap"));
return;
}
- await TimerConfirmInternal();
+ await TimerConfirmInternal();
}
catch (Exception e)
{
@@ -60,7 +59,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 () =>
diff --git a/NebulaAuth/Model/MAAC/PortableMaClient.cs b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
similarity index 96%
rename from NebulaAuth/Model/MAAC/PortableMaClient.cs
rename to src/NebulaAuth/Model/MAAC/PortableMaClient.cs
index c73161e..33dd601 100644
--- a/NebulaAuth/Model/MAAC/PortableMaClient.cs
+++ b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
@@ -14,10 +14,10 @@ using NebulaAuth.Model.Entities;
using NebulaAuth.Utility;
using SteamLib.Api.Mobile;
using SteamLib.Authentication;
-using SteamLib.Core.Interfaces;
-using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
+using SteamLibForked.Abstractions;
namespace NebulaAuth.Model.MAAC;
@@ -90,7 +90,8 @@ public partial class PortableMaClient : ObservableObject, IDisposable
var toConfirm = new List();
if (AutoConfirmMarket)
{
- var market = conf.Where(c => c.ConfType == ConfirmationType.MarketSellTransaction);
+ var market = conf.Where(c =>
+ c.ConfType is ConfirmationType.MarketSellTransaction or ConfirmationType.Purchase);
toConfirm.AddRange(market);
}
diff --git a/NebulaAuth/Model/MaClient.cs b/src/NebulaAuth/Model/MaClient.cs
similarity index 87%
rename from NebulaAuth/Model/MaClient.cs
rename to src/NebulaAuth/Model/MaClient.cs
index 2ad2a31..62944ca 100644
--- a/NebulaAuth/Model/MaClient.cs
+++ b/src/NebulaAuth/Model/MaClient.cs
@@ -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.Core.Interfaces;
-using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.ProtoCore.Services;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
@@ -26,6 +26,7 @@ public static class MaClient
public static ProxyData? DefaultProxy { get; set; }
+
static MaClient()
{
Proxy = new DynamicProxy();
@@ -62,7 +63,7 @@ public static class MaClient
return SteamMobileConfirmationsApi.GetConfirmations(Client, mafile, mafile.SessionData!.SteamId);
}
- public static Task LoginAgain(Mafile mafile, string password, bool savePassword, ICaptchaResolver? resolver)
+ public static Task LoginAgain(Mafile mafile, string password, bool savePassword)
{
SetProxy(mafile);
return SessionHandler.LoginAgain(new HttpClientHandlerPair(Client, ClientHandler), mafile, password,
@@ -137,7 +138,7 @@ public static class MaClient
ValidateMafile(mafile);
SetProxy(mafile);
var token = mafile.SessionData!.GetMobileToken()!.Value;
- var sessions = await SteamMobileAuthenticatorApi.GetAuthSessionsForAccount(Client, token.Token);
+ var sessions = await AuthenticationServiceApi.GetAuthSessionsForAccount(Client, token.Token);
if (sessions.ClientIds.Count == 0)
{
@@ -156,16 +157,11 @@ public static class MaClient
}
var clientId = sessions.ClientIds.Single();
- 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);
+ 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);
return new LoginConfirmationResult
{
Country = clientInfo.Country,
diff --git a/NebulaAuth/Model/NebulaSerializer.cs b/src/NebulaAuth/Model/NebulaSerializer.cs
similarity index 89%
rename from NebulaAuth/Model/NebulaSerializer.cs
rename to src/NebulaAuth/Model/NebulaSerializer.cs
index 6ab8654..921d69a 100644
--- a/NebulaAuth/Model/NebulaSerializer.cs
+++ b/src/NebulaAuth/Model/NebulaSerializer.cs
@@ -22,6 +22,11 @@ public static class NebulaSerializer
AllowDeviceIdGeneration = true,
AllowSessionIdGeneration = true,
ThrowIfInvalidSteamId = false
+ },
+ SerializationOptions =
+ {
+ Sign = true,
+ Formatting = Formatting.Indented
}
});
}
@@ -80,9 +85,9 @@ public static class NebulaSerializer
{
if (Settings.Instance.LegacyMode)
{
- return MafileSerializer.SerializeLegacy(data, Formatting.Indented, properties);
+ return MafileSerializer.SerializeLegacy(data, Serializer.Settings.SerializationOptions, properties);
}
- return MafileSerializer.Serialize(data);
+ return Serializer.Serialize(data);
}
}
\ No newline at end of file
diff --git a/NebulaAuth/Model/PHandler.cs b/src/NebulaAuth/Model/PHandler.cs
similarity index 100%
rename from NebulaAuth/Model/PHandler.cs
rename to src/NebulaAuth/Model/PHandler.cs
diff --git a/NebulaAuth/Model/ProxyStorage.cs b/src/NebulaAuth/Model/ProxyStorage.cs
similarity index 100%
rename from NebulaAuth/Model/ProxyStorage.cs
rename to src/NebulaAuth/Model/ProxyStorage.cs
diff --git a/NebulaAuth/Model/SessionHandler.cs b/src/NebulaAuth/Model/SessionHandler.cs
similarity index 99%
rename from NebulaAuth/Model/SessionHandler.cs
rename to src/NebulaAuth/Model/SessionHandler.cs
index d042159..a04ed52 100644
--- a/NebulaAuth/Model/SessionHandler.cs
+++ b/src/NebulaAuth/Model/SessionHandler.cs
@@ -7,7 +7,7 @@ using MaterialDesignThemes.Wpf;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NebulaAuth.View.Dialogs;
-using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
namespace NebulaAuth.Model;
diff --git a/NebulaAuth/Model/SessionHandler_API.cs b/src/NebulaAuth/Model/SessionHandler_API.cs
similarity index 88%
rename from NebulaAuth/Model/SessionHandler_API.cs
rename to src/NebulaAuth/Model/SessionHandler_API.cs
index c6ebd25..91728ed 100644
--- a/NebulaAuth/Model/SessionHandler_API.cs
+++ b/src/NebulaAuth/Model/SessionHandler_API.cs
@@ -1,12 +1,13 @@
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;
+using SteamLib.Exceptions.Authorization;
+using SteamLib.Factory.Helpers;
using SteamLib.SteamMobile;
+using SteamLibForked.Models.Session;
namespace NebulaAuth.Model;
@@ -35,11 +36,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(LoginV2Executor.NullConsumer, chp.Client)
+ var options = new LoginV2ExecutorOptions(StaticLoginConsumer.Instance, chp.Client)
{
Logger = Shell.ExtensionsLogger,
- SteamGuardProvider = sgGenerator,
- DeviceDetails = LoginV2ExecutorOptions.GetMobileDefaultDevice(),
+ AuthProviders = [sgGenerator],
+ DeviceDetails = DeviceDetailsDefaultBuilder.GetMobileDefaultDevice(),
WebsiteId = "Mobile"
};
chp.Handler.CookieContainer.ClearMobileSessionCookies();
diff --git a/NebulaAuth/Model/Settings.cs b/src/NebulaAuth/Model/Settings.cs
similarity index 58%
rename from NebulaAuth/Model/Settings.cs
rename to src/NebulaAuth/Model/Settings.cs
index 12fc064..385f70e 100644
--- a/NebulaAuth/Model/Settings.cs
+++ b/src/NebulaAuth/Model/Settings.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows.Media;
@@ -12,6 +13,15 @@ public partial class Settings : ObservableObject
{
public static Settings Instance { get; }
+ private static IReadOnlyDictionary ThemeNames { get; } = new Dictionary
+ {
+ {ThemeType.Default, "DefaultTheme"},
+ {ThemeType.Light, "LightTheme"},
+ {ThemeType.Black, "BlackTheme"},
+ {ThemeType.Luxury, "LuxuryTheme"},
+ {ThemeType.Shadcn, "ShadcnTheme"}
+ };
+
static Settings()
{
if (File.Exists("settings.json") == false)
@@ -40,6 +50,10 @@ 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()
@@ -48,12 +62,27 @@ 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;
@@ -62,6 +91,15 @@ 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
}
@@ -70,4 +108,13 @@ public enum BackgroundMode
Default,
Custom,
Color
+}
+
+public enum ThemeType
+{
+ Default = 0,
+ Black = 1,
+ Light = 2,
+ Luxury = 3,
+ Shadcn = 4
}
\ No newline at end of file
diff --git a/NebulaAuth/Model/Shell.cs b/src/NebulaAuth/Model/Shell.cs
similarity index 89%
rename from NebulaAuth/Model/Shell.cs
rename to src/NebulaAuth/Model/Shell.cs
index 6464c68..f9d598a 100644
--- a/NebulaAuth/Model/Shell.cs
+++ b/src/NebulaAuth/Model/Shell.cs
@@ -11,11 +11,12 @@ namespace NebulaAuth.Model;
public static class Shell
{
- public static Logger Logger { get; } = LogManager.GetLogger("Logger");
+ public static Logger Logger { get; private set; } = null!;
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;
@@ -39,5 +40,6 @@ public static class Shell
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Logger.Fatal((Exception) e.ExceptionObject);
+ LogManager.Shutdown();
}
}
\ No newline at end of file
diff --git a/NebulaAuth/Model/Storage.cs b/src/NebulaAuth/Model/Storage.cs
similarity index 66%
rename from NebulaAuth/Model/Storage.cs
rename to src/NebulaAuth/Model/Storage.cs
index 49f42ad..d50d205 100644
--- a/NebulaAuth/Model/Storage.cs
+++ b/src/NebulaAuth/Model/Storage.cs
@@ -1,71 +1,84 @@
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.Core.Models;
-using SteamLib.Exceptions;
+using SteamLib;
+using SteamLib.Exceptions.Authorization;
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 readonly int DuplicateFound;
-
+ public static int DuplicateFound => _duplicateFound;
public static string MafileFolder { get; } = Path.GetFullPath(MAFILE_F);
public static string RemovedMafileFolder { get; } = Path.GetFullPath(REMOVED_F);
- public static ObservableCollection MaFiles { get; } = new();
+ public static ObservableCollection MaFiles { get; private set; } = new();
static Storage()
{
- if (Directory.Exists(MafileFolder) == false)
- {
+ }
+
+ public static async Task Initialize(int threadCount, CancellationToken token = default)
+ {
+ if (!Directory.Exists(MafileFolder))
Directory.CreateDirectory(MafileFolder);
- }
- if (Directory.Exists(RemovedMafileFolder) == false)
- {
+ if (!Directory.Exists(RemovedMafileFolder))
Directory.CreateDirectory(RemovedMafileFolder);
- }
-
- var files = Directory.GetFiles(MafileFolder);
- var hashNames = new HashSet();
- var hashIds = new HashSet();
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")))
+ var files = Directory
+ .GetFiles(MafileFolder)
+ .Where(file => Path.GetExtension(file).EqualsIgnoreCase(".mafile"))
+ .Order(comparer)
+ .ToList();
+
+
+ var hashNames = new ConcurrentDictionary();
+ var hashIds = new ConcurrentDictionary();
+ var localList = new ConcurrentBag();
+
+ var processed = 0;
+
+ await Task.Run(() =>
{
- try
- {
- var data = ReadMafile(file);
-
- if (hashNames.Contains(data.AccountName) || hashIds.Contains(data.SteamId))
+ return Parallel.ForEachAsync(files,
+ new ParallelOptions {CancellationToken = token, MaxDegreeOfParallelism = threadCount},
+ async (file, ct) =>
{
- DuplicateFound++;
- Shell.Logger.Error("Duplicate mafile {file}", Path.GetFileName(file));
- continue;
- }
+ try
+ {
+ var data = await ReadMafileAsync(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));
- }
- }
+ 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));
+ }
- MaFiles = new ObservableCollection(MaFiles.OrderBy(m => m.AccountName));
+ localList.Add(data);
+ }
+ catch (Exception ex)
+ {
+ Shell.Logger.Error(ex, "Can't load mafile {file}", Path.GetFileName(file));
+ }
+ });
+ }, token);
+
+ MaFiles = new ObservableCollection(localList.OrderBy(m => m.AccountName));
}
///
@@ -117,6 +130,12 @@ public static class Storage
return NebulaSerializer.Deserialize(str);
}
+ public static async Task ReadMafileAsync(string path)
+ {
+ var str = await File.ReadAllTextAsync(path);
+ return NebulaSerializer.Deserialize(str);
+ }
+
public static void SaveMafile(Mafile data)
{
var path = CreatePathForMafile(data);
@@ -202,9 +221,35 @@ 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
{
private const string MAF_64_START = "765";
diff --git a/NebulaAuth/NLog.config b/src/NebulaAuth/NLog.config
similarity index 99%
rename from NebulaAuth/NLog.config
rename to src/NebulaAuth/NLog.config
index dd93a45..c9bf400 100644
--- a/NebulaAuth/NLog.config
+++ b/src/NebulaAuth/NLog.config
@@ -16,7 +16,6 @@
-
diff --git a/src/NebulaAuth/NebulaAuth.csproj b/src/NebulaAuth/NebulaAuth.csproj
new file mode 100644
index 0000000..e3d170b
--- /dev/null
+++ b/src/NebulaAuth/NebulaAuth.csproj
@@ -0,0 +1,68 @@
+
+
+
+ WinExe
+ net9.0-windows7.0
+ enable
+ true
+ true
+ latest
+ en;ru;ua
+ Theme\lock.ico
+ 7.0
+ 1.7.1
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Never
+
+
+ Never
+
+
+
+
+
+
+
+
+
+
+
+ Code
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/NebulaAuth.csproj.DotSettings b/src/NebulaAuth/NebulaAuth.csproj.DotSettings
new file mode 100644
index 0000000..53e8b1a
--- /dev/null
+++ b/src/NebulaAuth/NebulaAuth.csproj.DotSettings
@@ -0,0 +1,6 @@
+
+ True
\ No newline at end of file
diff --git a/NebulaAuth/PlannedChanges.txt b/src/NebulaAuth/PlannedChanges.txt
similarity index 68%
rename from NebulaAuth/PlannedChanges.txt
rename to src/NebulaAuth/PlannedChanges.txt
index bac9938..a38bff5 100644
--- a/NebulaAuth/PlannedChanges.txt
+++ b/src/NebulaAuth/PlannedChanges.txt
@@ -6,4 +6,9 @@
• Добавить запоминание пароля при привязке мафайла
• Функция переноса гуарда с мобильного устройства на ПК с созданием мафайла
• Добавить полное шифрование мафайлов по аналогии с SDA
-• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
\ No newline at end of file
+• Сделать автоматический билд и загрузку обновления на Github при изменении в мастер ветке
+• Антик-окно как в MarketApp, возможность сразу открыть браузер напр. на CefSharp с залогиненым аккаунтом
+• Стабильность авто-подтверждений, возможность задать пользователю порог времени когда льются ошибки и только тогда выключать авто-подтверждение
+• Безопасное сохранение мафайлов через .tmp / .bak
+• Создание механизма накопления ошибок, чтобы исправить Patch Tuesday, условно аккаунт может игнорировать ошибки 1-2 часа (настриавемо)
+
diff --git a/src/NebulaAuth/Theme/Background.png b/src/NebulaAuth/Theme/Background.png
new file mode 100644
index 0000000..9d0c85f
Binary files /dev/null and b/src/NebulaAuth/Theme/Background.png differ
diff --git a/NebulaAuth/Theme/Background.jpg b/src/NebulaAuth/Theme/Background_Old.jpg
similarity index 100%
rename from NebulaAuth/Theme/Background.jpg
rename to src/NebulaAuth/Theme/Background_Old.jpg
diff --git a/src/NebulaAuth/Theme/Brushes.xaml b/src/NebulaAuth/Theme/Brushes.xaml
new file mode 100644
index 0000000..a75f635
--- /dev/null
+++ b/src/NebulaAuth/Theme/Brushes.xaml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/Theme/Controls/CodeProgressBar.cs b/src/NebulaAuth/Theme/Controls/CodeProgressBar.cs
new file mode 100644
index 0000000..4f55936
--- /dev/null
+++ b/src/NebulaAuth/Theme/Controls/CodeProgressBar.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media.Animation;
+
+namespace NebulaAuth.Theme.Controls;
+
+public class CodeProgressBar : ProgressBar
+{
+ public static readonly DependencyProperty TimeRemainingProperty =
+ DependencyProperty.Register(nameof(TimeRemaining), typeof(double), typeof(CodeProgressBar),
+ new PropertyMetadata(-1.0, OnTimeRemainingChanged));
+
+ public static readonly DependencyProperty MaxTimeProperty =
+ DependencyProperty.Register(nameof(MaxTime), typeof(double), typeof(CodeProgressBar),
+ new PropertyMetadata(30.0)); // По умолчанию 30 сек
+
+ public double TimeRemaining
+ {
+ get => (double) GetValue(TimeRemainingProperty);
+ set => SetValue(TimeRemainingProperty, value);
+ }
+
+ public double MaxTime
+ {
+ get => (double) GetValue(MaxTimeProperty);
+ set => SetValue(MaxTimeProperty, value);
+ }
+
+ private static void OnTimeRemainingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is CodeProgressBar progressBar)
+ {
+ var newValue = (double) e.NewValue;
+ progressBar.StartProgressAnimation(newValue);
+ }
+ }
+
+ private void StartProgressAnimation(double timeRemaining)
+ {
+ if (timeRemaining <= 0 || MaxTime <= 0) return;
+
+ var progress = (1 - timeRemaining / MaxTime) * 100;
+ Value = 0;
+ Value = 100;
+ var animation = new DoubleAnimation
+ {
+ From = progress,
+ To = 100,
+ Duration = TimeSpan.FromSeconds(timeRemaining),
+ AccelerationRatio = 0,
+ DecelerationRatio = 0
+ };
+
+
+ BeginAnimation(ValueProperty, animation);
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/Theme/FontScaleWindow.cs b/src/NebulaAuth/Theme/FontScaleWindow.cs
similarity index 100%
rename from NebulaAuth/Theme/FontScaleWindow.cs
rename to src/NebulaAuth/Theme/FontScaleWindow.cs
diff --git a/src/NebulaAuth/Theme/MaterialDesignThemes.Overrides.xaml b/src/NebulaAuth/Theme/MaterialDesignThemes.Overrides.xaml
new file mode 100644
index 0000000..e7a0621
--- /dev/null
+++ b/src/NebulaAuth/Theme/MaterialDesignThemes.Overrides.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NebulaAuth/Theme/Palette.xaml b/src/NebulaAuth/Theme/Palette.xaml
similarity index 100%
rename from NebulaAuth/Theme/Palette.xaml
rename to src/NebulaAuth/Theme/Palette.xaml
diff --git a/NebulaAuth/Theme/Palette.xaml.cs b/src/NebulaAuth/Theme/Palette.xaml.cs
similarity index 100%
rename from NebulaAuth/Theme/Palette.xaml.cs
rename to src/NebulaAuth/Theme/Palette.xaml.cs
diff --git a/src/NebulaAuth/Theme/SplashScreen.png b/src/NebulaAuth/Theme/SplashScreen.png
new file mode 100644
index 0000000..e108b21
Binary files /dev/null and b/src/NebulaAuth/Theme/SplashScreen.png differ
diff --git a/NebulaAuth/Theme/SplashScreen.psd b/src/NebulaAuth/Theme/SplashScreen.psd
similarity index 100%
rename from NebulaAuth/Theme/SplashScreen.psd
rename to src/NebulaAuth/Theme/SplashScreen.psd
diff --git a/src/NebulaAuth/Theme/SplashScreen2.psd b/src/NebulaAuth/Theme/SplashScreen2.psd
new file mode 100644
index 0000000..b963ea2
Binary files /dev/null and b/src/NebulaAuth/Theme/SplashScreen2.psd differ
diff --git a/src/NebulaAuth/Theme/Themes/BlackTheme.xaml b/src/NebulaAuth/Theme/Themes/BlackTheme.xaml
new file mode 100644
index 0000000..f87044f
--- /dev/null
+++ b/src/NebulaAuth/Theme/Themes/BlackTheme.xaml
@@ -0,0 +1,25 @@
+
+
+ #605dff
+ #fdf9e8
+ #009689
+ #effcf9
+ #3c3dfc
+ #ffffff
+ #f8f8f8
+ #314157
+ #1d1d20
+ #151515
+ #131313
+ #f2f2f2
+ #1e1e24
+ #0082ce
+ #edf7fd
+ #5ca300
+ #f5fce5
+ #b94b00
+ #fcfae6
+ #f82834
+ #fef2f2
+
\ No newline at end of file
diff --git a/src/NebulaAuth/Theme/Themes/DefaultTheme.xaml b/src/NebulaAuth/Theme/Themes/DefaultTheme.xaml
new file mode 100644
index 0000000..4423c87
--- /dev/null
+++ b/src/NebulaAuth/Theme/Themes/DefaultTheme.xaml
@@ -0,0 +1,27 @@
+
+
+ #794DFF
+ #eae7ff
+ #76717f
+ #ffffff
+ #3b82f6
+ #dbeafe
+ #928f9e
+ #141119
+ #282332
+ #1d1a26
+ #4a4456
+ #b8b6c0
+ #1e1e24
+ #06b6d4
+ #cffafe
+ #02ca4b
+ #e1faf1
+ #fcaa1d
+ #fffae8
+ #fb4141
+ #fff5ed
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/Theme/Themes/LightTheme.xaml b/src/NebulaAuth/Theme/Themes/LightTheme.xaml
new file mode 100644
index 0000000..44ca85e
--- /dev/null
+++ b/src/NebulaAuth/Theme/Themes/LightTheme.xaml
@@ -0,0 +1,25 @@
+
+
+ #794DFF
+ #f3f2ff
+ #76717f
+ #f7f7f8
+ #3b82f6
+ #eff6ff
+ #3f404d
+ #f8f8f9
+ #ffffff
+ #d6d5d9
+ #3f404d
+ #3f404d
+ #1e1e24
+ #04b6d4
+ #ecfeff
+ #00ca4b
+ #f0fcf8
+ #fcaa1e
+ #fffdf5
+ #fb4141
+ #fffaf5
+
\ No newline at end of file
diff --git a/src/NebulaAuth/Theme/Themes/LuxuryTheme.xaml b/src/NebulaAuth/Theme/Themes/LuxuryTheme.xaml
new file mode 100644
index 0000000..803fe57
--- /dev/null
+++ b/src/NebulaAuth/Theme/Themes/LuxuryTheme.xaml
@@ -0,0 +1,26 @@
+
+
+ #c28f58
+ #f0e3d5
+ #76717f
+ #f7f7f8
+ #d55e93
+ #f3d2e1
+ #77624a
+ #190b02
+ #2a1f16
+ #1e140d
+ #0e0702
+ #ecdac7
+ #1e1e24
+ #447b99
+ #cbdae2
+ #447571
+ #bfd0cf
+ #8262c5
+ #dcd3ef
+ #934c5e
+ #e4d2d7
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/Theme/Themes/ShadcnTheme.xaml b/src/NebulaAuth/Theme/Themes/ShadcnTheme.xaml
new file mode 100644
index 0000000..1c41e57
--- /dev/null
+++ b/src/NebulaAuth/Theme/Themes/ShadcnTheme.xaml
@@ -0,0 +1,26 @@
+
+
+ #27272a
+ #fafafa
+ #76717f
+ #f7f7f8
+ #3b82f6
+ #eff6ff
+ #474857
+ #f7f7f8
+ #ffffff
+ #f4f4f5
+ #000000
+ #18181b
+ #1e1e24
+ #06b6d4
+ #ecfeff
+ #10b981
+ #ecfdf5
+ #f97316
+ #fff7ed
+ #fb4141
+ #fffaf5
+
+
\ No newline at end of file
diff --git a/NebulaAuth/Theme/WindowStyle/NativeMethods.cs b/src/NebulaAuth/Theme/WindowStyle/NativeMethods.cs
similarity index 100%
rename from NebulaAuth/Theme/WindowStyle/NativeMethods.cs
rename to src/NebulaAuth/Theme/WindowStyle/NativeMethods.cs
diff --git a/NebulaAuth/Theme/WindowStyle/WindowChromeHelper.cs b/src/NebulaAuth/Theme/WindowStyle/WindowChromeHelper.cs
similarity index 100%
rename from NebulaAuth/Theme/WindowStyle/WindowChromeHelper.cs
rename to src/NebulaAuth/Theme/WindowStyle/WindowChromeHelper.cs
diff --git a/NebulaAuth/Theme/WindowStyle/WindowChromeRenderedBehavior.cs b/src/NebulaAuth/Theme/WindowStyle/WindowChromeRenderedBehavior.cs
similarity index 100%
rename from NebulaAuth/Theme/WindowStyle/WindowChromeRenderedBehavior.cs
rename to src/NebulaAuth/Theme/WindowStyle/WindowChromeRenderedBehavior.cs
diff --git a/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml b/src/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml
similarity index 95%
rename from NebulaAuth/Theme/WindowStyle/WindowStyle.xaml
rename to src/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml
index 4e8e25c..c17a41b 100644
--- a/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml
+++ b/src/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml
@@ -17,7 +17,8 @@
Margin="{x:Static local:WindowChromeHelper.LayoutOffsetThickness}"
BorderBrush="Transparent"
BorderThickness="1"
- Background="{DynamicResource WindowBackground}">
+ Background="{DynamicResource Base200Brush}">
+
@@ -26,11 +27,12 @@
+ Background="{DynamicResource Base300Brush}">
+
+ Background="{DynamicResource Base200Brush}">
diff --git a/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml.cs b/src/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml.cs
similarity index 100%
rename from NebulaAuth/Theme/WindowStyle/WindowStyle.xaml.cs
rename to src/NebulaAuth/Theme/WindowStyle/WindowStyle.xaml.cs
diff --git a/src/NebulaAuth/Theme/icon.png b/src/NebulaAuth/Theme/icon.png
new file mode 100644
index 0000000..b98abfc
Binary files /dev/null and b/src/NebulaAuth/Theme/icon.png differ
diff --git a/src/NebulaAuth/Theme/icon.psd b/src/NebulaAuth/Theme/icon.psd
new file mode 100644
index 0000000..77453e9
Binary files /dev/null and b/src/NebulaAuth/Theme/icon.psd differ
diff --git a/src/NebulaAuth/Theme/lock.ico b/src/NebulaAuth/Theme/lock.ico
new file mode 100644
index 0000000..40f5660
Binary files /dev/null and b/src/NebulaAuth/Theme/lock.ico differ
diff --git a/NebulaAuth/Utility/ClipboardHelper.cs b/src/NebulaAuth/Utility/ClipboardHelper.cs
similarity index 100%
rename from NebulaAuth/Utility/ClipboardHelper.cs
rename to src/NebulaAuth/Utility/ClipboardHelper.cs
diff --git a/NebulaAuth/Utility/ErrorTranslatorHelper.cs b/src/NebulaAuth/Utility/ErrorTranslatorHelper.cs
similarity index 76%
rename from NebulaAuth/Utility/ErrorTranslatorHelper.cs
rename to src/NebulaAuth/Utility/ErrorTranslatorHelper.cs
index 9f39d81..b43ad32 100644
--- a/NebulaAuth/Utility/ErrorTranslatorHelper.cs
+++ b/src/NebulaAuth/Utility/ErrorTranslatorHelper.cs
@@ -1,8 +1,8 @@
using CodingSeb.Localization;
using NebulaAuth.Core;
-using SteamLib.Exceptions;
+using SteamLib.Core.StatusCodes;
using SteamLib.Exceptions.Mobile;
-using SteamLib.ProtoCore.Enums;
+using SteamLibForked.Exceptions.Authorization;
namespace NebulaAuth.Utility;
@@ -14,11 +14,10 @@ public static class ErrorTranslatorHelper
return result ?? error.ToString();
}
-
- public static string TranslateEResult(EResult eResult)
+ public static string TranslateSteamStatusCode(SteamStatusCode statusCode)
{
- var result = GetMessage("EResult", eResult.ToString());
- return result ?? eResult.ToString();
+ var result = GetMessage("EResult", statusCode.Name);
+ return result ?? statusCode.ToString();
}
public static string TranslateLinkerError(AuthenticatorLinkerError error)
diff --git a/NebulaAuth/Utility/ExceptionHandler.cs b/src/NebulaAuth/Utility/ExceptionHandler.cs
similarity index 64%
rename from NebulaAuth/Utility/ExceptionHandler.cs
rename to src/NebulaAuth/Utility/ExceptionHandler.cs
index 395c462..9fb4598 100644
--- a/NebulaAuth/Utility/ExceptionHandler.cs
+++ b/src/NebulaAuth/Utility/ExceptionHandler.cs
@@ -4,8 +4,9 @@ using System.Threading.Tasks;
using NebulaAuth.Core;
using NebulaAuth.Model;
using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions.General;
-using SteamLib.ProtoCore.Exceptions;
+using SteamLibForked.Exceptions.Authorization;
namespace NebulaAuth.Utility;
@@ -16,53 +17,58 @@ 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);
- switch (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)
{
case SessionPermanentlyExpiredException:
{
- msg = "SessionExpiredException".GetCodeBehindLocalization();
- break;
+ return "SessionExpiredException".GetCodeBehindLocalization();
}
case SessionInvalidException:
{
- msg = "SessionExpiredException".GetCodeBehindLocalization();
- break;
+ return "SessionExpiredException".GetCodeBehindLocalization();
}
case TaskCanceledException e:
{
- msg = e.InnerException is TimeoutException
+ return e.InnerException is TimeoutException
? "TimeoutException".GetCodeBehindLocalization()
: "TaskCanceledException".GetCodeBehindLocalization();
- break;
}
case HttpRequestException e:
{
var str = "RequestError".GetCommonLocalization() + ": ";
+
if (e.StatusCode != null)
{
- msg = str + e.StatusCode;
+ str = str + e.StatusCode;
}
else if (e.InnerException != null)
{
- msg = str + e.InnerException.Message;
+ str = str + e.InnerException.Message;
}
else
{
- msg = str + e.Message;
+ str = str + e.Message;
}
- break;
+ return str;
}
case UnsupportedResponseException:
{
- msg = "UnsupportedResponseException".GetCodeBehindLocalization();
- break;
+ return "UnsupportedResponseException".GetCodeBehindLocalization();
}
case CantLoadConfirmationsException e:
{
- msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
+ var msg = LocManager.GetCodeBehindOrDefault(nameof(CantLoadConfirmationsException),
EXCEPTION_HANDLER_LOC_PATH, nameof(CantLoadConfirmationsException), "Common");
if (e.Error == LoadConfirmationsError.Unknown)
{
@@ -76,30 +82,25 @@ public static class ExceptionHandler
nameof(CantLoadConfirmationsException), e.Error.ToString());
}
- break;
+ return msg;
}
- case EResultException e:
+ case SteamStatusCodeException e:
{
- msg = "Error".GetCommonLocalization() + ": " + ErrorTranslatorHelper.TranslateEResult(e.Result);
- break;
+ return "Error".GetCommonLocalization() + ": " +
+ ErrorTranslatorHelper.TranslateSteamStatusCode(e.StatusCode);
}
case LoginException e:
{
- msg = "LoginException".GetCodeBehindLocalization() + ": " +
- ErrorTranslatorHelper.TranslateLoginError(e.Error);
- break;
+ return "LoginException".GetCodeBehindLocalization() + ": " +
+ ErrorTranslatorHelper.TranslateLoginError(e.Error);
}
case not null when handleAllExceptions:
{
- msg = "UnknownException".GetCodeBehindLocalization() + ex.Message;
- break;
+ return "UnknownException".GetCodeBehindLocalization() + exception.Message;
}
- default:
- return false;
}
- SnackbarController.SendSnackbar(prefix + msg + postfix);
- return true;
+ return null;
}
private static string GetCommonLocalization(this string key)
diff --git a/NebulaAuth/View/ConfirmationTemplates.xaml b/src/NebulaAuth/View/ConfirmationTemplates.xaml
similarity index 88%
rename from NebulaAuth/View/ConfirmationTemplates.xaml
rename to src/NebulaAuth/View/ConfirmationTemplates.xaml
index 56b2f01..9568309 100644
--- a/NebulaAuth/View/ConfirmationTemplates.xaml
+++ b/src/NebulaAuth/View/ConfirmationTemplates.xaml
@@ -7,7 +7,7 @@
xmlns:entities="clr-namespace:NebulaAuth.Model.Entities"
xmlns:vm="clr-namespace:NebulaAuth.ViewModel">
-
+
@@ -207,4 +207,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml b/src/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml
similarity index 100%
rename from NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml
rename to src/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml
diff --git a/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml.cs b/src/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml.cs
similarity index 100%
rename from NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml.cs
rename to src/NebulaAuth/View/Dialogs/ConfirmCancelDialog.xaml.cs
diff --git a/src/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml b/src/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml
new file mode 100644
index 0000000..0a02b2a
--- /dev/null
+++ b/src/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml.cs b/src/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml.cs
similarity index 100%
rename from NebulaAuth/View/Dialogs/LoginAgainDialog.xaml.cs
rename to src/NebulaAuth/View/Dialogs/LoginAgainDialog.xaml.cs
diff --git a/src/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml b/src/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml
new file mode 100644
index 0000000..ad32a0f
--- /dev/null
+++ b/src/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs b/src/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs
similarity index 100%
rename from NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs
rename to src/NebulaAuth/View/Dialogs/LoginAgainOnImportDialog.xaml.cs
diff --git a/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml b/src/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml
similarity index 55%
rename from NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml
rename to src/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml
index 785b2b5..4ac6d1d 100644
--- a/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml
+++ b/src/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml
@@ -1,4 +1,4 @@
-
+ d:DataContext="{d:DesignInstance other:LoginAgainVM}">
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+ theme:FontScaleWindow.ResizeFont="True" Margin="10" HorizontalAlignment="Left" />
-
+
diff --git a/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml.cs b/src/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml.cs
similarity index 100%
rename from NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml.cs
rename to src/NebulaAuth/View/Dialogs/SetCryptPasswordDialog.xaml.cs
diff --git a/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml b/src/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml
similarity index 100%
rename from NebulaAuth/View/Dialogs/WaitLoginDialog.xaml
rename to src/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml
diff --git a/src/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs b/src/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs
new file mode 100644
index 0000000..8ed0802
--- /dev/null
+++ b/src/NebulaAuth/View/Dialogs/WaitLoginDialog.xaml.cs
@@ -0,0 +1,30 @@
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace NebulaAuth.View.Dialogs;
+
+///
+/// Логика взаимодействия для WaitLoginDialog.xaml
+///
+public partial class WaitLoginDialog
+{
+ private TaskCompletionSource _tcs = new();
+
+ public WaitLoginDialog()
+ {
+ InitializeComponent();
+ }
+
+ 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();
+ oldTcs.SetResult(CaptchaTB.Text);
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/View/LinkerStepTemplates.xaml b/src/NebulaAuth/View/LinkerStepTemplates.xaml
new file mode 100644
index 0000000..5921781
--- /dev/null
+++ b/src/NebulaAuth/View/LinkerStepTemplates.xaml
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/View/LinkerView.xaml b/src/NebulaAuth/View/LinkerView.xaml
new file mode 100644
index 0000000..0e2f2f7
--- /dev/null
+++ b/src/NebulaAuth/View/LinkerView.xaml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NebulaAuth/View/LinkerView.xaml.cs b/src/NebulaAuth/View/LinkerView.xaml.cs
similarity index 100%
rename from NebulaAuth/View/LinkerView.xaml.cs
rename to src/NebulaAuth/View/LinkerView.xaml.cs
diff --git a/src/NebulaAuth/View/LinksView.xaml b/src/NebulaAuth/View/LinksView.xaml
new file mode 100644
index 0000000..47bd926
--- /dev/null
+++ b/src/NebulaAuth/View/LinksView.xaml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/View/LinksView.xaml.cs b/src/NebulaAuth/View/LinksView.xaml.cs
new file mode 100644
index 0000000..305d8a1
--- /dev/null
+++ b/src/NebulaAuth/View/LinksView.xaml.cs
@@ -0,0 +1,37 @@
+using System.Diagnostics;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace NebulaAuth.View;
+
+///
+/// Логика взаимодействия для LinksView.xaml
+///
+public partial class LinksView : UserControl
+{
+ public LinksView()
+ {
+ InitializeComponent();
+ }
+
+ private void Telegram_Click(object sender, RoutedEventArgs e)
+ {
+ Process.Start(new ProcessStartInfo("https://t.me/nebulaauth") {UseShellExecute = true});
+ }
+
+ private void GitHub_Click(object sender, RoutedEventArgs e)
+ {
+ Process.Start(new ProcessStartInfo("https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies")
+ {UseShellExecute = true});
+ }
+
+ private void Website_Click(object sender, RoutedEventArgs e)
+ {
+ Process.Start(new ProcessStartInfo("https://yourwebsite.com") {UseShellExecute = true});
+ }
+
+ private void Documentation_Click(object sender, RoutedEventArgs e)
+ {
+ Process.Start(new ProcessStartInfo("https://yourwebsite.com") {UseShellExecute = true});
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/View/MafileMoverStepTemplates.xaml b/src/NebulaAuth/View/MafileMoverStepTemplates.xaml
new file mode 100644
index 0000000..0bf5a16
--- /dev/null
+++ b/src/NebulaAuth/View/MafileMoverStepTemplates.xaml
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/View/MafileMoverView.xaml b/src/NebulaAuth/View/MafileMoverView.xaml
new file mode 100644
index 0000000..f0c3ab6
--- /dev/null
+++ b/src/NebulaAuth/View/MafileMoverView.xaml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/View/MafileMoverView.xaml.cs b/src/NebulaAuth/View/MafileMoverView.xaml.cs
new file mode 100644
index 0000000..275c1d7
--- /dev/null
+++ b/src/NebulaAuth/View/MafileMoverView.xaml.cs
@@ -0,0 +1,14 @@
+using System.Windows.Controls;
+
+namespace NebulaAuth.View;
+
+///
+/// Логика взаимодействия для MafileMoverView.xaml
+///
+public partial class MafileMoverView : UserControl
+{
+ public MafileMoverView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/View/ProxyManagerView.xaml b/src/NebulaAuth/View/ProxyManagerView.xaml
similarity index 87%
rename from NebulaAuth/View/ProxyManagerView.xaml
rename to src/NebulaAuth/View/ProxyManagerView.xaml
index e05fd15..5e879ca 100644
--- a/NebulaAuth/View/ProxyManagerView.xaml
+++ b/src/NebulaAuth/View/ProxyManagerView.xaml
@@ -7,13 +7,12 @@
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="{DynamicResource WindowBackground}">
+ Background="Transparent">
@@ -22,19 +21,23 @@
-
+
-
-
+
+
-
-
diff --git a/NebulaAuth/View/ProxyManagerView.xaml.cs b/src/NebulaAuth/View/ProxyManagerView.xaml.cs
similarity index 100%
rename from NebulaAuth/View/ProxyManagerView.xaml.cs
rename to src/NebulaAuth/View/ProxyManagerView.xaml.cs
diff --git a/src/NebulaAuth/View/SettingsView.xaml b/src/NebulaAuth/View/SettingsView.xaml
new file mode 100644
index 0000000..0f048fb
--- /dev/null
+++ b/src/NebulaAuth/View/SettingsView.xaml
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/NebulaAuth/View/SettingsView.xaml.cs b/src/NebulaAuth/View/SettingsView.xaml.cs
new file mode 100644
index 0000000..ee85db7
--- /dev/null
+++ b/src/NebulaAuth/View/SettingsView.xaml.cs
@@ -0,0 +1,82 @@
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Media;
+using MaterialDesignThemes.Wpf;
+
+namespace NebulaAuth.View;
+
+///
+/// Логика взаимодействия для SettingsView.xaml
+///
+public partial class SettingsView
+{
+ private readonly DialogHost? _dialogHost;
+ private bool _applyBlurBackground;
+
+ private BindingBase? _applyBlurBinding;
+ private SolidColorBrush? _defaultDialogBackground;
+ private SolidColorBrush? _defaultOverlayBackground;
+ private BindingBase? _dialogBackgroundBinding;
+ private BindingBase? _overlayBackgroundBinding;
+
+ public SettingsView()
+ {
+ InitializeComponent();
+ }
+
+ public SettingsView(DialogHost? dialogHost)
+ {
+ _dialogHost = dialogHost;
+ InitializeComponent();
+ }
+
+ private void Slider_OnMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (_dialogHost != null)
+ {
+ _applyBlurBinding = BindingOperations.GetBindingBase(_dialogHost, DialogHost.ApplyBlurBackgroundProperty);
+ _dialogBackgroundBinding =
+ BindingOperations.GetBindingBase(_dialogHost, DialogHost.DialogBackgroundProperty);
+ _overlayBackgroundBinding =
+ BindingOperations.GetBindingBase(_dialogHost, DialogHost.OverlayBackgroundProperty);
+
+
+ _defaultDialogBackground = _dialogHost.DialogBackground as SolidColorBrush;
+ _defaultOverlayBackground = _dialogHost.OverlayBackground as SolidColorBrush;
+ _applyBlurBackground = _dialogHost.ApplyBlurBackground;
+
+
+ _dialogHost.ClearValue(DialogHost.ApplyBlurBackgroundProperty);
+ _dialogHost.ApplyBlurBackground = false;
+ _dialogHost.DialogBackground = new SolidColorBrush(Colors.Transparent);
+ _dialogHost.OverlayBackground = new SolidColorBrush(Colors.Transparent);
+ }
+
+ Opacity = 0.05;
+ }
+
+ private void Slider_OnMouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if (_dialogHost != null)
+ {
+ if (_applyBlurBinding != null)
+ BindingOperations.SetBinding(_dialogHost, DialogHost.ApplyBlurBackgroundProperty, _applyBlurBinding);
+ else
+ _dialogHost.ApplyBlurBackground = _applyBlurBackground;
+
+ if (_dialogBackgroundBinding != null)
+ BindingOperations.SetBinding(_dialogHost, DialogHost.DialogBackgroundProperty,
+ _dialogBackgroundBinding);
+ else
+ _dialogHost.DialogBackground = _defaultDialogBackground;
+
+ if (_overlayBackgroundBinding != null)
+ BindingOperations.SetBinding(_dialogHost, DialogHost.OverlayBackgroundProperty,
+ _overlayBackgroundBinding);
+ else
+ _dialogHost.OverlayBackground = _defaultOverlayBackground ?? new SolidColorBrush(Colors.Transparent);
+ }
+
+ Opacity = 1.0;
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/View/UpdaterView.xaml b/src/NebulaAuth/View/UpdaterView.xaml
similarity index 100%
rename from NebulaAuth/View/UpdaterView.xaml
rename to src/NebulaAuth/View/UpdaterView.xaml
diff --git a/NebulaAuth/View/UpdaterView.xaml.cs b/src/NebulaAuth/View/UpdaterView.xaml.cs
similarity index 100%
rename from NebulaAuth/View/UpdaterView.xaml.cs
rename to src/NebulaAuth/View/UpdaterView.xaml.cs
diff --git a/src/NebulaAuth/ViewModel/Linker/DesignLinkAccountAuthStepVM.cs b/src/NebulaAuth/ViewModel/Linker/DesignLinkAccountAuthStepVM.cs
new file mode 100644
index 0000000..fcd26ca
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/DesignLinkAccountAuthStepVM.cs
@@ -0,0 +1,13 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class DesignLinkAccountAuthStepVM : ObservableObject
+{
+ [ObservableProperty] private LinkAccountStepVM _currentStep;
+
+ public DesignLinkAccountAuthStepVM()
+ {
+ CurrentStep = new LinkAccountDoneStepVM("R5555", "76561199680782345");
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/LinkAccountStepVM.cs b/src/NebulaAuth/ViewModel/Linker/LinkAccountStepVM.cs
new file mode 100644
index 0000000..763dac6
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/LinkAccountStepVM.cs
@@ -0,0 +1,18 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public abstract partial class LinkAccountStepVM : ObservableObject
+{
+ public virtual string? Tip => null;
+
+ [RelayCommand(CanExecute = nameof(CanExecute))]
+ public abstract Task Next();
+
+ public abstract bool CanExecute();
+
+ [RelayCommand]
+ public abstract void Cancel();
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/LinkAccountVM.cs b/src/NebulaAuth/ViewModel/Linker/LinkAccountVM.cs
new file mode 100644
index 0000000..fb8be06
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/LinkAccountVM.cs
@@ -0,0 +1,374 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Threading;
+using AchiesUtilities.Web.Proxy;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using NebulaAuth.Core;
+using NebulaAuth.Model;
+using NebulaAuth.Model.Entities;
+using NebulaAuth.Utility;
+using NLog;
+using SteamLib;
+using SteamLib.Abstractions;
+using SteamLib.Api.Services;
+using SteamLib.Authentication;
+using SteamLib.Authentication.LoginV2;
+using SteamLib.Core.StatusCodes;
+using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
+using SteamLib.Exceptions.Mobile;
+using SteamLib.Factory.Helpers;
+using SteamLib.ProtoCore.Enums;
+using SteamLib.SteamMobile.AuthenticatorLinker;
+using SteamLib.Web;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Abstractions.Linker;
+using SteamLibForked.Exceptions.Authorization;
+using SteamLibForked.Models.Session;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountVM : ObservableObject, ISmsCodeProvider, IPhoneNumberProvider, IEmailProvider,
+ IDisposable
+{
+ public const string LOCALIZATION_KEY = "LinkVM";
+
+ private static Logger Logger => Shell.Logger;
+ private static ILogger Logger2 => Shell.ExtensionsLogger;
+
+ int IEmailProvider.RetryCount => 3;
+ private readonly HttpClient _client;
+ private readonly HttpClientHandler _handler;
+ private readonly DynamicProxy _proxy;
+ private CancellationTokenSource _cts = new();
+ [ObservableProperty] private LinkAccountStepVM _currentStep;
+
+ [ObservableProperty] private string? _error;
+
+ private KeyValuePair? _lastProxy;
+
+ [ObservableProperty] private string? _tip;
+
+ public LinkAccountVM()
+ {
+ _proxy = new DynamicProxy();
+ var pair = ClientBuilder.BuildMobileClient(_proxy, null);
+ _client = pair.Client;
+ _handler = pair.Handler;
+ KeyValuePair? selectedProxy = null;
+ if (MaClient.DefaultProxy != null)
+ {
+ var def = ProxyStorage.Proxies.FirstOrDefault(p => p.Value.Equals(MaClient.DefaultProxy));
+
+ if (def.Value != null!)
+ {
+ selectedProxy = def;
+ }
+ }
+
+ CurrentStep = new LinkAccountAuthStepVM(selectedProxy)
+ {
+ Callback = Proceed
+ };
+ }
+
+ public async Task Proceed()
+ {
+ _cts = new CancellationTokenSource();
+ _cts.Token.Register(() => { CurrentStep.Cancel(); });
+ _handler.CookieContainer.ClearMobileSessionCookies();
+
+
+ try
+ {
+ await ProceedImpl();
+ }
+ catch (OperationCanceledException)
+ {
+ //Ignored
+ }
+ catch (Exception ex)
+ {
+ Error = ExceptionHandler.GetExceptionString(ex);
+ Logger.Error(ex, "Error while linking mafie");
+ }
+ finally
+ {
+ _cts.Dispose();
+ if (CurrentStep is not LinkAccountAuthStepVM)
+ {
+ var step = new LinkAccountAuthStepVM(_lastProxy)
+ {
+ Callback = Proceed
+ };
+ SetCurrentStep(step);
+ }
+ }
+ }
+
+ private async Task ProceedImpl()
+ {
+ // Step 1: login/pass
+ Error = null;
+ if (CurrentStep is not LinkAccountAuthStepVM authStep)
+ {
+ throw new InvalidOperationException("Current step is not an authentication step.");
+ }
+
+ var (login, pass, proxy) = authStep.GetState(_cts.Token);
+ _lastProxy = proxy;
+ _proxy.SetData(proxy?.Value);
+ var log = new LoginV2ExecutorOptions(StaticLoginConsumer.Instance, _client)
+ {
+ DeviceDetails = DeviceDetailsDefaultBuilder.GetMobileDefaultDevice(),
+ WebsiteId = "Mobile",
+ AuthProviders = [this],
+ Logger = Logger2
+ };
+
+ ISessionData session;
+ try
+ {
+ session = await LoginV2Executor.DoLogin(log, login, pass);
+ }
+ catch (UnsupportedAuthTypeException ex)
+ when (ex.AllowedGuardTypes.Contains(EAuthSessionGuardType.DeviceCode))
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLocalizationOrDefault("CantLogin") + GetLocalizationOrDefault("UnsupportedGuardType");
+ return;
+ }
+ catch (SteamStatusCodeException ex)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLocalizationOrDefault("CantLogin") +
+ ErrorTranslatorHelper.TranslateSteamStatusCode(ex.StatusCode);
+ return;
+ }
+ catch (LoginException ex)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateLoginError(ex.Error);
+ return;
+ }
+ catch (Exception ex)
+ when (ex is not OperationCanceledException)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLocalizationOrDefault("CantLogin") + ex.Message;
+ return;
+ }
+
+ if (session is not MobileSessionData msd)
+ {
+ Logger.Error("Link exception on login: session is not MobileSessionData, but {type}",
+ session.GetType().Name);
+ Error = "Session data is not MobileSession. " + session.GetType();
+ return;
+ }
+
+
+ var linkOptions = new LinkOptions(_client, StaticLoginConsumer.Instance, this,
+ this, this, Storage.BackupHandler, Logger2);
+ var linker = new SteamAuthenticatorLinker(linkOptions);
+ MobileDataExtended result;
+ try
+ {
+ result = await linker.LinkAccount(msd);
+ }
+ catch (AuthenticatorLinkerException ex)
+ {
+ Logger.Error(ex, "Link exception");
+ Error = $"{GetLocalizationCommon("Error")}: {ErrorTranslatorHelper.TranslateLinkerError(ex.Error)}";
+ return;
+ }
+ catch (HttpRequestException ex)
+ {
+ var msg = ex.StatusCode?.ToString() ?? ex.Message;
+ Error = $"{GetLocalizationCommon("RequestError")}: {msg}";
+ return;
+ }
+ catch (SteamStatusCodeException ex)
+ {
+ Logger.Error(ex, "Link exception");
+ Error = GetLocalizationOrDefault("ErrorWithCode") +
+ ErrorTranslatorHelper.TranslateSteamStatusCode(ex.StatusCode);
+
+ return;
+ }
+ catch (Exception ex)
+ when (ex is not OperationCanceledException)
+ {
+ Logger.Error(ex, "Link exception");
+ Error = GetLocalizationOrDefault("UnknownError") + ex.Message;
+ return;
+ }
+
+ var mafile = Mafile.FromMobileDataExtended(result);
+ try
+ {
+ if (proxy.HasValue)
+ mafile.Proxy = new MaProxy(proxy.Value.Key, proxy.Value.Value);
+ if (Settings.Instance.IsPasswordSet)
+ mafile.Password = PHandler.Encrypt(pass);
+ }
+ 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"));
+ await Done(mafile.RevocationCode ?? string.Empty, mafile.SteamId.Steam64.ToString());
+ }
+
+ #region Step 3: Phone Number
+
+ // Step 3: Phone number
+ public Task GetPhoneNumber(ILoginConsumer caller)
+ {
+ var step = new LinkAccountPhoneStepVM();
+ SetCurrentStep(step);
+ return step.GetResultAsync();
+ }
+
+ #endregion
+
+ #region Step 4: Confirm Phone
+
+ public Task ConfirmEmailLink(ILoginConsumer caller, EmailConfirmationType confirmationType,
+ CancellationToken cancellationToken = default)
+ {
+ var retry = CurrentStep is LinkAccountConfirmEmailStepVM;
+ var step = new LinkAccountConfirmEmailStepVM(retry);
+ SetCurrentStep(step);
+ return step.GetResultAsync();
+ }
+
+ #endregion
+
+ #region Step 5: SMS Code
+
+ public Task GetSmsCode(ILoginConsumer caller, long? phoneNumber, string? phoneHint)
+ {
+ var step = new LinkAccountSmsStepVM(phoneHint);
+ SetCurrentStep(step);
+ return step.GetResultAsync();
+ }
+
+ #endregion
+
+ #region Step 6: Email Code
+
+ public async ValueTask GetAddAuthenticatorCode(ILoginConsumer caller,
+ CancellationToken cancellationToken = default)
+ {
+ var step = new LinkAccountEmailCodeStepVM();
+ SetCurrentStep(step);
+ return await step.GetResultAsync();
+ }
+
+ #endregion
+
+ #region Step 7: Done
+
+ public async Task Done(string rCode, string steamId)
+ {
+ var step = new LinkAccountDoneStepVM(rCode, steamId);
+ SetCurrentStep(step);
+ await step.GetResultAsync();
+ }
+
+ #endregion
+
+ private void SetCurrentStep(LinkAccountStepVM step)
+ {
+ Dispatcher.CurrentDispatcher.Invoke(() =>
+ {
+ CurrentStep = step;
+ Tip = CurrentStep.Tip;
+ });
+ }
+
+ [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
+ });
+ }
+
+ private static string GetLocalizationOrDefault(string key)
+ {
+ return LocManager.GetCodeBehindOrDefault(key, LOCALIZATION_KEY, key);
+ }
+
+ private static string GetLocalizationCommon(string key)
+ {
+ return LocManager.GetCommonOrDefault(key, key);
+ }
+
+
+ public void Dispose()
+ {
+ _client.Dispose();
+ _handler.Dispose();
+ try
+ {
+ _cts.Cancel();
+ }
+ catch
+ {
+ //Ignored, may be cancelled or disposed
+ }
+
+ _cts.Dispose();
+ }
+
+ #region Step 2: Email Code
+
+ public bool IsSupportedGuardType(ILoginConsumer consumer, EAuthSessionGuardType type)
+ {
+ return type == EAuthSessionGuardType.EmailCode;
+ }
+
+ // Step 2: Email Code
+ public async Task UpdateAuthSession(HttpClient authClient, ILoginConsumer loginConsumer,
+ UpdateAuthSessionModel model,
+ CancellationToken cancellationToken = default)
+ {
+ while (true)
+ {
+ try
+ {
+ var step = new LinkAccountEmailAuthStepVM();
+ SetCurrentStep(step);
+ var res = await step.GetResultAsync();
+ var req = AuthRequestHelper.CreateEmailCodeRequest(res, model.ClientId, model.SteamId);
+ await AuthenticationServiceApi.UpdateAuthSessionWithSteamGuardCode(authClient, req, cancellationToken);
+ Error = null;
+ break;
+ }
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode.Equals(SteamStatusCode.InvalidLoginAuthCode))
+ {
+ Error = ExceptionHandler.GetExceptionString(ex);
+ }
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[1]LinkAccountAuthStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[1]LinkAccountAuthStepVM.cs
new file mode 100644
index 0000000..c85abd9
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[1]LinkAccountAuthStepVM.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using AchiesUtilities.Collections;
+using AchiesUtilities.Web.Proxy;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Model;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountAuthStepVM : LinkAccountStepVM
+{
+ public ObservableDictionary Proxies => ProxyStorage.Proxies;
+ public Func Callback { get; set; } = () => Task.CompletedTask;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _login = string.Empty;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _password = string.Empty;
+
+ [ObservableProperty] private KeyValuePair? _selectedProxy;
+
+ public LinkAccountAuthStepVM()
+ {
+ }
+
+ public LinkAccountAuthStepVM(KeyValuePair? selectedProxy)
+ {
+ SelectedProxy = selectedProxy;
+ }
+
+ public override Task Next()
+ {
+ return Callback.Invoke();
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(Login) && !string.IsNullOrWhiteSpace(Password);
+ }
+
+ public (string, string, KeyValuePair?) GetState(CancellationToken cancellationToken)
+ {
+ return (Login, Password, SelectedProxy);
+ }
+
+ public override void Cancel()
+ {
+ Login = string.Empty;
+ Password = string.Empty;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[2]LinkAccountEmailAuthStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[2]LinkAccountEmailAuthStepVM.cs
new file mode 100644
index 0000000..d6bee9b
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[2]LinkAccountEmailAuthStepVM.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountEmailAuthStepVM : LinkAccountStepVM
+{
+ public override string? Tip { get; }
+
+ private readonly TaskCompletionSource _tcs = new();
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _emailCode = string.Empty;
+
+ private bool _executing;
+
+ public LinkAccountEmailAuthStepVM()
+ {
+ Tip = LocManager.GetCodeBehindOrDefault("EnterEmailCode", LinkAccountVM.LOCALIZATION_KEY, "EnterEmailCode");
+ }
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+ public override Task Next()
+ {
+ _tcs.TrySetResult(EmailCode);
+ _executing = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(EmailCode) && EmailCode.Length == 5 && !_executing;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[3]LinkAccountPhoneStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[3]LinkAccountPhoneStepVM.cs
new file mode 100644
index 0000000..16ac490
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[3]LinkAccountPhoneStepVM.cs
@@ -0,0 +1,56 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountPhoneStepVM : LinkAccountStepVM
+{
+ public override string? Tip { get; }
+
+ private readonly TaskCompletionSource _tcs = new();
+ private bool _isExecuting;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string? _phoneNumber = string.Empty;
+
+ public LinkAccountPhoneStepVM()
+ {
+ var tipStr =
+ LocManager.GetCodeBehindOrDefault("EnterPhoneNumber", LinkAccountVM.LOCALIZATION_KEY, "EnterPhoneNumber");
+ Tip = string.Format(tipStr, PhoneNumber);
+ }
+
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+
+ public override Task Next()
+ {
+ if (string.IsNullOrEmpty(PhoneNumber))
+ {
+ _tcs.TrySetResult(null);
+ return Task.CompletedTask;
+ }
+
+ var res = long.Parse(PhoneNumber);
+ _tcs.TrySetResult(res);
+ _isExecuting = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return string.IsNullOrEmpty(PhoneNumber) ||
+ (PhoneNumber.Length >= 5 && long.TryParse(PhoneNumber, out _) && !_isExecuting);
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[4]LinkAccountConfirmEmailStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[4]LinkAccountConfirmEmailStepVM.cs
new file mode 100644
index 0000000..b4bbc8f
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[4]LinkAccountConfirmEmailStepVM.cs
@@ -0,0 +1,50 @@
+using System.Threading.Tasks;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public class LinkAccountConfirmEmailStepVM : LinkAccountStepVM
+{
+ public override string? Tip { get; }
+ private readonly TaskCompletionSource _tcs = new();
+ private bool _isExecuting;
+
+
+ public LinkAccountConfirmEmailStepVM(bool retry)
+ {
+ if (retry)
+ {
+ Tip = LocManager.GetCodeBehindOrDefault("ConfirmEmailLink", LinkAccountVM.LOCALIZATION_KEY,
+ "ClickOnEmailLinkRetry");
+ }
+ else
+ {
+ Tip = LocManager.GetCodeBehindOrDefault("ConfirmEmailLink", LinkAccountVM.LOCALIZATION_KEY,
+ "ClickOnEmailLink");
+ }
+ }
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+
+ public override Task Next()
+ {
+ _tcs.TrySetResult();
+ _isExecuting = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return !_isExecuting;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[5]LinkAccountSmsStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[5]LinkAccountSmsStepVM.cs
new file mode 100644
index 0000000..1eb8955
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[5]LinkAccountSmsStepVM.cs
@@ -0,0 +1,48 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountSmsStepVM : LinkAccountStepVM
+{
+ public override string? Tip { get; }
+ private readonly TaskCompletionSource _tcs = new();
+ private bool _isExecuting;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _smsCode = string.Empty;
+
+ public LinkAccountSmsStepVM(string? phoneTip)
+ {
+ var tipStr = LocManager.GetCodeBehindOrDefault("PhoneHint", LinkAccountVM.LOCALIZATION_KEY, "PhoneHint");
+ Tip = string.Format(tipStr, phoneTip);
+ }
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+ public override Task Next()
+ {
+ var res = int.Parse(SmsCode);
+ _tcs.TrySetResult(res);
+ _isExecuting = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(SmsCode)
+ && int.TryParse(SmsCode, out var sms)
+ && sms.ToString("D5").Length == 5
+ && !_isExecuting;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[6]LinkAccountEmailCodeStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[6]LinkAccountEmailCodeStepVM.cs
new file mode 100644
index 0000000..2c39958
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[6]LinkAccountEmailCodeStepVM.cs
@@ -0,0 +1,45 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountEmailCodeStepVM : LinkAccountStepVM
+{
+ public override string? Tip { get; }
+
+ private readonly TaskCompletionSource _tcs = new();
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _emailCode = string.Empty;
+
+ private bool _executing;
+
+ public LinkAccountEmailCodeStepVM()
+ {
+ Tip = LocManager.GetCodeBehindOrDefault("EnterEmailCode", LinkAccountVM.LOCALIZATION_KEY, "EnterEmailCode");
+ }
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+ public override Task Next()
+ {
+ _tcs.TrySetResult(EmailCode);
+ _executing = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(EmailCode) && EmailCode.Length == 5 && !_executing;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/Linker/Steps/[7]LinkAccountDoneStepVM.cs b/src/NebulaAuth/ViewModel/Linker/Steps/[7]LinkAccountDoneStepVM.cs
new file mode 100644
index 0000000..f2f869d
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/Linker/Steps/[7]LinkAccountDoneStepVM.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using CommunityToolkit.Mvvm.Input;
+using NebulaAuth.Core;
+using NebulaAuth.Model;
+
+namespace NebulaAuth.ViewModel.Linker;
+
+public partial class LinkAccountDoneStepVM : LinkAccountStepVM
+{
+ public string? InnerTip { get; }
+ private readonly TaskCompletionSource _doneTcs = new();
+ private readonly string _rCode;
+
+ public LinkAccountDoneStepVM(string rCode, string steamId)
+ {
+ var tipStr = LocManager.GetCodeBehindOrDefault("MafileLinked", LinkAccountVM.LOCALIZATION_KEY, "MafileLinked");
+ InnerTip = string.Format(tipStr, rCode, steamId);
+ _rCode = rCode;
+ }
+
+ public Task GetResultAsync()
+ {
+ return _doneTcs.Task;
+ }
+
+ public override Task Next()
+ {
+ _doneTcs.TrySetResult();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return true;
+ }
+
+ public override void Cancel()
+ {
+ _doneTcs.TrySetResult();
+ }
+
+ [RelayCommand]
+ private void CopyCode()
+ {
+ try
+ {
+ Clipboard.SetText(_rCode);
+ }
+ catch (Exception ex)
+ {
+ Shell.Logger.Error(ex, "Error whily copying RCode");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/MafileMoverStepVM.cs b/src/NebulaAuth/ViewModel/MafileMover/MafileMoverStepVM.cs
new file mode 100644
index 0000000..1a400c9
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/MafileMoverStepVM.cs
@@ -0,0 +1,23 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public abstract partial class MafileMoverStepVM : ObservableObject
+{
+ public virtual string? Tip => null;
+
+ [RelayCommand(CanExecute = nameof(CanExecute))]
+ public abstract Task Next();
+
+ public abstract bool CanExecute();
+
+ [RelayCommand(CanExecute = nameof(CancelCanExecute))]
+ public abstract void Cancel();
+
+ public virtual bool CancelCanExecute()
+ {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/MafileMoverVM.cs b/src/NebulaAuth/ViewModel/MafileMover/MafileMoverVM.cs
new file mode 100644
index 0000000..f1525e9
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/MafileMoverVM.cs
@@ -0,0 +1,377 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Threading;
+using AchiesUtilities.Web.Proxy;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using NebulaAuth.Core;
+using NebulaAuth.Model;
+using NebulaAuth.Model.Entities;
+using NebulaAuth.Utility;
+using NebulaAuth.ViewModel.Linker;
+using Newtonsoft.Json;
+using NLog;
+using SteamLib.Abstractions;
+using SteamLib.Api.Mobile;
+using SteamLib.Api.Services;
+using SteamLib.Authentication;
+using SteamLib.Authentication.LoginV2;
+using SteamLib.Core.StatusCodes;
+using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
+using SteamLib.Factory.Helpers;
+using SteamLib.ProtoCore.Enums;
+using SteamLib.ProtoCore.Services;
+using SteamLib.Web;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Exceptions.Authorization;
+using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Session;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public partial class MafileMoverVM : ObservableObject, IAuthProvider, IDisposable
+{
+ public const string LOCALIZATION_KEY = "MafileMoverVM";
+
+ private static Logger Logger => Shell.Logger;
+ private static ILogger Logger2 => Shell.ExtensionsLogger;
+ private readonly HttpClient _client;
+ private readonly HttpClientHandler _handler;
+ private readonly DynamicProxy _proxy;
+ private CancellationTokenSource _cts = new();
+ [ObservableProperty] private MafileMoverStepVM _currentStep;
+
+ [ObservableProperty] private string? _error;
+
+ private KeyValuePair? _lastProxy;
+
+ [ObservableProperty] private string? _tip;
+
+ public MafileMoverVM()
+ {
+ _proxy = new DynamicProxy();
+ var pair = ClientBuilder.BuildMobileClient(_proxy, null);
+ _client = pair.Client;
+ _handler = pair.Handler;
+ KeyValuePair? selectedProxy = null;
+ if (MaClient.DefaultProxy != null)
+ {
+ var def = ProxyStorage.Proxies.FirstOrDefault(p => p.Value.Equals(MaClient.DefaultProxy));
+
+ if (def.Value != null!)
+ {
+ selectedProxy = def;
+ }
+ }
+
+ CurrentStep = new MafileMoverAuthStepVM(selectedProxy)
+ {
+ Callback = Proceed
+ };
+ }
+
+ public async Task Proceed()
+ {
+ _cts = new CancellationTokenSource();
+ _cts.Token.Register(() => { CurrentStep.Cancel(); });
+ _handler.CookieContainer.ClearMobileSessionCookies();
+
+
+ try
+ {
+ await ProceedImpl();
+ }
+ catch (OperationCanceledException)
+ {
+ //Ignored
+ }
+ catch (Exception ex)
+ {
+ Error = ExceptionHandler.GetExceptionString(ex);
+ Logger.Error(ex, "Error while moving mafie");
+ }
+ finally
+ {
+ _cts.Dispose();
+ if (CurrentStep is not MafileMoverAuthStepVM)
+ {
+ var step = new MafileMoverAuthStepVM(_lastProxy)
+ {
+ Callback = Proceed
+ };
+ SetCurrentStep(step);
+ }
+ }
+ }
+
+ private async Task ProceedImpl()
+ {
+ // Step 1: login/pass
+ Error = null;
+ if (CurrentStep is not MafileMoverAuthStepVM authStep)
+ {
+ throw new InvalidOperationException("Current step is not an authentication step.");
+ }
+
+ var (login, pass, proxy) = authStep.GetState(_cts.Token);
+ _lastProxy = proxy;
+ _proxy.SetData(proxy?.Value);
+ var log = new LoginV2ExecutorOptions(StaticLoginConsumer.Instance, _client)
+ {
+ DeviceDetails = DeviceDetailsDefaultBuilder.GetMobileDefaultDevice(),
+ WebsiteId = "Mobile",
+ AuthProviders = [this],
+ Logger = Logger2
+ };
+
+ ISessionData session;
+ try
+ {
+ session = await LoginV2Executor.DoLogin(log, login, pass);
+ }
+ catch (UnsupportedAuthTypeException ex)
+ when (!ex.AllowedGuardTypes.Contains(EAuthSessionGuardType.DeviceCode))
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLinkerLocalizationOrDefault("CantLogin") + GetLocalizationOrDefault("GuardIsNotActive");
+ return;
+ }
+ catch (SteamStatusCodeException ex)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLinkerLocalizationOrDefault("CantLogin") +
+ ErrorTranslatorHelper.TranslateSteamStatusCode(ex.StatusCode);
+ return;
+ }
+ catch (LoginException ex)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLinkerLocalizationOrDefault("CantLogin") + ErrorTranslatorHelper.TranslateLoginError(ex.Error);
+ return;
+ }
+ catch (Exception ex)
+ when (ex is not OperationCanceledException)
+ {
+ Logger.Error(ex, "Link exception on login");
+ Error = GetLinkerLocalizationOrDefault("CantLogin") + ex.Message;
+ return;
+ }
+
+ if (session is not MobileSessionData msd)
+ {
+ Logger.Error("Link exception on login: session is not MobileSessionData, but {type}",
+ session.GetType().Name);
+ Error = "Session data is not MobileSession. " + session.GetType();
+ return;
+ }
+
+ if (CurrentStep is not MafileMoverGuardCodeStepVM)
+ {
+ //No guard was requested
+ Error = GetLocalizationOrDefault("GuardIsNotActive");
+ return;
+ }
+
+ var token = msd.GetToken(SteamDomain.Community)!.Value.Token;
+ try
+ {
+ await SteamAuthenticatorLinkerApi.RemoveAuthenticatorViaChallengeStart(_client, token, _cts.Token);
+ }
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode.Equals(SteamStatusCode.Fail))
+ {
+ Logger.Error(ex, "Move mafile exception via challenge continue");
+ Error = GetLocalizationOrDefault("SeemsNoPhoneNumber");
+ return;
+ }
+ catch (Exception ex)
+ when (ex is not OperationCanceledException)
+ {
+ Logger.Error(ex, "Move mafile exception via challenge start");
+ Error = ExceptionHandler.GetExceptionString(ex);
+ return;
+ }
+
+
+ RemoveAuthenticatorViaChallengeContinue_Response res;
+ try
+ {
+ var i = 0;
+ while (true)
+ {
+ try
+ {
+ var sms = await GetSms();
+ res = await SteamAuthenticatorLinkerApi
+ .RemoveAuthenticatorViaChallengeContinue(_client, token, sms.ToString("D5"));
+ Error = null;
+ break;
+ }
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode.Equals(SteamStatusCode.SmsCodeFailed))
+ {
+ Logger.Warn("Sms code failed, retrying {attempt} time", i + 1);
+ Error = GetLocalizationOrDefault("SmsCodeFailed");
+ if (i == 2) throw;
+ }
+
+ i++;
+ }
+ }
+ catch (Exception ex)
+ when (ex is not OperationCanceledException)
+ {
+ Logger.Error(ex, "Move mafile exception via challenge continue");
+ Error = ExceptionHandler.GetExceptionString(ex);
+ return;
+ }
+
+ var t = res.ReplacementToken;
+ var j = JsonConvert.SerializeObject(t);
+ Storage.BackupHandlerStr(login, j);
+ var mobileData = t.ToMobileDataExtended(SteamAuthenticatorLinkerApi.GenerateDeviceId(), msd);
+
+
+ var mafile = Mafile.FromMobileDataExtended(mobileData);
+ try
+ {
+ if (proxy.HasValue)
+ mafile.Proxy = new MaProxy(proxy.Value.Key, proxy.Value.Value);
+ if (Settings.Instance.IsPasswordSet)
+ mafile.Password = PHandler.Encrypt(pass);
+ }
+ 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"));
+ await Done(mafile.RevocationCode ?? string.Empty, mafile.SteamId.Steam64.ToString());
+ }
+
+ #region Step 3: Sms code
+
+ // Step 3: Sms code
+ public Task GetSms()
+ {
+ var step = new MafileMoverSmsStepVM();
+ SetCurrentStep(step);
+ return step.GetResultAsync();
+ }
+
+ #endregion
+
+ #region Step 4: Done
+
+ public async Task Done(string rCode, string steamId)
+ {
+ var step = new MafileMoverDoneStepVM(rCode, steamId);
+ SetCurrentStep(step);
+ await step.GetResultAsync();
+ }
+
+ #endregion
+
+ private void SetCurrentStep(MafileMoverStepVM step)
+ {
+ Dispatcher.CurrentDispatcher.Invoke(() =>
+ {
+ CurrentStep = step;
+ Tip = CurrentStep.Tip;
+ });
+ }
+
+ [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
+ });
+ }
+
+ private static string GetLocalizationOrDefault(string key)
+ {
+ return LocManager.GetCodeBehindOrDefault(key, LOCALIZATION_KEY, key);
+ }
+
+ private static string GetLinkerLocalizationOrDefault(string key)
+ {
+ return LocManager.GetCodeBehindOrDefault(key, LinkAccountVM.LOCALIZATION_KEY, key);
+ }
+
+ private static string GetLocalizationCommon(string key)
+ {
+ return LocManager.GetCommonOrDefault(key, key);
+ }
+
+
+ public void Dispose()
+ {
+ _client.Dispose();
+ _handler.Dispose();
+ try
+ {
+ _cts.Cancel();
+ }
+ catch
+ {
+ //Ignored, may be cancelled or disposed
+ }
+
+ _cts.Dispose();
+ }
+
+ #region Step 2: Guard Code
+
+ public bool IsSupportedGuardType(ILoginConsumer consumer, EAuthSessionGuardType type)
+ {
+ return type == EAuthSessionGuardType.DeviceCode;
+ }
+
+ // Step 2: Guard Code
+ public async Task UpdateAuthSession(HttpClient authClient, ILoginConsumer loginConsumer,
+ UpdateAuthSessionModel model,
+ CancellationToken cancellationToken = default)
+ {
+ var isRetrying = CurrentStep is MafileMoverGuardCodeStepVM;
+ while (true)
+ {
+ try
+ {
+ var step = new MafileMoverGuardCodeStepVM(isRetrying);
+ SetCurrentStep(step);
+ var res = await step.GetResultAsync();
+ if (res == null)
+ {
+ return;
+ }
+
+ var req = AuthRequestHelper.CreateMobileCodeRequest(res, model.ClientId, model.SteamId);
+ await AuthenticationServiceApi.UpdateAuthSessionWithSteamGuardCode(authClient, req, cancellationToken);
+ Error = null;
+ break;
+ }
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode.Equals(SteamStatusCode.InvalidLoginAuthCode))
+ {
+ Error = ExceptionHandler.GetExceptionString(ex);
+ }
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/Steps/[1]MafileMoverAuthStepVM.cs b/src/NebulaAuth/ViewModel/MafileMover/Steps/[1]MafileMoverAuthStepVM.cs
new file mode 100644
index 0000000..1d9750b
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/Steps/[1]MafileMoverAuthStepVM.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using AchiesUtilities.Collections;
+using AchiesUtilities.Web.Proxy;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Model;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public partial class MafileMoverAuthStepVM : MafileMoverStepVM
+{
+ public ObservableDictionary Proxies => ProxyStorage.Proxies;
+ public Func Callback { get; set; } = () => Task.CompletedTask;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _login = string.Empty;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _password = string.Empty;
+
+ [ObservableProperty] private KeyValuePair? _selectedProxy;
+
+
+ public MafileMoverAuthStepVM(KeyValuePair? selectedProxy)
+ {
+ SelectedProxy = selectedProxy;
+ }
+
+ public override Task Next()
+ {
+ return Callback.Invoke();
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(Login) && !string.IsNullOrWhiteSpace(Password);
+ }
+
+ public (string, string, KeyValuePair?) GetState(CancellationToken cancellationToken)
+ {
+ return (Login, Password, SelectedProxy);
+ }
+
+ public override void Cancel()
+ {
+ Login = string.Empty;
+ Password = string.Empty;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/Steps/[2]MafileMoverGuardCodeStepVM.cs b/src/NebulaAuth/ViewModel/MafileMover/Steps/[2]MafileMoverGuardCodeStepVM.cs
new file mode 100644
index 0000000..1d32b49
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/Steps/[2]MafileMoverGuardCodeStepVM.cs
@@ -0,0 +1,54 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public partial class MafileMoverGuardCodeStepVM : MafileMoverStepVM
+{
+ public override string? Tip { get; }
+
+ private readonly TaskCompletionSource _tcs = new();
+ private bool _executing;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _guardCode = string.Empty;
+
+ public MafileMoverGuardCodeStepVM(bool isRetrying)
+ {
+ Tip = isRetrying
+ ? LocManager.GetCodeBehindOrDefault("EnterGuardCodeRetrying", MafileMoverVM.LOCALIZATION_KEY,
+ "EnterGuardCodeRetrying")
+ : LocManager.GetCodeBehindOrDefault("EnterGuardCode", MafileMoverVM.LOCALIZATION_KEY, "EnterGuardCode");
+ }
+
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+ public override Task Next()
+ {
+ _executing = true;
+ NextCommand.NotifyCanExecuteChanged();
+ if (string.IsNullOrWhiteSpace(GuardCode))
+ {
+ _tcs.TrySetResult(null);
+ return Task.CompletedTask;
+ }
+
+ _tcs.TrySetResult(GuardCode);
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return (string.IsNullOrWhiteSpace(GuardCode) || GuardCode.Length == 5) && !_executing;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/Steps/[3]MafileMoverSmsStepVM.cs b/src/NebulaAuth/ViewModel/MafileMover/Steps/[3]MafileMoverSmsStepVM.cs
new file mode 100644
index 0000000..a48655f
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/Steps/[3]MafileMoverSmsStepVM.cs
@@ -0,0 +1,54 @@
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using NebulaAuth.Core;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public partial class MafileMoverSmsStepVM : MafileMoverStepVM
+{
+ public override string? Tip { get; }
+ private readonly TaskCompletionSource _tcs = new();
+ private bool _isExecuting;
+
+ [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(NextCommand))]
+ private string _smsCode = string.Empty;
+
+ public MafileMoverSmsStepVM()
+ {
+ var tipStr =
+ LocManager.GetCodeBehindOrDefault("SmsCodeStepTip", MafileMoverVM.LOCALIZATION_KEY, "SmsCodeStepTip");
+ Tip = tipStr;
+ }
+
+ public Task GetResultAsync()
+ {
+ return _tcs.Task;
+ }
+
+ public override Task Next()
+ {
+ var res = int.Parse(SmsCode);
+ _tcs.TrySetResult(res);
+ _isExecuting = true;
+ NextCommand.NotifyCanExecuteChanged();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return !string.IsNullOrWhiteSpace(SmsCode)
+ && int.TryParse(SmsCode, out var sms)
+ && sms.ToString("D5").Length == 5
+ && !_isExecuting;
+ }
+
+ public override void Cancel()
+ {
+ _tcs.TrySetCanceled();
+ }
+
+ public override bool CancelCanExecute()
+ {
+ return !_isExecuting;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/ViewModel/MafileMover/Steps/[4]MafileMoverDoneStepVM.cs b/src/NebulaAuth/ViewModel/MafileMover/Steps/[4]MafileMoverDoneStepVM.cs
new file mode 100644
index 0000000..499fcc3
--- /dev/null
+++ b/src/NebulaAuth/ViewModel/MafileMover/Steps/[4]MafileMoverDoneStepVM.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using CommunityToolkit.Mvvm.Input;
+using NebulaAuth.Core;
+using NebulaAuth.Model;
+
+namespace NebulaAuth.ViewModel.MafileMover;
+
+public partial class MafileMoverDoneStepVM : MafileMoverStepVM
+{
+ public string? InnerTip { get; }
+ private readonly TaskCompletionSource _doneTcs = new();
+ private readonly string _rCode;
+
+ public MafileMoverDoneStepVM(string rCode, string steamId)
+ {
+ var tipStr = LocManager.GetCodeBehindOrDefault("DoneStepTip", MafileMoverVM.LOCALIZATION_KEY, "DoneStepTip");
+ InnerTip = string.Format(tipStr, rCode, steamId);
+ _rCode = rCode;
+ }
+
+ public Task GetResultAsync()
+ {
+ return _doneTcs.Task;
+ }
+
+ public override Task Next()
+ {
+ _doneTcs.TrySetResult();
+ return Task.CompletedTask;
+ }
+
+ public override bool CanExecute()
+ {
+ return true;
+ }
+
+ public override void Cancel()
+ {
+ _doneTcs.TrySetResult();
+ }
+
+ [RelayCommand]
+ private void CopyCode()
+ {
+ try
+ {
+ Clipboard.SetText(_rCode);
+ }
+ catch (Exception ex)
+ {
+ Shell.Logger.Error(ex, "Error whily copying RCode");
+ }
+ }
+}
\ No newline at end of file
diff --git a/NebulaAuth/ViewModel/MainVM.cs b/src/NebulaAuth/ViewModel/MainVM.cs
similarity index 91%
rename from NebulaAuth/ViewModel/MainVM.cs
rename to src/NebulaAuth/ViewModel/MainVM.cs
index c3fe2c3..b536975 100644
--- a/NebulaAuth/ViewModel/MainVM.cs
+++ b/src/NebulaAuth/ViewModel/MainVM.cs
@@ -11,9 +11,10 @@ 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;
@@ -29,12 +30,12 @@ public partial class MainVM : ObservableObject
}
public bool IsMafileSelected => SelectedMafile != null;
+ public DialogHost CurrentDialogHost { get; set; } = null!;
[ObservableProperty] private ObservableCollection _maFiles = Storage.MaFiles;
private Mafile? _selectedMafile;
-
public MainVM()
{
CreateCodeTimer();
@@ -51,6 +52,12 @@ public partial class MainVM : ObservableObject
}
}
+ [RelayCommand]
+ public async Task Debug()
+ {
+ Shell.Logger.Info("test");
+ }
+
private void SetMafile(Mafile? mafile)
{
@@ -90,7 +97,7 @@ public partial class MainVM : ObservableObject
var wait = DialogHost.Show(waitDialog);
try
{
- await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword, waitDialog);
+ await MaClient.LoginAgain(SelectedMafile, password, loginAgainVm.SavePassword);
SnackbarController.SendSnackbar(GetLocalization("SuccessfulLogin"));
}
catch (LoginException ex)
@@ -137,6 +144,12 @@ public partial class MainVM : ObservableObject
await DialogsController.ShowLinkerDialog();
}
+ [RelayCommand]
+ public async Task MoveAccount()
+ {
+ await DialogsController.ShowMafileMoverDialog();
+ }
+
[RelayCommand]
private async Task RemoveAuthenticator()
{
@@ -209,6 +222,15 @@ 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)
{
diff --git a/NebulaAuth/ViewModel/MainVM_Code.cs b/src/NebulaAuth/ViewModel/MainVM_Code.cs
similarity index 74%
rename from NebulaAuth/ViewModel/MainVM_Code.cs
rename to src/NebulaAuth/ViewModel/MainVM_Code.cs
index 7a133d8..a970414 100644
--- a/NebulaAuth/ViewModel/MainVM_Code.cs
+++ b/src/NebulaAuth/ViewModel/MainVM_Code.cs
@@ -22,32 +22,36 @@ 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;
- var codeProgress = untilChange / 30D * 100;
-
- string? code = null;
- if (untilChange == 0 && SelectedMafile != null)
- {
- code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile!.SharedSecret);
- }
-
+ if (untilChange != 0) return;
if (Application.Current == null) return;
- Application.Current.Dispatcher.BeginInvoke((string? c) =>
+ Application.Current.Dispatcher.BeginInvoke(() =>
{
+ CodeProgress = -1;
+ CodeProgress = 30;
if (Application.Current.MainWindow?.WindowState == WindowState.Minimized) return;
- CodeProgress = codeProgress;
- if (c != null) Code = c;
- }, DispatcherPriority.DataBind, code);
+ if (SelectedMafile == null) return;
+ Code = SteamGuardCodeGenerator.GenerateCode(SelectedMafile.SharedSecret);
+ }, DispatcherPriority.Normal);
}
+
+ private long CalculateCodeProgress()
+ {
+ var currentTime = TimeAligner.GetSteamTime();
+ var untilChange = currentTime % 30;
+ return 30 - untilChange;
+ }
+
+
[RelayCommand(AllowConcurrentExecutions = false)]
private async Task CopyCode()
{
diff --git a/NebulaAuth/ViewModel/MainVM_Confirmations.cs b/src/NebulaAuth/ViewModel/MainVM_Confirmations.cs
similarity index 100%
rename from NebulaAuth/ViewModel/MainVM_Confirmations.cs
rename to src/NebulaAuth/ViewModel/MainVM_Confirmations.cs
diff --git a/NebulaAuth/ViewModel/MainVM_File.cs b/src/NebulaAuth/ViewModel/MainVM_File.cs
similarity index 98%
rename from NebulaAuth/ViewModel/MainVM_File.cs
rename to src/NebulaAuth/ViewModel/MainVM_File.cs
index e225d03..8b199d6 100644
--- a/NebulaAuth/ViewModel/MainVM_File.cs
+++ b/src/NebulaAuth/ViewModel/MainVM_File.cs
@@ -17,7 +17,7 @@ using NebulaAuth.Utility;
using NebulaAuth.View;
using NebulaAuth.View.Dialogs;
using NebulaAuth.ViewModel.Other;
-using SteamLib.Exceptions;
+using SteamLibForked.Exceptions.Authorization;
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, waitDialog);
+ await MaClient.LoginAgain(data, password, loginAgainVm.SavePassword);
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
+ var view = new SettingsView(CurrentDialogHost)
{
DataContext = vm
};
diff --git a/NebulaAuth/ViewModel/MainVM_Groups.cs b/src/NebulaAuth/ViewModel/MainVM_Groups.cs
similarity index 100%
rename from NebulaAuth/ViewModel/MainVM_Groups.cs
rename to src/NebulaAuth/ViewModel/MainVM_Groups.cs
diff --git a/NebulaAuth/ViewModel/MainVM_MAAC.cs b/src/NebulaAuth/ViewModel/MainVM_MAAC.cs
similarity index 100%
rename from NebulaAuth/ViewModel/MainVM_MAAC.cs
rename to src/NebulaAuth/ViewModel/MainVM_MAAC.cs
diff --git a/NebulaAuth/ViewModel/MainVM_Proxy.cs b/src/NebulaAuth/ViewModel/MainVM_Proxy.cs
similarity index 99%
rename from NebulaAuth/ViewModel/MainVM_Proxy.cs
rename to src/NebulaAuth/ViewModel/MainVM_Proxy.cs
index b288f56..1453db0 100644
--- a/NebulaAuth/ViewModel/MainVM_Proxy.cs
+++ b/src/NebulaAuth/ViewModel/MainVM_Proxy.cs
@@ -37,6 +37,7 @@ public partial class MainVM
}
if (!system && SelectedMafile != null)
+
{
SelectedMafile.Proxy = SelectedProxy;
Storage.UpdateMafile(SelectedMafile);
diff --git a/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs b/src/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs
similarity index 100%
rename from NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs
rename to src/NebulaAuth/ViewModel/Other/LoginAgainOnImportVM.cs
diff --git a/NebulaAuth/ViewModel/Other/LoginAgainVM.cs b/src/NebulaAuth/ViewModel/Other/LoginAgainVM.cs
similarity index 100%
rename from NebulaAuth/ViewModel/Other/LoginAgainVM.cs
rename to src/NebulaAuth/ViewModel/Other/LoginAgainVM.cs
diff --git a/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs b/src/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs
similarity index 100%
rename from NebulaAuth/ViewModel/Other/ProxyManagerVM.cs
rename to src/NebulaAuth/ViewModel/Other/ProxyManagerVM.cs
diff --git a/NebulaAuth/ViewModel/Other/SetEncryptPasswordVM.cs b/src/NebulaAuth/ViewModel/Other/SetEncryptPasswordVM.cs
similarity index 100%
rename from NebulaAuth/ViewModel/Other/SetEncryptPasswordVM.cs
rename to src/NebulaAuth/ViewModel/Other/SetEncryptPasswordVM.cs
diff --git a/NebulaAuth/ViewModel/Other/SettingsVM.cs b/src/NebulaAuth/ViewModel/Other/SettingsVM.cs
similarity index 62%
rename from NebulaAuth/ViewModel/Other/SettingsVM.cs
rename to src/NebulaAuth/ViewModel/Other/SettingsVM.cs
index 75f883c..9612bd8 100644
--- a/NebulaAuth/ViewModel/Other/SettingsVM.cs
+++ b/src/NebulaAuth/ViewModel/Other/SettingsVM.cs
@@ -11,11 +11,6 @@ public partial class SettingsVM : ObservableObject
{
public Settings Settings => Settings.Instance;
- public BackgroundMode BackgroundMode
- {
- get => Settings.BackgroundMode;
- set => Settings.BackgroundMode = value;
- }
public bool HideToTray
{
@@ -30,6 +25,15 @@ public partial class SettingsVM : ObservableObject
{BackgroundMode.Color, LocManager.GetOrDefault("Default", "SettingsDialog", "BackgroundMode", "NoBackground")}
};
+ public Dictionary ThemeTypes => new()
+ {
+ {ThemeType.Default, "Default"},
+ {ThemeType.Black, "Black"},
+ {ThemeType.Light, "Light"},
+ {ThemeType.Luxury, "Luxury"},
+ {ThemeType.Shadcn, "Shadcn"}
+ };
+
public Dictionary Languages { get; } = new()
{
{LocalizationLanguage.English, "English"},
@@ -37,12 +41,6 @@ public partial class SettingsVM : ObservableObject
{LocalizationLanguage.Ukrainian, "Українська"}
};
- public Color? BackgroundColor
- {
- get => Settings.BackgroundColor;
- set => Settings.BackgroundColor = value;
- }
-
public Color? IconColor
{
get => Settings.IconColor;
@@ -64,21 +62,6 @@ 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
{
@@ -122,4 +105,69 @@ 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
}
\ No newline at end of file
diff --git a/NebulaAuth/ViewModel/Other/UpdaterVM.cs b/src/NebulaAuth/ViewModel/Other/UpdaterVM.cs
similarity index 100%
rename from NebulaAuth/ViewModel/Other/UpdaterVM.cs
rename to src/NebulaAuth/ViewModel/Other/UpdaterVM.cs
diff --git a/NebulaAuth/localization.loc.json b/src/NebulaAuth/localization.loc.json
similarity index 78%
rename from NebulaAuth/localization.loc.json
rename to src/NebulaAuth/localization.loc.json
index 6db757a..db25661 100644
--- a/NebulaAuth/localization.loc.json
+++ b/src/NebulaAuth/localization.loc.json
@@ -68,14 +68,6 @@
"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": {
@@ -117,6 +109,11 @@
"ru": "Привязать",
"ua": "Прив'язати"
},
+ "MoveSteamGuard": {
+ "en": "Move Steam Guard",
+ "ru": "Перенести Steam Guard",
+ "ua": "Перенести Steam Guard"
+ },
"Unlink": {
"en": "Unlink",
"ru": "Отвязать",
@@ -207,6 +204,11 @@
"en": "Search",
"ru": "Поиск",
"ua": "Пошук"
+ },
+ "NoMafiles": {
+ "en": "No mafiles found..",
+ "ru": "Мафайлы не найдены..",
+ "ua": "Мафайли не знайдено.."
}
},
"RightPart": {
@@ -253,7 +255,12 @@
"en": "Market",
"ru": "Маркет",
"ua": "Маркет"
- }
+ },
+ "Purchase": {
+ "en": "Purchase",
+ "ru": "Покупка",
+ "ua": "Покупка"
+ }
},
"CodeCopied": {
"ru": "Скопировано",
@@ -313,6 +320,58 @@
"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": "Фон",
@@ -368,14 +427,15 @@
}
},
"LegacyMafileMode": {
- "en": "Legacy mafile mode",
- "ru": "Режим старых мафайлов",
- "ua": "Режим старих мафайлів"
+ "en": "Common mafiles format",
+ "ru": "Общепринятый формат мафайлов",
+ "ua": "Загальноприйнятий формат мафайлів"
},
"LegacyMafileModeHint": {
- "en": "Use old mafile format for compatibility with old versions of Steam Desktop Authenticator",
- "ru": "Использовать старый формат мафайлов для совместимости со старыми версиями Steam Desktop Authenticator",
- "ua": "Використовувати старий формат мафайлів для сумісності зі старими версіями Steam Desktop Authenticator"
+ "en": "Save mafiles in compatibility format with Steam Desktop Authenticator and other applications",
+ "ru":
+ "Сохранять мафайлы в старом формате для совместимости со Steam Desktop Authenticator и другими приложениями",
+ "ua": "Зберігати мафайли у старому форматі для сумісності зі Steam Desktop Authenticator та іншими додатками"
},
"AllowAutoUpdate": {
"en": "Allow auto update",
@@ -487,8 +547,8 @@
},
"Authorization": {
"en": "Authorization",
- "ru": "Авторизация",
- "ua": "Авторизація"
+ "ru": "Вход в аккаунт",
+ "ua": "Вхід в акаунт"
},
"EmailCode": {
"en": "Email code",
@@ -524,9 +584,54 @@
"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)",
@@ -551,6 +656,30 @@
"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": {
@@ -817,6 +946,11 @@
"ua": "Скасовано (52)"
},
+ "InvalidLoginAuthCode": {
+ "ru": "Неверный код авторизации (65)",
+ "en": "Invalid login auth code (65)",
+ "ua": "Невірний код авторизації (65)"
+ },
"ExpiredLoginAuthCode": {
"ru": "Истекло время кода (71)",
"en": "Expired login auth code (71)",
@@ -969,14 +1103,14 @@
},
"ExceptionHandler": {
"SessionInvalidException": {
- "ru": "Сессия истекла. Попробуйте обновить ее через меню или залогиниться заново",
- "en": "Session expired. Try to refresh it through menu or login again",
- "ua": "Сесія прострочена. Спробуйте оновити її через меню або залогінитися знову"
+ "ru": "Сессия истекла. Попробуйте обновить ее или залогиниться заново (Аккаунт → войти)",
+ "en": "Session expired. Try to refresh it or login again (Account → Login)",
+ "ua": "Сесія прострочена. Спробуйте оновити її через меню або залогінитися знову (Акаунт → Увійти)"
},
"SessionExpiredException": {
- "ru": "Сессия полностью истекла. Нужно залогиниться заново",
- "en": "Session fully expired. Need to login again",
- "ua": "Сесія повніст'ю прострочена'. Потрібно залогінитися знову"
+ "ru": "Сессия полностью истекла. Нужно залогиниться заново (Аккаунт → Войти)",
+ "en": "Session fully expired. Need to login again (Account → Login)",
+ "ua": "Сесія повніст'ю прострочена'. Потрібно залогінитися знову (Акаунт → Увійти)"
},
"TaskCanceledException": {
"ru": "Произошла отмена операции",
@@ -1062,10 +1196,15 @@
"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": "Mafile successfully linked. RCode: {0}\r\nFile name: {1}.mafile",
- "ua": "Мафайл успішно прив'язано. RCode: {0}\r\nІм'я файлу: {1}.mafile"
+ "ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
+ "en": "RCode: {0}\r\nFile name: {1}.mafile",
+ "ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
},
"ErrorWithCode": {
"ru": "Ошибка с кодом: ",
@@ -1077,25 +1216,23 @@
"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 code from email",
- "ua": "Введіть код з листа"
+ "ru": "Введите код, отправленный на вашу почту",
+ "en": "Enter the code sent to your email",
+ "ua": "Введіть код, надісланий на вашу пошту"
},
"ClickOnEmailLink": {
- "ru": "На почту было отправлено письмо, нажмите по ссылке затем - 'Продолжить'",
- "en": "Email was sent, click on link and then - 'Proceed'",
- "ua": "На пошту було відправлено лист, натисніть по посиланню потім - 'Продовжити'"
+ "ru": "На почту было отправлено письмо, откройте ссылку из письма, а затем нажмите — 'Продолжить'",
+ "en": "An email has been sent. Open the link from the email, then click 'Proceed'",
+ "ua": "На пошту надіслано лист. Відкрийте посилання з листа, а потім натисніть — 'Продовжити'"
+ },
+ "ClickOnEmailLinkRetry": {
+ "ru":
+ "Не удалось подтвердить переход по ссылке. Убедитесь, что вы открыли ссылку из письма, затем нажмите — 'Продолжить'",
+ "en":
+ "We couldn’t verify that you clicked the link. Make sure you opened the link from the email, then click 'Proceed'",
+ "ua":
+ "Не вдалося підтвердити перехід за посиланням. Переконайтесь, що ви відкрили посилання з листа, а потім натисніть — 'Продовжити'"
},
"PhoneHint": {
"ru": "На телефон {0} была отправлена СМС",
@@ -1103,39 +1240,84 @@
"ua": "На телефон {0} було відправлено СМС"
},
"EnterPhoneNumber": {
- "ru": "Введите номер телефона (без знака '+' и др. символов). По-желанию.",
- "en": "Enter phone number (without '+' and other symbols). Optional",
- "ua": "Введіть номер телефону (без знака '+' та ін. символів). За бажанням"
+ "ru":
+ "Введите номер в международном формате, только цифры (без '+', пробелов и скобок), или оставьте поле пустым, чтобы привязать без номера",
+ "en":
+ "Enter number in international format, digits only (no '+', spaces or brackets), or leave the field empty to link without a number",
+ "ua":
+ "Введіть номер у міжнародному форматі, лише цифри (без '+', пробілів і дужок), або залиште поле порожнім, щоб прив’язати без номера"
}
},
- "MAAC": {
- "TimerConfirmed": {
- "ru": "Авто: подтверждено ",
- "en": "Auto: confirmed ",
- "ua": "Авто: підтверджено "
+ "MafileMoverVM": {
+ "EnterGuardCode": {
+ "en": "Enter Steam Guard code or confirm login and click 'Proceed'",
+ "ru": "Введите код Steam Guard либо подтвердите вход и нажмите \"Продолжить\"",
+ "ua": "Введіть код Steam Guard або підтвердіть вхід і натисніть 'Продовжити'"
},
- "TimerNotConfirmed": {
- "ru": "Авто: подтверждение не сработало",
- "en": "Auto: confirmation was unsuccessful",
- "ua": "Авто: підтвердження не спрацювало"
+ "EnterGuardCodeRetrying": {
+ "en": "Failed to confirm login. Enter Steam Guard code or try again",
+ "ru": "Не удалось подтвердить вход. Введите код Steam Guard или попробуйте еще раз",
+ "ua": "Не вдалося підтвердити вхід. Введіть код Steam Guard або спробуйте ще раз"
},
- "TimerSessionError": {
- "ru": "необходимо обновить сессию или перелогиниться",
- "en": "need to refresh session or relogin",
- "ua": "необхідно оновити сесію або перелогінитися"
+ "SmsCodeStepTip": {
+ "en": "Enter the code from the SMS sent to your phone number",
+ "ru": "Введите код из СМС, отправленный на ваш номер телефона",
+ "ua": "Введіть код з СМС, надісланий на ваш номер телефону"
},
- "TimerPrefix": {
- "ru": "Авто ",
- "en": "Auto ",
- "ua": "Авто "
+ "DoneStepTip": {
+ "ru": "RCode: {0}\r\nИмя файла: {1}.mafile",
+ "en": "RCode: {0}\r\nFile name: {1}.mafile",
+ "ua": "RCode: {0}\r\nІм'я файлу: {1}.mafile"
},
- "TimerPreventedOverlap": {
- "ru": "Авто: таймер подтверждений пытался начать новый цикл, когда предыдущий еще не завершился. Советуем увеличить задержку",
- "en": "Auto: confirmation timer tried to start new cycle when previous one was not finished yet. We recommend to increase delay",
- "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-коду, спробуйте ще раз"
}
}
},
+ "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",
diff --git a/src/SteamLibForked/Abstractions/Auth/IAuthProvider.cs b/src/SteamLibForked/Abstractions/Auth/IAuthProvider.cs
new file mode 100644
index 0000000..fb3ee75
--- /dev/null
+++ b/src/SteamLibForked/Abstractions/Auth/IAuthProvider.cs
@@ -0,0 +1,34 @@
+using SteamLib.Authentication.LoginV2;
+using SteamLib.ProtoCore.Enums;
+
+namespace SteamLib.Abstractions;
+
+public interface IAuthProvider
+{
+ bool IsSupportedGuardType(ILoginConsumer consumer, EAuthSessionGuardType type);
+
+ ///
+ ///
+ /// Client which initiated auth request (typically 's client)
+ ///
+ ///
+ ///
+ ///
+ Task UpdateAuthSession(HttpClient authClient, ILoginConsumer loginConsumer, UpdateAuthSessionModel model,
+ CancellationToken cancellationToken = default);
+}
+
+//TODO: Move
+public class UpdateAuthSessionModel
+{
+ public EAuthSessionGuardType Type { get; }
+ public ulong ClientId { get; }
+ public ulong SteamId { get; }
+
+ public UpdateAuthSessionModel(EAuthSessionGuardType type, ulong clientId, ulong steamId)
+ {
+ Type = type;
+ ClientId = clientId;
+ SteamId = steamId;
+ }
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Abstractions/Auth/IEmailAuthProvider.cs b/src/SteamLibForked/Abstractions/Auth/IEmailAuthProvider.cs
new file mode 100644
index 0000000..7711b5b
--- /dev/null
+++ b/src/SteamLibForked/Abstractions/Auth/IEmailAuthProvider.cs
@@ -0,0 +1,17 @@
+namespace SteamLib.Abstractions;
+
+public enum EmailConfirmationType
+{
+ AttachPhoneAuthenticator
+}
+
+public interface IEmailProvider : IAuthProvider
+{
+ public int RetryCount { get; }
+
+ public ValueTask GetAddAuthenticatorCode(ILoginConsumer caller,
+ CancellationToken cancellationToken = default);
+
+ public Task ConfirmEmailLink(ILoginConsumer caller, EmailConfirmationType confirmationType,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Abstractions/Auth/ILoginConsumer.cs b/src/SteamLibForked/Abstractions/Auth/ILoginConsumer.cs
new file mode 100644
index 0000000..3484363
--- /dev/null
+++ b/src/SteamLibForked/Abstractions/Auth/ILoginConsumer.cs
@@ -0,0 +1,6 @@
+namespace SteamLib.Abstractions;
+
+public interface ILoginConsumer
+{
+ public string FriendlyName { get; } //RETHINK
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Abstractions/Auth/ISteamGuardProvider.cs b/src/SteamLibForked/Abstractions/Auth/ISteamGuardProvider.cs
new file mode 100644
index 0000000..3a8c4ca
--- /dev/null
+++ b/src/SteamLibForked/Abstractions/Auth/ISteamGuardProvider.cs
@@ -0,0 +1,8 @@
+using SteamLib.Abstractions;
+
+namespace SteamLibForked.Abstractions.Auth;
+
+public interface ISteamGuardProvider : IAuthProvider
+{
+ public ValueTask GetSteamGuardCode();
+}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Interfaces/ISessionData.cs b/src/SteamLibForked/Abstractions/ISessionData.cs
similarity index 75%
rename from SteamLibForked/Core/Interfaces/ISessionData.cs
rename to src/SteamLibForked/Abstractions/ISessionData.cs
index f556acd..8ece677 100644
--- a/SteamLibForked/Core/Interfaces/ISessionData.cs
+++ b/src/SteamLibForked/Abstractions/ISessionData.cs
@@ -1,13 +1,13 @@
-using SteamLib.Account;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Session;
-namespace SteamLib.Core.Interfaces;
+namespace SteamLibForked.Abstractions;
//WARNING: Any changes here should be reflected in MafileSerializer.cs
public interface ISessionData : ICloneable
{
- internal bool? IsValid { get; set; }
+ [Obsolete("Will be removed in V2")] internal bool? IsValid { get; set; }
+
public bool IsExpired => RefreshToken.IsExpired;
public string SessionId { get; }
public SteamId SteamId { get; }
diff --git a/SteamLibForked/Core/Interfaces/IPhoneNumberProvider.cs b/src/SteamLibForked/Abstractions/Linker/IPhoneNumberProvider.cs
similarity index 56%
rename from SteamLibForked/Core/Interfaces/IPhoneNumberProvider.cs
rename to src/SteamLibForked/Abstractions/Linker/IPhoneNumberProvider.cs
index ca58421..fbe25c8 100644
--- a/SteamLibForked/Core/Interfaces/IPhoneNumberProvider.cs
+++ b/src/SteamLibForked/Abstractions/Linker/IPhoneNumberProvider.cs
@@ -1,4 +1,6 @@
-namespace SteamLib.Core.Interfaces;
+using SteamLib.Abstractions;
+
+namespace SteamLibForked.Abstractions.Linker;
public interface IPhoneNumberProvider
{
diff --git a/SteamLibForked/Core/Interfaces/ISmsCodeProvider.cs b/src/SteamLibForked/Abstractions/Linker/ISmsCodeProvider.cs
similarity index 62%
rename from SteamLibForked/Core/Interfaces/ISmsCodeProvider.cs
rename to src/SteamLibForked/Abstractions/Linker/ISmsCodeProvider.cs
index d7810fe..da5e053 100644
--- a/SteamLibForked/Core/Interfaces/ISmsCodeProvider.cs
+++ b/src/SteamLibForked/Abstractions/Linker/ISmsCodeProvider.cs
@@ -1,4 +1,6 @@
-namespace SteamLib.Core.Interfaces;
+using SteamLib.Abstractions;
+
+namespace SteamLibForked.Abstractions.Linker;
public interface ISmsCodeProvider
{
diff --git a/SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs b/src/SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs
similarity index 72%
rename from SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs
rename to src/SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs
index 2fe6988..8d61aed 100644
--- a/SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs
+++ b/src/SteamLibForked/Api/Mobile/SteamAuthenticatorLinkerApi.cs
@@ -1,39 +1,54 @@
-using JetBrains.Annotations;
-using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Linq;
using SteamLib.Authentication;
using SteamLib.Core;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
using SteamLib.Core.StatusCodes;
using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions.Mobile;
using SteamLib.ProtoCore;
using SteamLib.ProtoCore.Enums;
-using SteamLib.ProtoCore.Exceptions;
using SteamLib.ProtoCore.Services;
using SteamLib.SteamMobile;
using SteamLib.SteamMobile.AuthenticatorLinker;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Core;
namespace SteamLib.Api.Mobile;
-[PublicAPI]
public static class SteamAuthenticatorLinkerApi
{
- private const string PHONE_REQ = SteamConstants.STEAM_COMMUNITY + "steamguard/phoneajax";
-
private static string GetAccessToken(this ISessionData s)
{
return s.GetToken(SteamDomain.Community)?.Token ??
throw new SessionInvalidException("Access token was null. MobileEndpoints requires valid AccessToken");
}
+ public static class Routes
+ {
+ public const string HAS_PRONE = SteamConstants.STEAM_API + "/IPhoneService/AccountPhoneStatus/v1";
+ public const string LINK_REQUEST = SteamConstants.STEAM_API + "/ITwoFactorService/AddAuthenticator/v1";
+ public const string FINALIZE_LINK = SteamConstants.STEAM_API + "/ITwoFactorService/FinalizeAddAuthenticator/v1";
+
+ public const string CHECK_EMAIL_CONFIRMATION =
+ SteamConstants.STEAM_API + "/IPhoneService/IsAccountWaitingForEmailConfirmation/v1";
+
+ public const string SEND_SMS_CODE = SteamConstants.STEAM_API + "/IPhoneService/SendPhoneVerificationCode/v1";
+ public const string ATTACH_PHONE = SteamConstants.STEAM_API + "/IPhoneService/SetAccountPhoneNumber/v1";
+ public const string VALIDATE_PHONE_NUMBER = SteamConstants.STEAM_STORE + "/phone/validate";
+ public const string PRONE_AJAX = SteamConstants.STEAM_COMMUNITY + "/steamguard/phoneajax";
+
+ public const string REMOVE_AUTHENTICATOR_VIA_CHALLENGE =
+ SteamConstants.STEAM_API + "/ITwoFactorService/RemoveAuthenticatorViaChallengeStart/v1";
+
+ public const string REMOVE_AUTHENTICATOR_VIA_CHALLENGE_CONTINUE = SteamConstants.STEAM_API +
+ "/ITwoFactorService/RemoveAuthenticatorViaChallengeContinue/v1";
+ }
+
#region Global
public static Task HasPhone(HttpClient client, string accessToken)
{
- const string uri = SteamConstants.STEAM_API + "IPhoneService/AccountPhoneStatus/v1";
-
- var reqUri = AddAccessToken(uri, accessToken);
+ var reqUri = AddAccessToken(Routes.HAS_PRONE, accessToken);
return client.PostProto(reqUri, null);
}
@@ -44,13 +59,12 @@ public static class SteamAuthenticatorLinkerApi
///
///
///
- ///
+ ///
public static async Task LinkRequest(HttpClient client, ISessionData data,
string deviceId)
{
- const string uri = SteamConstants.STEAM_API + "ITwoFactorService/AddAuthenticator/v1";
data.EnsureValidated();
- var reqUri = AddAccessToken(uri, data.GetAccessToken());
+ var reqUri = AddAccessToken(Routes.LINK_REQUEST, data.GetAccessToken());
var req = new AddAuthenticator_Request
{
SteamId = (ulong) data.SteamId.Steam64.Id,
@@ -71,36 +85,15 @@ public static class SteamAuthenticatorLinkerApi
public static async Task FinalizeLink(HttpClient client, string confirmationCode, ISessionData data,
byte[] sharedSecret, bool validateSmsCode)
{
- const string uri = SteamConstants.STEAM_API + "ITwoFactorService/FinalizeAddAuthenticator/v1";
data.EnsureValidated();
- var reqUri = AddAccessToken(uri, data.GetAccessToken());
- var time = await TimeAligner.GetSteamTimeAsync();
- if (validateSmsCode)
- {
- var validateSmsReq = new FinalizeAddAuthenticator_Request
- {
- SteamId = data.SteamId.Steam64.ToUlong(),
- AuthenticatorTime = (ulong) time,
- ConfirmationCode = confirmationCode,
- ValidateConfirmationCode = true
- };
-
- var validateResp = await client.PostProto(reqUri, validateSmsReq);
- if (validateResp.Success == false || validateResp.Status != 2)
- {
- if (validateResp.Status == 89)
- throw new AuthenticatorLinkerException(AuthenticatorLinkerError.BadConfirmationCode);
- throw new AuthenticatorLinkerException("Can't accept sms code. Status: " + validateResp.Status);
- }
- }
-
+ var reqUri = AddAccessToken(Routes.FINALIZE_LINK, data.GetAccessToken());
var tries = 0;
while (tries < 30)
{
tries++;
- time = await TimeAligner.GetSteamTimeAsync();
+ var time = await TimeAligner.GetSteamTimeAsync();
var code = SteamGuardCodeGenerator.GenerateCode(sharedSecret, time);
var req = new FinalizeAddAuthenticator_Request
@@ -108,13 +101,14 @@ public static class SteamAuthenticatorLinkerApi
SteamId = data.SteamId.Steam64.ToUlong(),
AuthenticatorCode = code,
AuthenticatorTime = (ulong) time,
- ConfirmationCode = confirmationCode
+ ConfirmationCode = confirmationCode,
+ ValidateConfirmationCode = validateSmsCode
};
var resp = await client.PostProto(reqUri, req);
- if (resp.Success && resp.WantMore == false)
+ if (resp is {Success: true, WantMore: false})
{
return new LinkResult();
}
@@ -149,8 +143,10 @@ public static class SteamAuthenticatorLinkerApi
};
var reqContent = new FormUrlEncodedContent(data);
- var req = new HttpRequestMessage(HttpMethod.Post, SteamConstants.STEAM_STORE + "phone/validate");
- req.Content = reqContent;
+ var req = new HttpRequestMessage(HttpMethod.Post, Routes.VALIDATE_PHONE_NUMBER)
+ {
+ Content = reqContent
+ };
req.Headers.Referrer = new Uri("https://store.steampowered.com/phone/add");
var resp = await client.SendAsync(req);
var content = await resp.EnsureSuccessStatusCode().Content.ReadAsStringAsync();
@@ -167,14 +163,13 @@ public static class SteamAuthenticatorLinkerApi
public static async Task AttachPhone(HttpClient client, long phoneNumber, string accessToken)
{
- const string uri = SteamConstants.STEAM_API + "IPhoneService/SetAccountPhoneNumber/v1";
var phone = '+' + phoneNumber.ToString();
var req = new SetAccountPhoneNumber_Request
{
PhoneNumber = phone
};
- var reqUri = AddAccessToken(uri, accessToken);
+ var reqUri = AddAccessToken(Routes.ATTACH_PHONE, accessToken);
var resp =
await client.PostProtoMsg(reqUri, req);
@@ -183,9 +178,7 @@ public static class SteamAuthenticatorLinkerApi
public static async Task CheckEmailConfirmation(HttpClient client, string accessToken)
{
- const string uri = SteamConstants.STEAM_API + "IPhoneService/IsAccountWaitingForEmailConfirmation/v1";
-
- var reqUri = AddAccessToken(uri, accessToken);
+ var reqUri = AddAccessToken(Routes.CHECK_EMAIL_CONFIRMATION, accessToken);
var i = 0;
while (i < 5)
@@ -204,9 +197,7 @@ public static class SteamAuthenticatorLinkerApi
public static Task SendSmsCode(HttpClient client, string accessToken)
{
- const string uri = SteamConstants.STEAM_API + "IPhoneService/SendPhoneVerificationCode/v1";
-
- var reqUri = AddAccessToken(uri, accessToken);
+ var reqUri = AddAccessToken(Routes.SEND_SMS_CODE, accessToken);
return client.PostProto(reqUri, new SendPhoneVerificationCode_Request());
}
@@ -222,9 +213,9 @@ public static class SteamAuthenticatorLinkerApi
};
var content = new FormUrlEncodedContent(data);
- var resp = await client.PostAsync(PHONE_REQ, content);
+ var resp = await client.PostAsync(Routes.PRONE_AJAX, content);
var respContent = await resp.EnsureSuccessStatusCode().Content.ReadAsStringAsync();
- var success = SteamStatusCode.Translate(respContent, out _).Equals(SteamStatusCode.Ok);
+ var success = SteamStatusCode.Translate(respContent).Equals(SteamStatusCode.Ok);
if (success) return true;
@@ -233,6 +224,26 @@ public static class SteamAuthenticatorLinkerApi
return hasPhone.HasPhone;
}
+ public static Task RemoveAuthenticatorViaChallengeStart(HttpClient client, string accessToken,
+ CancellationToken cancellationToken = default)
+ {
+ var reqUri = AddAccessToken(Routes.REMOVE_AUTHENTICATOR_VIA_CHALLENGE, accessToken);
+ return client.PostProtoEnsureSuccess(reqUri, EmptyMessage.Instance, cancellationToken);
+ }
+
+ public static Task RemoveAuthenticatorViaChallengeContinue(
+ HttpClient client, string accessToken, string smsCode, CancellationToken cancellationToken = default)
+ {
+ var req = new RemoveAuthenticatorViaChallengeContinue_Request
+ {
+ SmsCode = smsCode,
+ GenerateNewToken = true,
+ Version = 2
+ };
+ var reqUri = AddAccessToken(Routes.REMOVE_AUTHENTICATOR_VIA_CHALLENGE_CONTINUE, accessToken);
+ return client.PostProto(reqUri, req, cancellationToken);
+ }
+
private static FormUrlEncodedContent CreateAjaxContent(string op, string arg, string sessionId)
{
var data = new Dictionary
diff --git a/SteamLibForked/Api/Mobile/SteamMobileApi.cs b/src/SteamLibForked/Api/Mobile/SteamMobileApi.cs
similarity index 76%
rename from SteamLibForked/Api/Mobile/SteamMobileApi.cs
rename to src/SteamLibForked/Api/Mobile/SteamMobileApi.cs
index 3d71ab8..3e4e1b7 100644
--- a/SteamLibForked/Api/Mobile/SteamMobileApi.cs
+++ b/src/SteamLibForked/Api/Mobile/SteamMobileApi.cs
@@ -1,23 +1,16 @@
using System.Net;
-using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using SteamLib.Core;
-using SteamLib.Core.Models;
+using SteamLib.Core.StatusCodes;
using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.ProtoCore;
-using SteamLib.ProtoCore.Enums;
-using SteamLib.ProtoCore.Exceptions;
using SteamLib.ProtoCore.Services;
namespace SteamLib.Api.Mobile;
-[PublicAPI]
public static class SteamMobileApi
{
- private const string GENERATE_ACCESS_TOKEN =
- SteamConstants.STEAM_API + "IAuthenticationService/GenerateAccessTokenForApp/v1";
-
-
///
///
///
@@ -38,12 +31,12 @@ public static class SteamMobileApi
try
{
- var resp = await client.PostProto(GENERATE_ACCESS_TOKEN, req,
+ var resp = await client.PostProto(Routes.GENERATE_ACCESS_TOKEN, req,
cancellationToken);
return resp.AccessToken;
}
- catch (EResultException ex)
- when (ex.Result == EResult.AccessDenied)
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode == SteamStatusCode.AccessDenied)
{
throw new SessionPermanentlyExpiredException(
"RefreshToken is not accepted by Steam. You must login again and use new token");
@@ -60,7 +53,7 @@ public static class SteamMobileApi
{"sessionid", sessionId}
};
var content = new FormUrlEncodedContent(data);
- var resp = await client.PostAsync(SteamConstants.STEAM_COMMUNITY + "steamguard/phoneajax", content,
+ var resp = await client.PostAsync(Routes.PHONE_AJAX, content,
cancellationToken);
var respContent = await resp.EnsureSuccessStatusCode().Content.ReadAsStringAsync(cancellationToken);
@@ -75,7 +68,7 @@ public static class SteamMobileApi
public static async Task RemoveAuthenticator(HttpClient client, string accessToken,
string rCode, CancellationToken cancellationToken = default)
{
- var req = SteamConstants.STEAM_API + "ITwoFactorService/RemoveAuthenticator/v1?access_token=" + accessToken;
+ var req = Routes.REMOVE_AUTHENTICATOR + $"?access_token={accessToken}";
var reqData = new RemoveAuthenticator_Request
{
RevocationCode = rCode,
@@ -92,4 +85,15 @@ public static class SteamMobileApi
throw new SessionInvalidException(SessionInvalidException.GOT_401_MSG);
}
}
+
+ public static class Routes
+ {
+ public const string GENERATE_ACCESS_TOKEN =
+ SteamConstants.STEAM_API + "/IAuthenticationService/GenerateAccessTokenForApp/v1";
+
+ public const string PHONE_AJAX = SteamConstants.STEAM_COMMUNITY + "/steamguard/phoneajax";
+
+ public const string REMOVE_AUTHENTICATOR =
+ SteamConstants.STEAM_API + "/ITwoFactorService/RemoveAuthenticator/v1";
+ }
}
\ No newline at end of file
diff --git a/SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs b/src/SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs
similarity index 83%
rename from SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs
rename to src/SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs
index e2235cb..b02517b 100644
--- a/SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs
+++ b/src/SteamLibForked/Api/Mobile/SteamMobileConfirmationsApi.cs
@@ -1,10 +1,9 @@
using System.Net;
using AchiesUtilities.Web.Extensions;
-using JetBrains.Annotations;
using SteamLib.Core;
-using SteamLib.Core.Models;
using SteamLib.Core.StatusCodes;
using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.SteamMobile;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Utility;
@@ -12,19 +11,14 @@ using SteamLib.Web.Scrappers.JSON;
namespace SteamLib.Api.Mobile;
-[PublicAPI]
public static class SteamMobileConfirmationsApi
{
- private const string CONF = SteamConstants.STEAM_COMMUNITY + "mobileconf";
- private const string CONF_OP = SteamConstants.STEAM_COMMUNITY + "mobileconf/ajaxop";
- private const string MULTI_CONF_OP = SteamConstants.STEAM_COMMUNITY + "mobileconf/multiajaxop";
-
public static async Task> GetConfirmations(HttpClient client, MobileData data,
SteamId steamId, CancellationToken cancellationToken = default)
{
var nvc = GetConfirmationKvp(steamId, data.DeviceId, data.IdentitySecret, "list");
- var req = new Uri(CONF + "/getlist" + nvc.ToQueryString());
+ var req = new Uri(Routes.CONF_LIST + nvc.ToQueryString());
var reqMsg = new HttpRequestMessage(HttpMethod.Get, req);
var resp = await client.SendAsync(reqMsg, cancellationToken);
@@ -63,10 +57,10 @@ public static class SteamMobileConfirmationsApi
query.Add(new KeyValuePair("cid", id));
query.Add(new KeyValuePair("ck", key));
- var req = CONF_OP + query.ToQueryString();
+ var req = Routes.CONF_OP + query.ToQueryString();
var resp = await client.GetStringAsync(req, cancellationToken);
var successCode =
- SteamLibErrorMonitor.HandleResponse(resp, () => SteamStatusCode.Translate(resp, out _));
+ SteamLibErrorMonitor.HandleResponse(resp, () => SteamStatusCode.Translate(resp));
return successCode.Equals(SteamStatusCode.Ok);
}
@@ -86,10 +80,10 @@ public static class SteamMobileConfirmationsApi
}
var content = new FormUrlEncodedContent(query);
- var resp = await client.PostAsync(MULTI_CONF_OP, content, cancellationToken);
+ var resp = await client.PostAsync(Routes.MULTI_CONF_OP, content, cancellationToken);
var respStr = await resp.Content.ReadAsStringAsync(cancellationToken);
var successCode = SteamLibErrorMonitor.HandleResponse(respStr,
- () => SteamStatusCode.Translate(respStr, out _));
+ () => SteamStatusCode.Translate(respStr));
return successCode.Equals(SteamStatusCode.Ok);
}
@@ -108,4 +102,12 @@ public static class SteamMobileConfirmationsApi
KeyValuePair.Create("tag", tag)
];
}
+
+ public static class Routes
+ {
+ public const string CONF = SteamConstants.STEAM_COMMUNITY + "/mobileconf";
+ public const string CONF_LIST = SteamConstants.STEAM_COMMUNITY + "/mobileconf/getlist";
+ public const string CONF_OP = SteamConstants.STEAM_COMMUNITY + "/mobileconf/ajaxop";
+ public const string MULTI_CONF_OP = SteamConstants.STEAM_COMMUNITY + "/mobileconf/multiajaxop";
+ }
}
\ No newline at end of file
diff --git a/src/SteamLibForked/Api/Services/AuthenticationServiceApi.cs b/src/SteamLibForked/Api/Services/AuthenticationServiceApi.cs
new file mode 100644
index 0000000..11ce584
--- /dev/null
+++ b/src/SteamLibForked/Api/Services/AuthenticationServiceApi.cs
@@ -0,0 +1,113 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Net;
+using SteamLib.Core;
+using SteamLib.Exceptions.Authorization;
+using SteamLib.ProtoCore;
+using SteamLib.ProtoCore.Services;
+
+namespace SteamLib.Api.Services;
+
+public static class AuthenticationServiceApi
+{
+ // ReSharper disable InconsistentNaming
+ [SuppressMessage("ReSharper", "MemberHidesStaticFromOuterClass")]
+ public static class Routes
+ {
+ public const string SERVICE = "IAuthenticationService";
+ private const string BASE = SteamConstants.STEAM_API + "/" + SERVICE;
+
+ public const string GetAuthSessionsForAccount = BASE + "/GetAuthSessionsForAccount/v1";
+ public const string GetAuthSessionInfo = BASE + "/GetAuthSessionInfo/v1";
+
+ public const string UpdateAuthSessionWithMobileConfirmation =
+ BASE + "/UpdateAuthSessionWithMobileConfirmation/v1";
+
+ public const string GetPasswordRSAPublicKey = BASE + "/GetPasswordRSAPublicKey/v1";
+ public const string BeginAuthSessionWithCredentials = BASE + "/BeginAuthSessionViaCredentials/v1";
+ public const string PollAuthSessionStatus = BASE + "/PollAuthSessionStatus/v1";
+ public const string UpdateAuthSessionWithSteamGuardCode = BASE + "/UpdateAuthSessionWithSteamGuardCode/v1";
+ }
+
+
+ ///
+ /// Auth not required
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Task GetPasswordRSAPublicKey(HttpClient client,
+ GetPasswordRSAPublicKey_Request request, CancellationToken cancellationToken = default)
+ {
+ return client.GetProto(Routes.GetPasswordRSAPublicKey, request,
+ cancellationToken);
+ }
+
+ public static Task BeginAuthSessionViaCredentials(HttpClient client,
+ BeginAuthSessionViaCredentials_Request request, CancellationToken cancellationToken = default)
+ {
+ return client.PostProto(Routes.BeginAuthSessionWithCredentials,
+ request, cancellationToken);
+ }
+
+ public static Task PollAuthSessionStatus(HttpClient client,
+ PollAuthSessionStatus_Request request, CancellationToken cancellationToken = default)
+ {
+ return client.PostProto(Routes.PollAuthSessionStatus, request,
+ cancellationToken);
+ }
+
+
+ public static async Task GetAuthSessionsForAccount(HttpClient client,
+ string accessToken, CancellationToken cancellationToken = default)
+ {
+ var req = Routes.GetAuthSessionsForAccount.AddAccessTokenQuery(accessToken);
+ try
+ {
+ return await client.GetProto(req, EmptyMessage.Instance,
+ cancellationToken);
+ }
+ catch (HttpRequestException ex)
+ when (ex.StatusCode == HttpStatusCode.Unauthorized)
+ {
+ throw new SessionInvalidException(SessionInvalidException.GOT_401_MSG, ex);
+ }
+ }
+
+ public static async Task GetAuthSessionInfo(HttpClient client, string accessToken,
+ ulong clientId, CancellationToken cancellationToken = default)
+ {
+ var req = Routes.GetAuthSessionInfo.AddAccessTokenQuery(accessToken);
+ var reqData = new GetAuthSessionInfo_Request
+ {
+ ClientId = clientId
+ };
+ try
+ {
+ return await client.PostProto(req, reqData, cancellationToken);
+ }
+ catch (HttpRequestException ex)
+ when (ex.StatusCode == HttpStatusCode.Unauthorized)
+ {
+ throw new SessionInvalidException(SessionInvalidException.GOT_401_MSG, ex);
+ }
+ }
+
+ public static Task UpdateAuthSessionWithSteamGuardCode(HttpClient client,
+ UpdateAuthSessionWithSteamGuardCode_Request request, CancellationToken cancellationToken = default)
+ {
+ return client.PostProtoEnsureSuccess(Routes.UpdateAuthSessionWithSteamGuardCode, request, cancellationToken);
+ }
+
+ public static Task UpdateAuthSessionWithMobileConfirmation(HttpClient client, string accessToken,
+ UpdateAuthSessionWithMobileConfirmation_Request request, CancellationToken cancellationToken = default)
+ {
+ var req = Routes.UpdateAuthSessionWithMobileConfirmation.AddAccessTokenQuery(accessToken);
+ return client.PostProtoEnsureSuccess(req, request, cancellationToken);
+ }
+
+ private static string AddAccessTokenQuery(this string route, string accessToken)
+ {
+ return route + "?access_token=" + accessToken;
+ }
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Api/SteamGlobalApi.cs b/src/SteamLibForked/Api/SteamGlobalApi.cs
new file mode 100644
index 0000000..d744d23
--- /dev/null
+++ b/src/SteamLibForked/Api/SteamGlobalApi.cs
@@ -0,0 +1,86 @@
+using System.Net;
+using System.Web;
+using SteamLib.Core;
+using SteamLib.Models;
+using SteamLib.Web.Scrappers.HTML;
+
+namespace SteamLib.Api;
+
+public static class SteamGlobalApi
+{
+ //FIXME: refactor
+ public static async Task GetSessionIdFromLoginPage(HttpClient client,
+ CancellationToken cancellationToken = default)
+ {
+ var resp = await client.GetStringAsync("https://steamcommunity.com/login/home", cancellationToken);
+ return SteamLibErrorMonitor.HandleResponse(resp, ScriptHeaderScrapper.Scrap);
+ }
+
+ public static async Task GetSessionIdFromPage(HttpClient client, string url,
+ CancellationToken cancellationToken = default)
+ {
+ var resp = await client.GetStringAsync(url, cancellationToken);
+ return SteamLibErrorMonitor.HandleResponse(resp, ScriptHeaderScrapper.Scrap);
+ }
+
+
+ [Obsolete(
+ "Not recommended. Creates HttpClientHandler's copy with AllowAutoRedirect = false. Rapid usage of this method can exhaust socket pool")]
+ public static async Task EligibilityCheck(HttpClientHandler handler,
+ CancellationToken cancellationToken = default)
+ {
+ var oneTimeHandler = new HttpClientHandler
+ {
+ CookieContainer = handler.CookieContainer,
+ AllowAutoRedirect = false,
+ AutomaticDecompression = handler.AutomaticDecompression
+ };
+ var client = new HttpClient(oneTimeHandler, true);
+ var req = new HttpRequestMessage(HttpMethod.Get, SteamConstants.STEAM_COMMUNITY + "/market/eligibilitycheck/");
+ var resp = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+ var setCookieHeaders =
+ resp.Headers.FirstOrDefault(h => h.Key == "Set-Cookie").Value;
+
+ if (setCookieHeaders == null)
+ {
+ throw new NullReferenceException("Can't find 'Set-Cookie' header in EligibilityCheck response");
+ }
+
+ var wedTradeEligibility = setCookieHeaders.FirstOrDefault(s => s.StartsWith("webTradeEligibility"));
+ if (wedTradeEligibility == null)
+ {
+ throw new NullReferenceException(
+ "Can't find wedTradeEligibility header in JwtRefresh (set-token) response");
+ }
+
+ var eligibilityStr = wedTradeEligibility
+ .ToCharArray()
+ .SkipWhile(ch => !ch.Equals('='))
+ .TakeWhile(ch => !ch.Equals(';'))
+ .ToArray();
+
+ var result = new string(eligibilityStr[1..]);
+ client.Dispose();
+ return HttpUtility.UrlDecode(result);
+ }
+
+ [Obsolete(
+ "Not recommended. Creates one-time usage HttpClientHandler with AllowAutoRedirect = false. Rapid usage of this method can exhaust socket pool")]
+ public static Task EligibilityCheck(CookieContainer container,
+ CancellationToken cancellationToken = default)
+ {
+ var oneTimeHandler = new HttpClientHandler
+ {
+ CookieContainer = container,
+ AllowAutoRedirect = false,
+ AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
+ };
+ return EligibilityCheck(oneTimeHandler, cancellationToken);
+ }
+
+ public static Task SetEligibilityCheckCookies(HttpClient client, CancellationToken cancellationToken = default)
+ {
+ var req = new HttpRequestMessage(HttpMethod.Get, SteamConstants.STEAM_COMMUNITY + "/market/eligibilitycheck/");
+ return client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/AdmissionHelper.cs b/src/SteamLibForked/Authentication/AdmissionHelper.cs
similarity index 80%
rename from SteamLibForked/Authentication/AdmissionHelper.cs
rename to src/SteamLibForked/Authentication/AdmissionHelper.cs
index 77250f8..8404c84 100644
--- a/SteamLibForked/Authentication/AdmissionHelper.cs
+++ b/src/SteamLibForked/Authentication/AdmissionHelper.cs
@@ -1,14 +1,15 @@
using System.Net;
using AchiesUtilities.Extensions;
-using JetBrains.Annotations;
-using SteamLib.Account;
+using AchiesUtilities.Models;
+using Newtonsoft.Json;
using SteamLib.Core;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
+using SteamLib.Models.Account;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Session;
namespace SteamLib.Authentication;
-[PublicAPI]
public static class AdmissionHelper
{
public const string ACCESS_COOKIE_NAME = "steamLoginSecure";
@@ -16,6 +17,28 @@ public static class AdmissionHelper
public const string LANGUAGE_COOKIE_NAME = "Steam_Language";
public const string SESSION_ID_COOKIE_NAME = "sessionid";
+ private static readonly Uri SteamLoginUri = new(SteamConstants.STEAM_LOGIN);
+
+ public static void InjectWebTradeEligibilityCookie(this CookieContainer container,
+ WebTradeEligibility? eligibility = null)
+ {
+ eligibility ??= new WebTradeEligibility
+ {
+ Allowed = 1,
+ AllowedAtTime = 0,
+ SteamGuardRequiredDays = 15,
+ NewDeviceCooldownDays = 0,
+ TimeChecked = UnixTimeStamp.FromDateTime(DateTime.Now)
+ };
+ var json = JsonConvert.SerializeObject(eligibility);
+ var encoded = WebUtility.UrlEncode(json);
+ var cookie = new Cookie("webTradeEligibility", encoded, "/")
+ {
+ HttpOnly = true
+ };
+ container.Add(SteamDomains.DomainUris[SteamDomain.Community], cookie);
+ }
+
#region Main
///
@@ -33,7 +56,7 @@ public static class AdmissionHelper
container.Add(community, new Cookie(SESSION_ID_COOKIE_NAME, sessionData.SessionId, "/"));
container.Add(community, new Cookie(LANGUAGE_COOKIE_NAME, setLanguage, "/"));
TransferCommunityCookies(container);
- foreach (var domain in SteamDomains.AllDomains)
+ foreach (var domain in SteamDomains.AuthDomains)
{
var token = sessionData.GetToken(domain);
if (token == null) continue;
@@ -53,11 +76,10 @@ public static class AdmissionHelper
AddTokenCookie(container, token);
}
-
///
/// Clear and set new session
///
- public static void SetSteamMobileCookies(this CookieContainer container, IMobileSessionData mobileSession,
+ public static void SetSteamMobileCookies(this CookieContainer container, ISessionData mobileSession,
string setLanguage = "english")
{
container.ClearSteamCookies(setLanguage);
@@ -70,11 +92,10 @@ public static class AdmissionHelper
container.Add(community, new Cookie(SESSION_ID_COOKIE_NAME, mobileSession.SessionId));
container.Add(community, new Cookie(LANGUAGE_COOKIE_NAME, setLanguage));
TransferCommunityCookies(container);
-
- foreach (var domain in SteamDomains.AllDomains)
+ foreach (var domain in SteamDomains.AuthDomains)
{
var token = mobileSession.GetToken(domain);
- if (token == null || token.Value.IsExpired) continue;
+ if (token == null) continue;
AddTokenCookie(container, token.Value);
}
}
@@ -111,10 +132,17 @@ public static class AdmissionHelper
var mobileToken = mobileSession.GetMobileToken();
if (domainCookieSet == false && mobileToken is {IsExpired: false})
- AddTokenCookie(container, SteamDomain.Community, mobileToken.Value);
+ {
+ var domain = SteamDomains.GetDomainUri(SteamDomain.Community);
+ container.Add(domain, new Cookie(ACCESS_COOKIE_NAME, mobileToken.Value.SignedToken)
+ {
+ HttpOnly = true,
+ Secure = true,
+ Expires = mobileToken.Value.Expires.ToLocalDateTime()
+ });
+ }
}
-
public static void AddMinimalMobileCookies(this CookieContainer container)
{
var community = SteamDomains.GetDomainUri(SteamDomain.Community);
@@ -145,6 +173,15 @@ public static class AdmissionHelper
TransferCommunityCookies(container);
}
+ public static void ClearAllCookies(this CookieContainer container)
+ {
+ var cookies = container.GetAllCookies().ToList();
+ foreach (var cookie in cookies)
+ {
+ cookie.Expired = true;
+ }
+ }
+
#endregion
#region Helpers
@@ -163,6 +200,7 @@ public static class AdmissionHelper
container.Add(SteamDomains.GetDomainUri(SteamDomain.Store), CloneCookie(cookie));
container.Add(SteamDomains.GetDomainUri(SteamDomain.Help), CloneCookie(cookie));
container.Add(SteamDomains.GetDomainUri(SteamDomain.TV), CloneCookie(cookie));
+ container.Add(SteamDomains.GetDomainUri(SteamDomain.Checkout), CloneCookie(cookie));
}
return;
@@ -181,7 +219,7 @@ public static class AdmissionHelper
$"Token must be of type Refresh or MobileRefresh. Provided token has type: {token.Type}",
nameof(token));
var refreshToken = token.SignedToken;
- container.Add(SteamDomains.LoginSteamDomain, new Cookie(REFRESH_COOKIE_NAME, refreshToken)
+ container.Add(SteamLoginUri, new Cookie(REFRESH_COOKIE_NAME, refreshToken)
{
Expires = token.Expires.ToLocalDateTime()
});
@@ -193,13 +231,8 @@ public static class AdmissionHelper
throw new ArgumentException($"Token must be of type AccessToken. Provided token has type: {token.Type}",
nameof(token));
- AddTokenCookie(container, token.Domain, token);
- }
-
- private static void AddTokenCookie(CookieContainer container, SteamDomain domain, SteamAuthToken token)
- {
- var domainUri = SteamDomains.GetDomainUri(domain);
- container.Add(domainUri, new Cookie(ACCESS_COOKIE_NAME, token.SignedToken)
+ var domain = SteamDomains.GetDomainUri(token.Domain);
+ container.Add(domain, new Cookie(ACCESS_COOKIE_NAME, token.SignedToken)
{
HttpOnly = true,
Secure = true,
@@ -225,13 +258,5 @@ public static class AdmissionHelper
.Value;
}
- public static void ClearAllCookies(this CookieContainer container)
- {
- foreach (Cookie allCookie in container.GetAllCookies())
- {
- allCookie.Expired = true;
- }
- }
-
#endregion
}
\ No newline at end of file
diff --git a/src/SteamLibForked/Authentication/AuthHelper.cs b/src/SteamLibForked/Authentication/AuthHelper.cs
new file mode 100644
index 0000000..3b1c9f2
--- /dev/null
+++ b/src/SteamLibForked/Authentication/AuthHelper.cs
@@ -0,0 +1,93 @@
+using System.Security.Cryptography;
+using SteamLib.ProtoCore.Enums;
+using SteamLib.ProtoCore.Services;
+
+namespace SteamLib.Authentication;
+
+public static class AuthRequestHelper
+{
+ #region MobileGuard
+
+ public static UpdateAuthSessionWithSteamGuardCode_Request CreateMobileCodeRequest(string code, ulong clientId,
+ SteamId steamId)
+ {
+ return CreateMobileCodeRequest(code, clientId, steamId.Steam64.ToUlong());
+ }
+
+ public static UpdateAuthSessionWithSteamGuardCode_Request CreateMobileCodeRequest(string code, ulong clientId,
+ ulong steamId)
+ {
+ return new UpdateAuthSessionWithSteamGuardCode_Request
+ {
+ Code = code,
+ ClientId = clientId,
+ Steamid = steamId,
+ CodeType = EAuthSessionGuardType.DeviceCode
+ };
+ }
+
+ #endregion
+
+ #region EmailGuard
+
+ public static UpdateAuthSessionWithSteamGuardCode_Request CreateEmailCodeRequest(string code, ulong clientId,
+ SteamId steamId)
+ {
+ return CreateEmailCodeRequest(code, clientId, steamId.Steam64.ToUlong());
+ }
+
+ public static UpdateAuthSessionWithSteamGuardCode_Request CreateEmailCodeRequest(string code, ulong clientId,
+ ulong steamId)
+ {
+ return new UpdateAuthSessionWithSteamGuardCode_Request
+ {
+ Code = code,
+ ClientId = clientId,
+ Steamid = steamId,
+ CodeType = EAuthSessionGuardType.EmailCode
+ };
+ }
+
+ #endregion
+
+ #region MobileConf
+
+ public static UpdateAuthSessionWithMobileConfirmation_Request CreateMobileConfirmationRequest(int version,
+ ulong clientId, SteamId steamId, string sharedSecret)
+ {
+ return new UpdateAuthSessionWithMobileConfirmation_Request
+ {
+ Version = version,
+ ClientId = clientId,
+ Steamid = steamId.Steam64.ToUlong(),
+ Signature = ComputeConfirmationSignature(version, clientId, steamId, sharedSecret),
+ Confirm = true,
+ Persistence = 1
+ };
+ }
+
+ public static void EnrichMobileConfirmationWithSignature(UpdateAuthSessionWithMobileConfirmation_Request request,
+ string sharedSecret)
+ {
+ request.Signature = ComputeConfirmationSignature(request.Version, request.ClientId,
+ request.Steamid, sharedSecret);
+ }
+
+ public static byte[] ComputeConfirmationSignature(int version, ulong clientId, SteamId steamId, string sharedSecret)
+ {
+ return ComputeConfirmationSignature(version, clientId, steamId.Steam64.ToUlong(), sharedSecret);
+ }
+
+ public static byte[] ComputeConfirmationSignature(int version, ulong clientId, ulong steamId, string sharedSecret)
+ {
+ var signatureData = new byte[2 + 8 + 8];
+ BitConverter.GetBytes(version).CopyTo(signatureData, 0);
+ BitConverter.GetBytes(clientId).CopyTo(signatureData, 2);
+ BitConverter.GetBytes(steamId).CopyTo(signatureData, 10);
+
+ using var hmac = new HMACSHA256(Convert.FromBase64String(sharedSecret));
+ return hmac.ComputeHash(signatureData);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/LoginV2/FinalizeLoginJson.cs b/src/SteamLibForked/Authentication/LoginV2/FinalizeLoginJson.cs
similarity index 100%
rename from SteamLibForked/Authentication/LoginV2/FinalizeLoginJson.cs
rename to src/SteamLibForked/Authentication/LoginV2/FinalizeLoginJson.cs
diff --git a/src/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs b/src/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs
new file mode 100644
index 0000000..4cc34ca
--- /dev/null
+++ b/src/SteamLibForked/Authentication/LoginV2/LoginV2Executor.cs
@@ -0,0 +1,293 @@
+using AchiesUtilities.Web.Extensions;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using SteamLib.Abstractions;
+using SteamLib.Api;
+using SteamLib.Api.Services;
+using SteamLib.Core;
+using SteamLib.Core.StatusCodes;
+using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
+using SteamLib.ProtoCore.Enums;
+using SteamLib.ProtoCore.Services;
+using SteamLib.Utility;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Exceptions.Authorization;
+using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Session;
+
+namespace SteamLib.Authentication.LoginV2;
+
+public class LoginV2Executor //FIXME: logs
+{
+ private ILoginConsumer Caller { get; }
+ private HttpClient HttpClient { get; }
+ private ILogger? Logger { get; }
+ private IReadOnlyList AuthProviders { get; }
+ private string WebsiteId { get; }
+ private DeviceDetails DeviceDetails { get; }
+
+ private LoginV2Executor(LoginV2ExecutorOptions options)
+ {
+ Caller = options.Consumer;
+ HttpClient = options.HttpClient;
+ Logger = options.Logger;
+ AuthProviders = options.AuthProviders;
+ WebsiteId = options.WebsiteId ?? throw new NullReferenceException("WebsiteId was null");
+ DeviceDetails = options.DeviceDetails ?? throw new NullReferenceException("DeviceDetails was null");
+ }
+
+
+ ///
+ /// Do log in on SteamCommunity.
+ /// Some functions require proper SessionId. But contains only SteamCommunity related
+ /// SessionId and some functions on other services may not work
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// or depending on which token type is returned
+ ///
+ ///
+ ///
+ public static async Task DoLogin(LoginV2ExecutorOptions options, string username, string password,
+ CancellationToken cancellationToken = default)
+ {
+ var executor = new LoginV2Executor(options);
+ var client = executor.HttpClient;
+ var logger = options.Logger;
+
+ var header = await SteamGlobalApi.GetSessionIdFromLoginPage(client, cancellationToken);
+ var sessionId = header.SessionId;
+
+ var rsgMsg = new GetPasswordRSAPublicKey_Request
+ {
+ AccountName = username
+ };
+
+ var rsaResp = await AuthenticationServiceApi.GetPasswordRSAPublicKey(client, rsgMsg, cancellationToken);
+ logger?.LogTrace("Got RSA");
+
+ var encodedPassword =
+ EncryptionHelper.ToBase64EncryptedPassword(rsaResp.PublickKeyExp, rsaResp.PublickKeyMod, password);
+
+
+ var beginAuthMsg = new BeginAuthSessionViaCredentials_Request
+ {
+ DeviceFriendlyName = string.Empty,
+ AccountName = username,
+ EncryptedPassword = encodedPassword,
+ EncryptionTimestamp = rsaResp.Timestamp,
+ RememberLogin = true,
+ PlatformType = executor.DeviceDetails.PlatformType,
+ Persistence = 1,
+ WebsiteId = executor.WebsiteId,
+ DeviceDetails = executor.DeviceDetails
+ };
+
+ logger?.LogDebug("Sending encrypted password to Steam");
+ BeginAuthSessionViaCredentials_Response beginAuthResp;
+ try
+ {
+ beginAuthResp =
+ await AuthenticationServiceApi.BeginAuthSessionViaCredentials(client, beginAuthMsg, cancellationToken);
+ }
+ catch (SteamStatusCodeException ex)
+ when (ex.StatusCode == SteamStatusCode.InvalidPassword)
+ {
+ throw new LoginException(LoginError.InvalidCredentials);
+ }
+
+ logger?.LogDebug("Password accepted");
+ var clientId = beginAuthResp.ClientId;
+ var steamId = beginAuthResp.Steamid;
+
+ var wantMore = true;
+
+
+ PollAuthSessionStatus_Response? pollResp = null;
+ for (var i = 0; i < 3; i++)
+ {
+ if (beginAuthResp.AllowedConfirmations.Count > 0 &&
+ beginAuthResp.AllowedConfirmations.All(a => a.ConfirmationType != EAuthSessionGuardType.None))
+ {
+ var t = SelectProvider(options, beginAuthResp.AllowedConfirmations);
+ if (!t.HasValue)
+ {
+ throw new UnsupportedAuthTypeException(
+ beginAuthResp.AllowedConfirmations.Select(a => a.ConfirmationType).ToArray());
+ }
+
+ var provider = t.Value.Item1;
+ var guardType = t.Value.Item2;
+ logger?.LogDebug("Asking {provider} {guardType} for confirmation", provider.GetType().Name, guardType);
+ var model = new UpdateAuthSessionModel(guardType, clientId, steamId);
+ await UpdateSessionAndMapException(client, executor.Caller, provider, model, cancellationToken);
+ }
+
+ var pollSessionMsg = new PollAuthSessionStatus_Request
+ {
+ ClientId = clientId,
+ RequestId = beginAuthResp.RequestId
+ };
+
+ pollResp = await AuthenticationServiceApi.PollAuthSessionStatus(client, pollSessionMsg, cancellationToken);
+ if (pollResp.AccessToken != null! && pollResp.RefreshToken != null!)
+ {
+ break;
+ }
+ }
+
+ if (pollResp == null)
+ {
+ throw new LoginException(LoginError.SessionPollingFailed);
+ }
+
+
+ SteamAuthToken refreshToken;
+ try
+ {
+ refreshToken = SteamTokenHelper.Parse(pollResp.RefreshToken);
+ if (refreshToken.Type is not (SteamAccessTokenType.Refresh or SteamAccessTokenType.MobileRefresh))
+ throw new InvalidOperationException(
+ "Refresh token must be of type Refresh or MobileRefresh. No 'renew' audience found in JWT.");
+ }
+ catch (ArgumentException ex)
+ {
+ throw new LoginException(null,
+ "Steam returned invalid refresh token or it's schema was unsupported. See inner exception for more details",
+ LoginError.UndefinedError, ex);
+ }
+
+ var data = new Dictionary
+ {
+ {"nonce", pollResp.RefreshToken},
+ {"sessionid", sessionId}
+ };
+
+ logger?.LogInformation("Got refresh token. Finalizing log-in");
+ var finalize = await client.PostAsync("https://login.steampowered.com/jwt/finalizelogin",
+ new FormUrlEncodedContent(data), cancellationToken);
+ var finalizeContent = await finalize.EnsureSuccessStatusCode().Content.ReadAsStringAsync(cancellationToken);
+
+ var finalizeResp =
+ JsonConvert.DeserializeObject(finalizeContent)!; //We don't want to log sensitive data
+
+
+ List tokens = [];
+ foreach (var transferInfo in finalizeResp.TransferInfo)
+ {
+ var transferData = new Dictionary
+ {
+ {"nonce", transferInfo.TransferInfoParams.Nonce},
+ {"auth", transferInfo.TransferInfoParams.Auth},
+ {"steamID", steamId.ToString()}
+ };
+
+
+ try
+ {
+ var req = new HttpRequestMessage(HttpMethod.Post, transferInfo.Url);
+ req.Content = new FormUrlEncodedContent(transferData);
+ req.Headers.Referrer = SteamDomains.GetDomainUri(SteamDomain.Store);
+ var transferResp = await client.SendAsync(req, cancellationToken);
+ var transferContent = await transferResp.ReadAsStringEnsureSuccessAsync(cancellationToken);
+ var status = JObject.Parse(transferContent);
+ var result = status["result"]?.Value();
+ if (result != null)
+ SteamStatusCode.ValidateSuccessOrThrow(result.Value);
+
+ var tokenStr = SteamTokenHelper.ExtractJwtFromSetCookiesHeader(transferResp.Headers);
+ var token = SteamTokenHelper.Parse(tokenStr);
+ tokens.Add(token);
+ }
+ catch (Exception ex)
+ {
+ logger?.LogWarning(ex, "Error while transferring tokens for URI: {uri}", transferInfo.Url);
+ }
+ }
+
+ var accessToken = SteamTokenHelper.Parse(pollResp.AccessToken);
+
+ logger?.LogInformation("Login successful. Got {authTokenType}", accessToken.Type);
+ if (accessToken.Type == SteamAccessTokenType.Mobile)
+ {
+ return new MobileSessionData(sessionId, SteamId.FromSteam64(steamId), refreshToken, accessToken, tokens);
+ }
+
+ return new SessionData(sessionId, SteamId.FromSteam64(steamId), refreshToken, tokens);
+ }
+
+ private static async Task UpdateSessionAndMapException(HttpClient client, ILoginConsumer consumer,
+ IAuthProvider provider, UpdateAuthSessionModel model, CancellationToken cancellationToken = default)
+ {
+ //Also DuplicateRequest means invalid steamId/clientId in MobileConf
+ try
+ {
+ await provider.UpdateAuthSession(client, consumer, model, cancellationToken);
+ }
+ catch (SteamStatusCodeException ex)
+ when (IsSupported(ex.StatusCode))
+ {
+ var loginError = Map(ex.StatusCode);
+ throw new LoginException(loginError, ex);
+ }
+
+ return;
+
+ bool IsSupported(SteamStatusCode code)
+ {
+ return code == SteamStatusCode.InvalidLoginAuthCode ||
+ code == SteamStatusCode.InvalidSignature ||
+ code == SteamStatusCode.TwoFactorCodeMismatch;
+ }
+
+ LoginError Map(SteamStatusCode code)
+ {
+ if (code == SteamStatusCode.InvalidLoginAuthCode)
+ {
+ return LoginError.InvalidEmailAuthCode;
+ }
+
+ if (code == SteamStatusCode.InvalidSignature)
+ {
+ return LoginError.InvalidSharedSecret;
+ }
+
+ if (code == SteamStatusCode.TwoFactorCodeMismatch)
+ {
+ return LoginError.InvalidTwoFactorCode;
+ }
+
+ return LoginError.UndefinedError;
+ }
+ }
+
+ private static (IAuthProvider, EAuthSessionGuardType)? SelectProvider(LoginV2ExecutorOptions options,
+ List allowed)
+ {
+ foreach (var guardType in options.PreferredGuardTypes)
+ {
+ var availableProvider =
+ options.AuthProviders.FirstOrDefault(a => a.IsSupportedGuardType(options.Consumer, guardType));
+ if (availableProvider != null)
+ {
+ return (availableProvider, guardType);
+ }
+ }
+
+ foreach (var allowedConfirmation in allowed)
+ {
+ var availableProvider = options.AuthProviders.FirstOrDefault(a =>
+ a.IsSupportedGuardType(options.Consumer, allowedConfirmation.ConfirmationType));
+ if (availableProvider != null)
+ {
+ return (availableProvider, allowedConfirmation.ConfirmationType);
+ }
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs b/src/SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs
similarity index 63%
rename from SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs
rename to src/SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs
index d670b34..9116f13 100644
--- a/SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs
+++ b/src/SteamLibForked/Authentication/LoginV2/LoginV2ExecutorOptions.cs
@@ -1,5 +1,5 @@
using Microsoft.Extensions.Logging;
-using SteamLib.Core.Interfaces;
+using SteamLib.Abstractions;
using SteamLib.ProtoCore.Enums;
using SteamLib.ProtoCore.Services;
@@ -10,33 +10,25 @@ public class LoginV2ExecutorOptions
public ILoginConsumer Consumer { get; }
public HttpClient HttpClient { get; }
public ILogger? Logger { get; init; }
- public IEmailProvider? EmailAuthProvider { get; init; }
- public ISteamGuardProvider? SteamGuardProvider { get; init; }
+ public IReadOnlyList AuthProviders { get; init; } = [];
+ public List PreferredGuardTypes { get; init; } = [];
public DeviceDetails? DeviceDetails { get; init; }
///
/// Gets or sets the website id that the login will be performed for.
/// Known values are "Unknown", "Client", "Mobile", "Website", "Store", "Community", "Partner", "SteamStats".
- /// Default value will be set to "Community"
///
/// The website id.
public string? WebsiteId { get; init; }
+
+ ///
+ ///
+ ///
+ ///
public LoginV2ExecutorOptions(ILoginConsumer consumer, HttpClient httpClient)
{
Consumer = consumer;
HttpClient = httpClient;
}
-
-
- public string GetWebsiteIdOrDefault()
- {
- return WebsiteId ?? "Community";
- }
-
-
- public static DeviceDetails GetMobileDefaultDevice() //FORTEST
- {
- return new DeviceDetails("Pixel 6 Pro", EAuthTokenPlatformType.MobileApp, -500, 528);
- }
}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/SessionDataValidator.cs b/src/SteamLibForked/Authentication/SessionDataValidator.cs
similarity index 91%
rename from SteamLibForked/Authentication/SessionDataValidator.cs
rename to src/SteamLibForked/Authentication/SessionDataValidator.cs
index 348bdc9..525fcb9 100644
--- a/SteamLibForked/Authentication/SessionDataValidator.cs
+++ b/src/SteamLibForked/Authentication/SessionDataValidator.cs
@@ -1,15 +1,14 @@
-using JetBrains.Annotations;
-using Microsoft.Extensions.Options;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
-using SteamLib.Core.Models;
-using SteamLib.Exceptions;
+using Microsoft.Extensions.Options;
+using SteamLib.Exceptions.Authorization;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Session;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Authentication;
public static class SessionDataValidator
{
- [PublicAPI] public static Dictionary> Validators { get; } = new();
+ public static Dictionary> Validators { get; } = new();
public static ValidateOptionsResult Validate(string? name, ISessionData data)
{
diff --git a/src/SteamLibForked/Authentication/StaticLoginConsumer.cs b/src/SteamLibForked/Authentication/StaticLoginConsumer.cs
new file mode 100644
index 0000000..c6a5140
--- /dev/null
+++ b/src/SteamLibForked/Authentication/StaticLoginConsumer.cs
@@ -0,0 +1,9 @@
+using SteamLib.Abstractions;
+
+namespace SteamLib.Authentication;
+
+public class StaticLoginConsumer : ILoginConsumer
+{
+ public string FriendlyName => nameof(StaticLoginConsumer);
+ public static StaticLoginConsumer Instance { get; } = new();
+}
\ No newline at end of file
diff --git a/SteamLibForked/Authentication/SteamTokenHelper.cs b/src/SteamLibForked/Authentication/SteamTokenHelper.cs
similarity index 98%
rename from SteamLibForked/Authentication/SteamTokenHelper.cs
rename to src/SteamLibForked/Authentication/SteamTokenHelper.cs
index 7a45aec..6c8361e 100644
--- a/SteamLibForked/Authentication/SteamTokenHelper.cs
+++ b/src/SteamLibForked/Authentication/SteamTokenHelper.cs
@@ -3,9 +3,9 @@ using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using AchiesUtilities.Models;
using Microsoft.IdentityModel.JsonWebTokens;
-using SteamLib.Account;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.Core;
+using SteamLibForked.Models.Session;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Authentication;
diff --git a/SteamLibForked/Authentication/TransferSession[folder]/OAuthData.cs b/src/SteamLibForked/Authentication/TransferSession[folder]/OAuthData.cs
similarity index 100%
rename from SteamLibForked/Authentication/TransferSession[folder]/OAuthData.cs
rename to src/SteamLibForked/Authentication/TransferSession[folder]/OAuthData.cs
diff --git a/SteamLibForked/Authentication/TransferSession[folder]/TransferParameters.cs b/src/SteamLibForked/Authentication/TransferSession[folder]/TransferParameters.cs
similarity index 100%
rename from SteamLibForked/Authentication/TransferSession[folder]/TransferParameters.cs
rename to src/SteamLibForked/Authentication/TransferSession[folder]/TransferParameters.cs
diff --git a/src/SteamLibForked/Core/StatusCodes/StatusCodeContext.cs b/src/SteamLibForked/Core/StatusCodes/StatusCodeContext.cs
new file mode 100644
index 0000000..dbf81f2
--- /dev/null
+++ b/src/SteamLibForked/Core/StatusCodes/StatusCodeContext.cs
@@ -0,0 +1,6 @@
+namespace SteamLib.Core.StatusCodes;
+
+public enum StatusCodeContext
+{
+ None = 0
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs b/src/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs
new file mode 100644
index 0000000..2a11bd8
--- /dev/null
+++ b/src/SteamLibForked/Core/StatusCodes/SteamStatusCode.cs
@@ -0,0 +1,79 @@
+using AchiesUtilities.Models;
+using SteamLib.Exceptions;
+using SteamLib.ProtoCore.Enums;
+using SteamLib.Utility;
+
+namespace SteamLib.Core.StatusCodes;
+
+public partial class SteamStatusCode : Enumeration
+{
+ protected SteamStatusCode(int id, string name) : base(id, name)
+ {
+ }
+
+ ///
+ /// Tries to translate status code. If no status code was found with
+ /// will be thrown
+ ///
+ ///
+ ///
+ [Obsolete("Not recommended")]
+ public static SteamStatusCode Translate(string response)
+ {
+ int successCode;
+ try
+ {
+ successCode = Utilities.GetSuccessCode(response);
+ }
+ catch (Exception ex)
+ {
+ throw new SteamStatusCodeException(Undefined, ex);
+ }
+
+ return Translate(successCode);
+ }
+
+ public static SteamStatusCode Translate(int statusCode)
+ {
+ var fromId = FromId(statusCode);
+ if (fromId != null)
+ {
+ return fromId;
+ }
+
+ return new SteamStatusCode(statusCode, nameof(Unknown));
+ }
+
+
+ ///
+ [Obsolete("Not recommended")]
+ public static void ValidateSuccessOrThrow(string response)
+ {
+ var translated = Translate(response);
+ if (translated.Id != 1)
+ throw new SteamStatusCodeException(translated);
+ }
+
+ ///
+ public static void ValidateSuccessOrThrow(int statusCode, StatusCodeContext context = StatusCodeContext.None)
+ {
+ if (statusCode == 1) return;
+ var translated = Translate(statusCode);
+ throw new SteamStatusCodeException(translated)
+ {
+ Context = context
+ };
+ }
+
+ public static SteamStatusCode FromEResult(EResult result)
+ {
+ var r = (int) result;
+ var fromId = FromId(r);
+ return fromId ?? new SteamStatusCode(r, "Unknown");
+ }
+
+ public override string ToString()
+ {
+ return $"{Name} ({Id})";
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs b/src/SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs
similarity index 99%
rename from SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs
rename to src/SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs
index d458edb..ceb1d3d 100644
--- a/SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs
+++ b/src/SteamLibForked/Core/StatusCodes/SteamStatusCode_Codes.cs
@@ -1,7 +1,10 @@
// ReSharper disable InconsistentNaming
+using JetBrains.Annotations;
+
namespace SteamLib.Core.StatusCodes;
+[PublicAPI]
public partial class SteamStatusCode //Codes
{
///
diff --git a/SteamLibForked/Core/SteamConstants.cs b/src/SteamLibForked/Core/SteamConstants.cs
similarity index 53%
rename from SteamLibForked/Core/SteamConstants.cs
rename to src/SteamLibForked/Core/SteamConstants.cs
index 57782a5..dc26e28 100644
--- a/SteamLibForked/Core/SteamConstants.cs
+++ b/src/SteamLibForked/Core/SteamConstants.cs
@@ -10,20 +10,23 @@ public static class SteamConstants
#region Base
- public const string STEAM_STORE = "https://store.steampowered.com/";
- public const string STEAM_COMMUNITY = "https://steamcommunity.com/";
- public const string STEAM_API = "https://api.steampowered.com/";
- public const string STEAM_HELP = "https://help.steampowered.com/";
- public const string STEAM_TV = "https://steam.tv/";
- public const string STEAM_CHECKOUT = "https://checkout.steampowered.com/";
- public const string LOGIN_STEAM = "https://login.steampowered.com/";
+ public const string STEAM_STORE = "https://store.steampowered.com";
+ public const string STEAM_COMMUNITY = "https://steamcommunity.com";
+ public const string STEAM_API = "https://api.steampowered.com";
+ public const string STEAM_HELP = "https://help.steampowered.com";
+ public const string STEAM_TV = "https://steam.tv";
+ public const string STEAM_CHECKOUT = "https://checkout.steampowered.com";
+ public const string STEAM_LOGIN = "https://login.steampowered.com";
+ public const string STEAM_AVATARS_CDN = "https://avatars.fastly.steamstatic.com";
#endregion
+
#region Endpoints
- public const string STEAM_MARKET = STEAM_COMMUNITY + "market/";
- public const string STORE_API = STEAM_STORE + "api/";
+ public const string STEAM_MARKET = STEAM_COMMUNITY + "/market/";
+ public const string STORE_API = STEAM_STORE + "/api/";
+ public const string TRADEOFFER_ENDPOINT = STEAM_COMMUNITY + "/tradeoffer";
#endregion
}
\ No newline at end of file
diff --git a/SteamLibForked/Core/SteamDomains.cs b/src/SteamLibForked/Core/SteamDomains.cs
similarity index 75%
rename from SteamLibForked/Core/SteamDomains.cs
rename to src/SteamLibForked/Core/SteamDomains.cs
index d42e4f6..a74737c 100644
--- a/SteamLibForked/Core/SteamDomains.cs
+++ b/src/SteamLibForked/Core/SteamDomains.cs
@@ -1,13 +1,10 @@
using System.Collections.ObjectModel;
-using SteamLib.Core.Enums;
-using SteamLib.Exceptions;
+using SteamLibForked.Models.Core;
namespace SteamLib.Core;
public static class SteamDomains
{
- public static readonly Uri LoginSteamDomain = new(SteamConstants.LOGIN_STEAM);
-
public static IReadOnlyDictionary Domains { get; } =
new ReadOnlyDictionary(
new Dictionary
@@ -16,7 +13,9 @@ public static class SteamDomains
{SteamDomain.Store, SteamConstants.STEAM_STORE},
{SteamDomain.Help, SteamConstants.STEAM_HELP},
{SteamDomain.TV, SteamConstants.STEAM_TV},
- {SteamDomain.Checkout, SteamConstants.STEAM_CHECKOUT}
+ {SteamDomain.Checkout, SteamConstants.STEAM_CHECKOUT},
+ {SteamDomain.Login, SteamConstants.STEAM_LOGIN},
+ {SteamDomain.API, SteamConstants.STEAM_API}
});
public static IReadOnlyDictionary DomainUris { get; }
@@ -25,14 +24,26 @@ public static class SteamDomains
);
- public static SteamDomain[] AllDomains => new[]
- {
+ public static IEnumerable AllDomains { get; } =
+ [
+ SteamDomain.Community,
+ SteamDomain.Store,
+ SteamDomain.Help,
+ SteamDomain.TV,
+ SteamDomain.Checkout,
+ SteamDomain.Login,
+ SteamDomain.API
+ ];
+
+ public static IEnumerable AuthDomains { get; } =
+ [
SteamDomain.Community,
SteamDomain.Store,
SteamDomain.Help,
SteamDomain.TV,
SteamDomain.Checkout
- };
+ ];
+
public static Uri GetDomainUri(SteamDomain domain)
{
@@ -48,7 +59,7 @@ public static class SteamDomains
return result;
}
- throw UnknownSteamDomainException.Create(domain);
+ throw new ArgumentOutOfRangeException(nameof(domain), domain, "Unknown steam domain");
}
public static string GetDomain(SteamDomain domain)
@@ -62,7 +73,7 @@ public static class SteamDomains
{
var uri = new Uri(domain);
var found = DomainUris.FirstOrDefault(x => x.Value.Host == uri.Host);
- if (found.Value == default)
+ if (found.Value == null)
{
result = SteamDomain.Undefined;
return false;
diff --git a/SteamLibForked/Core/HealthMonitor.cs b/src/SteamLibForked/Core/SteamLibErrorMonitor.cs
similarity index 100%
rename from SteamLibForked/Core/HealthMonitor.cs
rename to src/SteamLibForked/Core/SteamLibErrorMonitor.cs
diff --git a/src/SteamLibForked/Exceptions/Authorization/LoginException.cs b/src/SteamLibForked/Exceptions/Authorization/LoginException.cs
new file mode 100644
index 0000000..556d0c0
--- /dev/null
+++ b/src/SteamLibForked/Exceptions/Authorization/LoginException.cs
@@ -0,0 +1,50 @@
+using SteamLib.ProtoCore.Enums;
+
+namespace SteamLibForked.Exceptions.Authorization;
+
+public class LoginException : Exception
+{
+ public LoginError Error { get; }
+ public string? Response { get; }
+
+ public LoginException(LoginError error, Exception? inner = null)
+ : base($"Login was unsuccessful. Error {error}", inner)
+ {
+ Error = error;
+ }
+
+ public LoginException(string response)
+ {
+ Error = LoginError.UndefinedError;
+ Response = response;
+ }
+
+ public LoginException(string? response, string? message, LoginError? error, Exception? innerException) : base(
+ message, innerException)
+ {
+ Response = response;
+ Error = error ?? LoginError.UndefinedError;
+ }
+}
+
+public enum LoginError
+{
+ ///
+ /// Some error occurred while trying to log in.
+ ///
+ UndefinedError = 0,
+ [Obsolete] CaptchaRequired = 1,
+ InvalidCredentials = 2,
+ InvalidEmailAuthCode = 3,
+ InvalidTwoFactorCode = 4,
+
+ ///
+ /// The shared secret is invalid when trying to confirm for
+ ///
+ InvalidSharedSecret = 7,
+
+ ///
+ /// Auth provider didn't update session properly and polling failed.
+ ///
+ SessionPollingFailed = 8
+}
\ No newline at end of file
diff --git a/SteamLibForked/Exceptions/SessionExpiredException.cs b/src/SteamLibForked/Exceptions/Authorization/SessionExpiredException.cs
similarity index 93%
rename from SteamLibForked/Exceptions/SessionExpiredException.cs
rename to src/SteamLibForked/Exceptions/Authorization/SessionExpiredException.cs
index 2699f17..5ff8f0f 100644
--- a/SteamLibForked/Exceptions/SessionExpiredException.cs
+++ b/src/SteamLibForked/Exceptions/Authorization/SessionExpiredException.cs
@@ -1,4 +1,4 @@
-namespace SteamLib.Exceptions;
+namespace SteamLib.Exceptions.Authorization;
///
/// Unlike , this exception indicates a definite session expiration. Refreshing
diff --git a/SteamLibForked/Exceptions/SessionInvalidException.cs b/src/SteamLibForked/Exceptions/Authorization/SessionInvalidException.cs
similarity index 73%
rename from SteamLibForked/Exceptions/SessionInvalidException.cs
rename to src/SteamLibForked/Exceptions/Authorization/SessionInvalidException.cs
index 62a6a76..97b3f1b 100644
--- a/SteamLibForked/Exceptions/SessionInvalidException.cs
+++ b/src/SteamLibForked/Exceptions/Authorization/SessionInvalidException.cs
@@ -1,10 +1,13 @@
-namespace SteamLib.Exceptions;
+namespace SteamLib.Exceptions.Authorization;
public class SessionInvalidException : Exception
{
public const string SESSION_NULL_MSG = "Session is null. SteamClient must be logged in before proceeding.";
public const string GOT_401_MSG = "Steam indicates the session is invalid. Received a 401 Unauthorized response.";
+ public const string HEADER_NO_STEAMID =
+ "Header doesn't contain SteamId (== false). It indicated account is not logged in";
+
public SessionInvalidException()
{
}
diff --git a/src/SteamLibForked/Exceptions/Authorization/UnsupportedAuthTypeException.cs b/src/SteamLibForked/Exceptions/Authorization/UnsupportedAuthTypeException.cs
new file mode 100644
index 0000000..c28131d
--- /dev/null
+++ b/src/SteamLibForked/Exceptions/Authorization/UnsupportedAuthTypeException.cs
@@ -0,0 +1,20 @@
+using SteamLib.ProtoCore.Enums;
+
+namespace SteamLib.Exceptions.Authorization;
+
+public class UnsupportedAuthTypeException : Exception
+{
+ public EAuthSessionGuardType[] AllowedGuardTypes { get; }
+
+ public UnsupportedAuthTypeException(EAuthSessionGuardType[] allowedGuardTypes)
+ : base($"No provider found for required guard types. Allowed types: {string.Join(", ", allowedGuardTypes)}")
+ {
+ AllowedGuardTypes = allowedGuardTypes;
+ }
+
+ public UnsupportedAuthTypeException(string message, EAuthSessionGuardType[] allowedGuardTypes)
+ : base(message)
+ {
+ AllowedGuardTypes = allowedGuardTypes;
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/Exceptions/CantLoadConfirmationsException.cs b/src/SteamLibForked/Exceptions/CantLoadConfirmationsException.cs
similarity index 100%
rename from SteamLibForked/Exceptions/CantLoadConfirmationsException.cs
rename to src/SteamLibForked/Exceptions/CantLoadConfirmationsException.cs
diff --git a/SteamLibForked/Exceptions/General/UnsupportedResponseException.cs b/src/SteamLibForked/Exceptions/General/UnsupportedResponseException.cs
similarity index 100%
rename from SteamLibForked/Exceptions/General/UnsupportedResponseException.cs
rename to src/SteamLibForked/Exceptions/General/UnsupportedResponseException.cs
diff --git a/SteamLibForked/Exceptions/Mobile/AuthenticatorLinkerException.cs b/src/SteamLibForked/Exceptions/Mobile/AuthenticatorLinkerException.cs
similarity index 100%
rename from SteamLibForked/Exceptions/Mobile/AuthenticatorLinkerException.cs
rename to src/SteamLibForked/Exceptions/Mobile/AuthenticatorLinkerException.cs
diff --git a/SteamLibForked/Exceptions/Mobile/BadMobileCookiesException.cs b/src/SteamLibForked/Exceptions/Mobile/BadMobileCookiesException.cs
similarity index 100%
rename from SteamLibForked/Exceptions/Mobile/BadMobileCookiesException.cs
rename to src/SteamLibForked/Exceptions/Mobile/BadMobileCookiesException.cs
diff --git a/src/SteamLibForked/Exceptions/SteamStatusCodeException.cs b/src/SteamLibForked/Exceptions/SteamStatusCodeException.cs
new file mode 100644
index 0000000..ce88339
--- /dev/null
+++ b/src/SteamLibForked/Exceptions/SteamStatusCodeException.cs
@@ -0,0 +1,22 @@
+using SteamLib.Core.StatusCodes;
+
+namespace SteamLib.Exceptions;
+
+public class SteamStatusCodeException : Exception
+{
+ public SteamStatusCode StatusCode { get; }
+ public StatusCodeContext Context { get; init; } = StatusCodeContext.None;
+ public bool IsUnknownOrUndefined => StatusCode.Id == 0 || StatusCode.Name.Equals(nameof(SteamStatusCode.Unknown));
+
+ public SteamStatusCodeException(SteamStatusCode statusCode, Exception? innerException = null)
+ : base($"Steam returned not successful status code {statusCode}", innerException)
+ {
+ StatusCode = statusCode;
+ }
+
+ public SteamStatusCodeException(SteamStatusCode statusCode, string? message, Exception? innerException = null)
+ : base(message, innerException)
+ {
+ StatusCode = statusCode;
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/Exceptions/UnknownSteamDomainException.cs b/src/SteamLibForked/Exceptions/UnknownSteamDomainException.cs
similarity index 100%
rename from SteamLibForked/Exceptions/UnknownSteamDomainException.cs
rename to src/SteamLibForked/Exceptions/UnknownSteamDomainException.cs
diff --git a/src/SteamLibForked/Factory/Helpers/DeviceDetailsDefaultBuilder.cs b/src/SteamLibForked/Factory/Helpers/DeviceDetailsDefaultBuilder.cs
new file mode 100644
index 0000000..e3113f4
--- /dev/null
+++ b/src/SteamLibForked/Factory/Helpers/DeviceDetailsDefaultBuilder.cs
@@ -0,0 +1,30 @@
+using SteamLib.ProtoCore.Enums;
+using SteamLib.ProtoCore.Services;
+using SteamLib.Utility;
+
+namespace SteamLib.Factory.Helpers;
+
+public static class DeviceDetailsDefaultBuilder
+{
+ [Obsolete("Not recommended")]
+ public static DeviceDetails CreateDefault(string? deviceFriendlyName)
+ {
+ return new DeviceDetails(deviceFriendlyName ?? string.Empty, EAuthTokenPlatformType.WebBrowser, (int?) null,
+ null);
+ }
+
+ public static DeviceDetails CreateCommunityDetails(string userAgent)
+ {
+ return new DeviceDetails(userAgent, EAuthTokenPlatformType.WebBrowser, (int?) null, null);
+ }
+
+ public static DeviceDetails CreateMobileDetails(string deviceName)
+ {
+ return new DeviceDetails(deviceName, EAuthTokenPlatformType.MobileApp, EOSType.AndroidUnknown, 528);
+ }
+
+ public static DeviceDetails GetMobileDefaultDevice()
+ {
+ return new DeviceDetails("Pixel 6 Pro", EAuthTokenPlatformType.MobileApp, -500, 528);
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/MobileSteamClient/MobileData.cs b/src/SteamLibForked/MobileSteamClient/MobileData.cs
similarity index 96%
rename from SteamLibForked/MobileSteamClient/MobileData.cs
rename to src/SteamLibForked/MobileSteamClient/MobileData.cs
index b07a600..5e074f4 100644
--- a/SteamLibForked/MobileSteamClient/MobileData.cs
+++ b/src/SteamLibForked/MobileSteamClient/MobileData.cs
@@ -1,7 +1,6 @@
using Newtonsoft.Json;
-using SteamLib.Account;
-using SteamLib.Core.Models;
using SteamLib.Web.Converters;
+using SteamLibForked.Models.Session;
namespace SteamLib;
diff --git a/SteamLibForked/Account/MobileSessionData.cs b/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
similarity index 93%
rename from SteamLibForked/Account/MobileSessionData.cs
rename to src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
index d8ca32f..5c228fc 100644
--- a/SteamLibForked/Account/MobileSessionData.cs
+++ b/src/SteamLibForked/Models/Core/Session/MobileSessionData.cs
@@ -1,10 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
-using SteamLib.Core.Models;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Core;
-namespace SteamLib.Account;
+namespace SteamLibForked.Models.Session;
//WARNING: Any changes here should be reflected in MafileSerializer.cs
diff --git a/SteamLibForked/Account/SessionData.cs b/src/SteamLibForked/Models/Core/Session/SessionData.cs
similarity index 89%
rename from SteamLibForked/Account/SessionData.cs
rename to src/SteamLibForked/Models/Core/Session/SessionData.cs
index 9446365..26d44f5 100644
--- a/SteamLibForked/Account/SessionData.cs
+++ b/src/SteamLibForked/Models/Core/Session/SessionData.cs
@@ -1,15 +1,17 @@
using System.Collections.Concurrent;
using Newtonsoft.Json;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
-using SteamLib.Core.Models;
using SteamLib.Web.Converters;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Core;
-namespace SteamLib.Account;
+namespace SteamLibForked.Models.Session;
public class SessionData : ISessionData
{
- [JsonIgnore] public bool? IsValid { get; set; }
+ [JsonIgnore]
+ [Obsolete("Will be removed in V2")]
+ public bool? IsValid { get; set; }
+
[JsonIgnore] public bool IsExpired => RefreshToken.IsExpired;
public string SessionId { get; }
@@ -37,7 +39,7 @@ public class SessionData : ISessionData
SessionId = sessionId;
SteamId = steamId;
RefreshToken = refreshToken;
- tokensCollection ??= Array.Empty();
+ tokensCollection ??= [];
Tokens = new ConcurrentDictionary(
tokensCollection.ToDictionary(t => t.Domain, t => t));
}
diff --git a/SteamLibForked/Core/Enums/SteamAccessTokenType.cs b/src/SteamLibForked/Models/Core/Session/SteamAccessTokenType.cs
similarity index 94%
rename from SteamLibForked/Core/Enums/SteamAccessTokenType.cs
rename to src/SteamLibForked/Models/Core/Session/SteamAccessTokenType.cs
index 7078814..5476559 100644
--- a/SteamLibForked/Core/Enums/SteamAccessTokenType.cs
+++ b/src/SteamLibForked/Models/Core/Session/SteamAccessTokenType.cs
@@ -1,6 +1,6 @@
using SteamLib.Api.Mobile;
-namespace SteamLib.Core.Enums;
+namespace SteamLibForked.Models.Session;
public enum SteamAccessTokenType
{
diff --git a/SteamLibForked/Account/SteamAuthToken.cs b/src/SteamLibForked/Models/Core/Session/SteamAuthToken.cs
similarity index 94%
rename from SteamLibForked/Account/SteamAuthToken.cs
rename to src/SteamLibForked/Models/Core/Session/SteamAuthToken.cs
index 549a56e..01edbde 100644
--- a/SteamLibForked/Account/SteamAuthToken.cs
+++ b/src/SteamLibForked/Models/Core/Session/SteamAuthToken.cs
@@ -2,11 +2,10 @@
using AchiesUtilities.Newtonsoft.JSON.Converters.Special;
using Newtonsoft.Json;
using SteamLib.Authentication;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Models;
using SteamLib.Web.Converters;
+using SteamLibForked.Models.Core;
-namespace SteamLib.Account;
+namespace SteamLibForked.Models.Session;
public readonly struct SteamAuthToken
{
diff --git a/src/SteamLibForked/Models/Core/SteamDomain.cs b/src/SteamLibForked/Models/Core/SteamDomain.cs
new file mode 100644
index 0000000..b9c58f5
--- /dev/null
+++ b/src/SteamLibForked/Models/Core/SteamDomain.cs
@@ -0,0 +1,14 @@
+namespace SteamLibForked.Models.Core;
+
+// ReSharper disable once InconsistentNaming
+public enum SteamDomain
+{
+ Undefined = 0,
+ Community = 1,
+ Store = 2,
+ Help = 3,
+ TV = 4,
+ Checkout = 5,
+ Login = 6,
+ API = 7
+}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Models/SteamId.cs b/src/SteamLibForked/Models/Core/SteamId.cs
similarity index 57%
rename from SteamLibForked/Core/Models/SteamId.cs
rename to src/SteamLibForked/Models/Core/SteamId.cs
index 60dead7..3559792 100644
--- a/SteamLibForked/Core/Models/SteamId.cs
+++ b/src/SteamLibForked/Models/Core/SteamId.cs
@@ -1,6 +1,5 @@
using SteamLib.Utility;
-
-namespace SteamLib.Core.Models;
+using SteamLibForked.Models.SteamIds;
public readonly struct SteamId : IEquatable //TODO: validation in parse methods (in siblings also)
{
@@ -8,6 +7,14 @@ public readonly struct SteamId : IEquatable //TODO: validation in parse
public SteamId2 Steam2 { get; }
public SteamId3 Steam3 { get; }
+
+ public SteamId(SteamId64 steam64, SteamId2 steam2, SteamId3 steam3)
+ {
+ Steam64 = steam64;
+ Steam2 = steam2;
+ Steam3 = steam3;
+ }
+
public SteamId(SteamId64 steam64, char type = 'U', short universe = 0)
{
Steam64 = steam64;
@@ -34,6 +41,21 @@ public readonly struct SteamId : IEquatable //TODO: validation in parse
return new SteamId(new SteamId64(steam64), type, universe);
}
+ public static SteamId FromSteam64(ulong steam64, char type = 'U', short universe = 0)
+ {
+ return new SteamId(new SteamId64((long) steam64), type, universe);
+ }
+
+ public static SteamId FromSteam2(byte lowestBit, int highestBit, byte universe = 0, char type = 'U')
+ {
+ return new SteamId(new SteamId2(lowestBit, highestBit), type);
+ }
+
+ public static SteamId FromSteam3(int steam3, char type = 'U')
+ {
+ return new SteamId(new SteamId3(steam3, type));
+ }
+
public override string ToString()
{
return Steam64.ToString();
@@ -74,4 +96,34 @@ public readonly struct SteamId : IEquatable //TODO: validation in parse
{
return Steam64.GetHashCode();
}
+
+ public static implicit operator SteamId(SteamId64 steamId64)
+ {
+ return new SteamId(steamId64);
+ }
+
+ public static implicit operator SteamId(SteamId2 steamId2)
+ {
+ return new SteamId(steamId2);
+ }
+
+ public static implicit operator SteamId(SteamId3 steamId3)
+ {
+ return new SteamId(steamId3);
+ }
+
+ public static implicit operator SteamId64(SteamId steamId)
+ {
+ return steamId.Steam64;
+ }
+
+ public static implicit operator SteamId2(SteamId steamId)
+ {
+ return steamId.Steam2;
+ }
+
+ public static implicit operator SteamId3(SteamId steamId)
+ {
+ return steamId.Steam3;
+ }
}
\ No newline at end of file
diff --git a/SteamLibForked/Core/Models/SteamIds/SteamId2.cs b/src/SteamLibForked/Models/Core/SteamIds/SteamId2.cs
similarity index 98%
rename from SteamLibForked/Core/Models/SteamIds/SteamId2.cs
rename to src/SteamLibForked/Models/Core/SteamIds/SteamId2.cs
index 5a44622..d6656bb 100644
--- a/SteamLibForked/Core/Models/SteamIds/SteamId2.cs
+++ b/src/SteamLibForked/Models/Core/SteamIds/SteamId2.cs
@@ -1,6 +1,6 @@
using SteamLib.Utility;
-namespace SteamLib.Core.Models;
+namespace SteamLibForked.Models.SteamIds;
public readonly struct SteamId2 : IEquatable
{
diff --git a/SteamLibForked/Core/Models/SteamIds/SteamId3.cs b/src/SteamLibForked/Models/Core/SteamIds/SteamId3.cs
similarity index 97%
rename from SteamLibForked/Core/Models/SteamIds/SteamId3.cs
rename to src/SteamLibForked/Models/Core/SteamIds/SteamId3.cs
index cd5604a..54d4c77 100644
--- a/SteamLibForked/Core/Models/SteamIds/SteamId3.cs
+++ b/src/SteamLibForked/Models/Core/SteamIds/SteamId3.cs
@@ -1,6 +1,6 @@
using SteamLib.Utility;
-namespace SteamLib.Core.Models;
+namespace SteamLibForked.Models.SteamIds;
public readonly struct SteamId3 : IEquatable
{
diff --git a/SteamLibForked/Core/Models/SteamIds/SteamId64.cs b/src/SteamLibForked/Models/Core/SteamIds/SteamId64.cs
similarity index 98%
rename from SteamLibForked/Core/Models/SteamIds/SteamId64.cs
rename to src/SteamLibForked/Models/Core/SteamIds/SteamId64.cs
index bd0a77e..b9a72ff 100644
--- a/SteamLibForked/Core/Models/SteamIds/SteamId64.cs
+++ b/src/SteamLibForked/Models/Core/SteamIds/SteamId64.cs
@@ -1,6 +1,6 @@
using SteamLib.Utility;
-namespace SteamLib.Core.Models;
+namespace SteamLibForked.Models.SteamIds;
public readonly struct SteamId64 : IEquatable
{
diff --git a/src/SteamLibForked/Models/Native/Account/WebTradeEligibility.cs b/src/SteamLibForked/Models/Native/Account/WebTradeEligibility.cs
new file mode 100644
index 0000000..418f4cb
--- /dev/null
+++ b/src/SteamLibForked/Models/Native/Account/WebTradeEligibility.cs
@@ -0,0 +1,33 @@
+using AchiesUtilities.Models;
+using AchiesUtilities.Newtonsoft.JSON.Converters.Special;
+using Newtonsoft.Json;
+
+namespace SteamLib.Models.Account;
+
+public class WebTradeEligibility
+{
+ [JsonProperty("allowed")] public int Allowed { get; set; }
+
+ ///
+ /// 16416 - SteamGuard
+ /// 16672 - Password reset
+ ///
+ [JsonProperty("reason")]
+ public int Reason { get; set; }
+
+ [JsonProperty("allowed_at_time")] public long AllowedAtTime { get; set; }
+
+ [JsonProperty("steamguard_required_days")]
+ public int SteamGuardRequiredDays { get; set; }
+
+ [JsonProperty("new_device_cooldown_days")]
+ public int NewDeviceCooldownDays { get; set; }
+
+ [JsonProperty("expiration")]
+ [JsonConverter(typeof(UnixTimeStampConverter))]
+ public UnixTimeStamp Expiration { get; set; }
+
+ [JsonProperty("time_checked")]
+ [JsonConverter(typeof(UnixTimeStampConverter))]
+ public UnixTimeStamp TimeChecked { get; set; }
+}
\ No newline at end of file
diff --git a/src/SteamLibForked/Models/ScriptHeaderModel.cs b/src/SteamLibForked/Models/ScriptHeaderModel.cs
new file mode 100644
index 0000000..d5ff793
--- /dev/null
+++ b/src/SteamLibForked/Models/ScriptHeaderModel.cs
@@ -0,0 +1,7 @@
+namespace SteamLib.Models;
+
+public class ScriptHeaderModel
+{
+ public required string SessionId { get; set; }
+ public SteamId? SteamId { get; set; }
+}
\ No newline at end of file
diff --git a/SteamLibForked/ProtoCore/Enums/EAuthSessionGuardType.cs b/src/SteamLibForked/ProtoCore/Enums/EAuthSessionGuardType.cs
similarity index 100%
rename from SteamLibForked/ProtoCore/Enums/EAuthSessionGuardType.cs
rename to src/SteamLibForked/ProtoCore/Enums/EAuthSessionGuardType.cs
diff --git a/SteamLibForked/ProtoCore/Enums/EAuthTokenPlatformType.cs b/src/SteamLibForked/ProtoCore/Enums/EAuthTokenPlatformType.cs
similarity index 100%
rename from SteamLibForked/ProtoCore/Enums/EAuthTokenPlatformType.cs
rename to src/SteamLibForked/ProtoCore/Enums/EAuthTokenPlatformType.cs
diff --git a/SteamLibForked/ProtoCore/Enums/EResult.cs b/src/SteamLibForked/ProtoCore/Enums/EResult.cs
similarity index 98%
rename from SteamLibForked/ProtoCore/Enums/EResult.cs
rename to src/SteamLibForked/ProtoCore/Enums/EResult.cs
index d9e8a2f..cf50587 100644
--- a/SteamLibForked/ProtoCore/Enums/EResult.cs
+++ b/src/SteamLibForked/ProtoCore/Enums/EResult.cs
@@ -1,11 +1,8 @@
// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
-using JetBrains.Annotations;
-
namespace SteamLib.ProtoCore.Enums;
-[PublicAPI]
public enum EResult
{
Invalid = 0,
diff --git a/SteamLibForked/ProtoCore/Interfaces/IProtoMsg.cs b/src/SteamLibForked/ProtoCore/Interfaces/IProtoMsg.cs
similarity index 100%
rename from SteamLibForked/ProtoCore/Interfaces/IProtoMsg.cs
rename to src/SteamLibForked/ProtoCore/Interfaces/IProtoMsg.cs
diff --git a/SteamLibForked/ProtoCore/ProtoHelpers.cs b/src/SteamLibForked/ProtoCore/ProtoHelpers.cs
similarity index 83%
rename from SteamLibForked/ProtoCore/ProtoHelpers.cs
rename to src/SteamLibForked/ProtoCore/ProtoHelpers.cs
index 93f488b..f0e9623 100644
--- a/SteamLibForked/ProtoCore/ProtoHelpers.cs
+++ b/src/SteamLibForked/ProtoCore/ProtoHelpers.cs
@@ -1,7 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using ProtoBuf;
using SteamLib.ProtoCore.Enums;
-using SteamLib.ProtoCore.Exceptions;
using SteamLib.ProtoCore.Interfaces;
namespace SteamLib.ProtoCore;
@@ -26,10 +25,6 @@ public static class ProtoHelpers
if (response.Headers.TryGetValues("x-eresult", out var val))
{
var eResultInt = Convert.ToInt32(val.Single());
-
- if (Enum.IsDefined(typeof(EResult), eResultInt) == false)
- throw new UnknownEResultException(eResultInt);
-
return (EResult) eResultInt;
}
diff --git a/SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs b/src/SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs
similarity index 96%
rename from SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs
rename to src/SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs
index b6f94cc..80eaded 100644
--- a/SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs
+++ b/src/SteamLibForked/ProtoCore/ProtoHttpClientExtension.cs
@@ -1,5 +1,6 @@
-using SteamLib.ProtoCore.Enums;
-using SteamLib.ProtoCore.Exceptions;
+using SteamLib.Core.StatusCodes;
+using SteamLib.Exceptions;
+using SteamLib.ProtoCore.Enums;
using SteamLib.ProtoCore.Interfaces;
namespace SteamLib.ProtoCore;
@@ -66,7 +67,7 @@ public static class ProtoHttpClientExtension
{
if (eResult != EResult.OK)
{
- throw new EResultException(eResult);
+ throw new SteamStatusCodeException(SteamStatusCode.FromEResult(eResult));
}
}
@@ -75,13 +76,13 @@ public static class ProtoHttpClientExtension
///
///
///
- ///
+ ///
///
public static T GetResponseEnsureSuccess(this ProtoResponse response) where T : class, IProtoMsg
{
if (response.Result != EResult.OK)
{
- throw new EResultException(response.Result);
+ throw new SteamStatusCodeException(SteamStatusCode.FromEResult(response.Result));
}
return response.GetResponse();
diff --git a/SteamLibForked/ProtoCore/ProtoResponse.cs b/src/SteamLibForked/ProtoCore/ProtoResponse.cs
similarity index 100%
rename from SteamLibForked/ProtoCore/ProtoResponse.cs
rename to src/SteamLibForked/ProtoCore/ProtoResponse.cs
diff --git a/SteamLibForked/ProtoCore/Services/AuthenticationService.cs b/src/SteamLibForked/ProtoCore/Services/AuthenticationService.cs
similarity index 100%
rename from SteamLibForked/ProtoCore/Services/AuthenticationService.cs
rename to src/SteamLibForked/ProtoCore/Services/AuthenticationService.cs
diff --git a/SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs b/src/SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs
similarity index 67%
rename from SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs
rename to src/SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs
index fb68cba..a1db437 100644
--- a/SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs
+++ b/src/SteamLibForked/ProtoCore/Services/AuthenticatorLinkerService.cs
@@ -1,6 +1,6 @@
using ProtoBuf;
-using SteamLib.Account;
using SteamLib.ProtoCore.Interfaces;
+using SteamLibForked.Models.Session;
// ReSharper disable InconsistentNaming
@@ -132,4 +132,55 @@ public class RemoveAuthenticator_Response : IProtoMsg
{
[ProtoMember(1)] public bool Success { get; set; }
[ProtoMember(5)] public int RevocationAttemptsRemaining { get; set; }
+}
+
+[ProtoContract]
+public class RemoveAuthenticatorViaChallengeContinue_Request : IProtoMsg
+{
+ [ProtoMember(1)] public string SmsCode { get; set; }
+ [ProtoMember(2)] public bool GenerateNewToken { get; set; }
+ [ProtoMember(3)] public uint Version { get; set; }
+}
+
+[ProtoContract]
+public class RemoveAuthenticatorViaChallengeContinue_Replacement_Token : IProtoMsg
+{
+ [ProtoMember(1)] public byte[] SharedSecret { get; set; }
+ [ProtoMember(2)] public ulong SerialNumber { get; set; }
+ [ProtoMember(3)] public string RevocationCode { get; set; }
+ [ProtoMember(4)] public string Uri { get; set; }
+ [ProtoMember(5)] public long ServerTime { get; set; }
+ [ProtoMember(6)] public string AccountName { get; set; }
+ [ProtoMember(7)] public string TokenGid { get; set; }
+ [ProtoMember(8)] public byte[] IdentitySecret { get; set; }
+ [ProtoMember(9)] public byte[] Secret1 { get; set; }
+ [ProtoMember(10)] public int Status { get; set; }
+ [ProtoMember(11)] public uint SteamGuardScheme { get; set; }
+ [ProtoMember(12)] public ulong SteamId { get; set; }
+
+ public MobileDataExtended ToMobileDataExtended(string deviceId, MobileSessionData? sessionData)
+ {
+ return new MobileDataExtended
+ {
+ SharedSecret = Convert.ToBase64String(SharedSecret),
+ SerialNumber = SerialNumber,
+ RevocationCode = RevocationCode,
+ Uri = Uri,
+ ServerTime = ServerTime,
+ AccountName = AccountName,
+ TokenGid = TokenGid,
+ IdentitySecret = Convert.ToBase64String(IdentitySecret),
+ Secret1 = Convert.ToBase64String(Secret1),
+ SessionData = sessionData,
+ DeviceId = deviceId,
+ SteamId = global::SteamId.FromSteam64(SteamId)
+ };
+ }
+}
+
+[ProtoContract]
+public class RemoveAuthenticatorViaChallengeContinue_Response : IProtoMsg
+{
+ [ProtoMember(1)] public int Success { get; set; }
+ [ProtoMember(2)] public RemoveAuthenticatorViaChallengeContinue_Replacement_Token ReplacementToken { get; set; }
}
\ No newline at end of file
diff --git a/SteamLibForked/ProtoCore/Services/EmptyMessage.cs b/src/SteamLibForked/ProtoCore/Services/EmptyMessage.cs
similarity index 72%
rename from SteamLibForked/ProtoCore/Services/EmptyMessage.cs
rename to src/SteamLibForked/ProtoCore/Services/EmptyMessage.cs
index f8281f2..285c1c3 100644
--- a/SteamLibForked/ProtoCore/Services/EmptyMessage.cs
+++ b/src/SteamLibForked/ProtoCore/Services/EmptyMessage.cs
@@ -6,4 +6,5 @@ namespace SteamLib.ProtoCore.Services;
[ProtoContract]
public class EmptyMessage : IProtoMsg
{
+ public static readonly EmptyMessage Instance = new();
}
\ No newline at end of file
diff --git a/src/SteamLibForked/SteamLibForked.csproj b/src/SteamLibForked/SteamLibForked.csproj
new file mode 100644
index 0000000..d89e75d
--- /dev/null
+++ b/src/SteamLibForked/SteamLibForked.csproj
@@ -0,0 +1,21 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/SteamLibForked/SteamLibForked.csproj.DotSettings b/src/SteamLibForked/SteamLibForked.csproj.DotSettings
new file mode 100644
index 0000000..76b75f5
--- /dev/null
+++ b/src/SteamLibForked/SteamLibForked.csproj.DotSettings
@@ -0,0 +1,10 @@
+
+ True
+ True
+ True
\ No newline at end of file
diff --git a/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/CheckPhoneResult.cs b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/CheckPhoneResult.cs
similarity index 100%
rename from SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/CheckPhoneResult.cs
rename to src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/CheckPhoneResult.cs
diff --git a/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs
similarity index 74%
rename from SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs
rename to src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs
index 3b589ca..9e309f5 100644
--- a/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs
+++ b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkOptions.cs
@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
-using SteamLib.Core.Interfaces;
+using SteamLib.Abstractions;
+using SteamLibForked.Abstractions.Linker;
namespace SteamLib.SteamMobile.AuthenticatorLinker;
@@ -9,19 +10,17 @@ public class LinkOptions
public HttpClient HttpClient { get; }
public IEmailProvider? EmailProvider { get; }
public ISmsCodeProvider? SmsCodeProvider { get; }
- public ICaptchaResolver? CaptchaResolver { get; }
public IPhoneNumberProvider? PhoneNumberProvider { get; }
public Action? BackupHandler { get; }
public ILogger? Logger { get; }
public LinkOptions(HttpClient httpClient, ILoginConsumer loginConsumer, ISmsCodeProvider? smsCodeProvider,
- ICaptchaResolver? captchaResolver, IEmailProvider? emailProvider, IPhoneNumberProvider? phoneNumberProvider,
- Action? backupHandler = null,
+ IEmailProvider? emailProvider,
+ IPhoneNumberProvider? phoneNumberProvider, Action? backupHandler = null,
ILogger? logger = null)
{
EmailProvider = emailProvider;
SmsCodeProvider = smsCodeProvider;
- CaptchaResolver = captchaResolver;
HttpClient = httpClient;
LoginConsumer = loginConsumer;
BackupHandler = backupHandler;
diff --git a/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkResult.cs b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkResult.cs
similarity index 100%
rename from SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkResult.cs
rename to src/SteamLibForked/SteamMobile/AuthenticatorLinker/Models[folder]/LinkResult.cs
diff --git a/SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs
similarity index 90%
rename from SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs
rename to src/SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs
index 68976a3..942138e 100644
--- a/SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs
+++ b/src/SteamLibForked/SteamMobile/AuthenticatorLinker/SteamAuthenticatorLinker.cs
@@ -1,17 +1,15 @@
-using JetBrains.Annotations;
-using Microsoft.Extensions.Logging;
-using SteamLib.Account;
+using Microsoft.Extensions.Logging;
+using SteamLib.Abstractions;
using SteamLib.Api.Mobile;
using SteamLib.Authentication;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Interfaces;
-using SteamLib.Exceptions;
+using SteamLib.Exceptions.Authorization;
using SteamLib.Exceptions.Mobile;
using SteamLib.ProtoCore.Enums;
+using SteamLibForked.Abstractions;
+using SteamLibForked.Models.Session;
namespace SteamLib.SteamMobile.AuthenticatorLinker;
-[PublicAPI]
public class SteamAuthenticatorLinker
{
public ILoginConsumer Consumer { get; }
@@ -90,9 +88,17 @@ public class SteamAuthenticatorLinker
if (await this.AttachPhone(phoneNumber.Value) == false)
throw new AuthenticatorLinkerException(AuthenticatorLinkerError.CantAttachPhone);
- await Options.EmailProvider!.ConfirmEmailLink(Consumer, EmailConfirmationType.AttachPhoneAuthenticator);
- if (await this.CheckEmailConfirmation() == false)
+ var emailValid = false;
+ for (var i = 0; i < Options.EmailProvider!.RetryCount; i++)
+ {
+ await Options.EmailProvider!.ConfirmEmailLink(Consumer, EmailConfirmationType.AttachPhoneAuthenticator);
+ emailValid = await this.CheckEmailConfirmation();
+ if (emailValid) break;
+ }
+
+
+ if (!emailValid)
throw new AuthenticatorLinkerException(AuthenticatorLinkerError.CantConfirmAttachingEmail);
var sendSms = await this.SendSmsCode();
@@ -126,7 +132,7 @@ public class SteamAuthenticatorLinker
throw new AuthenticatorLinkerException(AuthenticatorLinkerError.NoSmsCodeProvider);
var smsCode = await Options.SmsCodeProvider.GetSmsCode(Consumer, phoneNumber, resp.PhoneNumberHint);
- code = smsCode.ToString();
+ code = smsCode.ToString("D5");
}
else if (resp.ConfirmType == 3)
{
diff --git a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs
similarity index 61%
rename from SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs
index c7ba356..53ce210 100644
--- a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/AccountRecoveryConfirmation.cs
@@ -2,7 +2,7 @@
public class AccountRecoveryConfirmation : Confirmation
{
- public AccountRecoveryConfirmation(long id, ulong nonce, long creator, string typeName) : base(id, nonce, 6,
+ public AccountRecoveryConfirmation(long id, ulong nonce, ulong creator, string typeName) : base(id, nonce, 6,
creator, ConfirmationType.AccountRecovery, typeName)
{
}
diff --git a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs
similarity index 86%
rename from SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs
index 0c0a2f9..8d5c460 100644
--- a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/Confirmation.cs
@@ -12,7 +12,7 @@ public class Confirmation
///
/// Represents either the Trade Offer ID or market transaction ID that caused this confirmation to be created.
///
- public long CreatorId { get; }
+ public ulong CreatorId { get; }
public string TypeName { get; init; }
public string HeadLine { get; init; } = string.Empty;
@@ -31,7 +31,7 @@ public class Confirmation
///
public int IntType;
- public Confirmation(long id, ulong nonce, int intType, long creatorId, ConfirmationType confType, string typeName)
+ public Confirmation(long id, ulong nonce, int intType, ulong creatorId, ConfirmationType confType, string typeName)
{
Id = id;
Nonce = nonce;
diff --git a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs
similarity index 76%
rename from SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs
index ffea8c4..f4a607d 100644
--- a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/MarketConfirmation.cs
@@ -6,7 +6,7 @@ public class MarketConfirmation : Confirmation
public string ItemName { get; init; } = string.Empty;
public string PriceString { get; init; } = string.Empty;
- public MarketConfirmation(long id, ulong key, long creator, string typeName) : base(id, key, 3, creator,
+ public MarketConfirmation(long id, ulong key, ulong creator, string typeName) : base(id, key, 3, creator,
ConfirmationType.MarketSellTransaction, typeName)
{
}
diff --git a/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/PurchaseConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/PurchaseConfirmation.cs
new file mode 100644
index 0000000..158d1e4
--- /dev/null
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/PurchaseConfirmation.cs
@@ -0,0 +1,8 @@
+namespace SteamLib.SteamMobile.Confirmations;
+
+public class PurchaseConfirmation : Confirmation
+{
+ public PurchaseConfirmation(long id, ulong nonce, int intType, ulong creatorId, string typeName) : base(id, nonce, intType, creatorId, ConfirmationType.Purchase, typeName)
+ {
+ }
+}
\ No newline at end of file
diff --git a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs
similarity index 61%
rename from SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs
index 74457b5..6217acf 100644
--- a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/RegisterApiKeyConfirmation.cs
@@ -2,7 +2,7 @@
public class RegisterApiKeyConfirmation : Confirmation
{
- public RegisterApiKeyConfirmation(long id, ulong nonce, long creatorId, string typeName) : base(id, nonce, 8,
+ public RegisterApiKeyConfirmation(long id, ulong nonce, ulong creatorId, string typeName) : base(id, nonce, 8,
creatorId, ConfirmationType.RegisterApiKey, typeName)
{
}
diff --git a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs
similarity index 71%
rename from SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs
index 468dad2..4952022 100644
--- a/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/Concrete[folder]/TradeConfirmation.cs
@@ -7,9 +7,9 @@ public class TradeConfirmation : Confirmation
public bool IsReceiveNothing { get; set; }
public override TradeConfirmationDetails? Details { get; }
- public long TradeId => CreatorId;
+ public ulong TradeId => CreatorId;
- public TradeConfirmation(long id, ulong nonce, long creator, string typeName) : base(id, nonce, 1, creator,
+ public TradeConfirmation(long id, ulong nonce, ulong creator, string typeName) : base(id, nonce, 1, creator,
ConfirmationType.Trade, typeName)
{
}
diff --git a/SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs b/src/SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs
similarity index 79%
rename from SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs
index 4196840..09f0e92 100644
--- a/SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs
+++ b/src/SteamLibForked/SteamMobile/Confirmations/ConfirmationType.cs
@@ -6,5 +6,6 @@ public enum ConfirmationType
Trade = 2,
MarketSellTransaction = 3,
AccountRecovery = 6,
- RegisterApiKey = 9
+ RegisterApiKey = 9,
+ Purchase = 12
}
\ No newline at end of file
diff --git a/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/ConfirmationDetails.cs b/src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/ConfirmationDetails.cs
similarity index 100%
rename from SteamLibForked/SteamMobile/Confirmations/Details[Folder]/ConfirmationDetails.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/ConfirmationDetails.cs
diff --git a/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/MarketConfirmationDetails.cs b/src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/MarketConfirmationDetails.cs
similarity index 100%
rename from SteamLibForked/SteamMobile/Confirmations/Details[Folder]/MarketConfirmationDetails.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/MarketConfirmationDetails.cs
diff --git a/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/TradeDetailsConfirmation.cs b/src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/TradeDetailsConfirmation.cs
similarity index 100%
rename from SteamLibForked/SteamMobile/Confirmations/Details[Folder]/TradeDetailsConfirmation.cs
rename to src/SteamLibForked/SteamMobile/Confirmations/Details[Folder]/TradeDetailsConfirmation.cs
diff --git a/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs b/src/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs
similarity index 68%
rename from SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs
rename to src/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs
index f1088db..d0b5fef 100644
--- a/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs
+++ b/src/SteamLibForked/SteamMobile/SteamGuardCodeGenerator.cs
@@ -1,19 +1,20 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
-using SteamLib.Core.Interfaces;
+using SteamLib.Abstractions;
+using SteamLib.Api.Services;
+using SteamLib.Authentication;
+using SteamLib.ProtoCore.Enums;
+using SteamLibForked.Abstractions.Auth;
namespace SteamLib.SteamMobile;
public class SteamGuardCodeGenerator : ISteamGuardProvider
{
private static readonly byte[] SteamGuardCodeTranslations =
- {50, 51, 52, 53, 54, 55, 56, 57, 66, 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 82, 84, 86, 87, 88, 89};
+ "23456789BCDFGHJKMNPQRTVWXY"u8.ToArray();
- public string SharedSecret { get; }
-
- int ISteamGuardProvider.MaxRetryCount => ProviderMaxRetryCount;
- public int ProviderMaxRetryCount { get; set; }
+ private string SharedSecret { get; }
public SteamGuardCodeGenerator(string sharedSecret)
{
@@ -21,7 +22,7 @@ public class SteamGuardCodeGenerator : ISteamGuardProvider
}
- public ValueTask GetSteamGuardCode(ILoginConsumer caller)
+ public ValueTask GetSteamGuardCode()
{
return ValueTask.FromResult(GenerateCode());
}
@@ -73,4 +74,18 @@ public class SteamGuardCodeGenerator : ISteamGuardProvider
return Encoding.UTF8.GetString(codeArray);
}
+
+
+ public bool IsSupportedGuardType(ILoginConsumer consumer, EAuthSessionGuardType type)
+ {
+ return type == EAuthSessionGuardType.DeviceCode;
+ }
+
+ public Task UpdateAuthSession(HttpClient authClient, ILoginConsumer loginConsumer, UpdateAuthSessionModel model,
+ CancellationToken cancellationToken = default)
+ {
+ var code = GenerateCode();
+ var req = AuthRequestHelper.CreateMobileCodeRequest(code, model.ClientId, model.SteamId);
+ return AuthenticationServiceApi.UpdateAuthSessionWithSteamGuardCode(authClient, req, cancellationToken);
+ }
}
\ No newline at end of file
diff --git a/SteamLibForked/SteamMobile/TimeAligner.cs b/src/SteamLibForked/SteamMobile/TimeAligner.cs
similarity index 94%
rename from SteamLibForked/SteamMobile/TimeAligner.cs
rename to src/SteamLibForked/SteamMobile/TimeAligner.cs
index 41a95f7..802152b 100644
--- a/SteamLibForked/SteamMobile/TimeAligner.cs
+++ b/src/SteamLibForked/SteamMobile/TimeAligner.cs
@@ -1,16 +1,15 @@
using System.Diagnostics;
using AchiesUtilities.Models;
-using JetBrains.Annotations;
using Newtonsoft.Json.Linq;
using SteamLib.Core;
namespace SteamLib.SteamMobile;
//TODO: Refactor
-[PublicAPI]
+
public static class TimeAligner
{
- private const string TIME_ALIGN_ENDPOINT = "ITwoFactorService/QueryTime/v0001";
+ private const string TIME_ALIGN_ENDPOINT = "/ITwoFactorService/QueryTime/v0001";
private static bool _aligned;
private static int _timeDifference;
public static UnixTimeStamp UtcNow => UnixTimeStamp.FromDateTime(DateTime.UtcNow);
diff --git a/SteamLibForked/Utility/EncryptionHelper.cs b/src/SteamLibForked/Utility/EncryptionHelper.cs
similarity index 100%
rename from SteamLibForked/Utility/EncryptionHelper.cs
rename to src/SteamLibForked/Utility/EncryptionHelper.cs
diff --git a/SteamLibForked/Utility/EnvironmentUtility.cs b/src/SteamLibForked/Utility/EnvironmentUtility.cs
similarity index 100%
rename from SteamLibForked/Utility/EnvironmentUtility.cs
rename to src/SteamLibForked/Utility/EnvironmentUtility.cs
diff --git a/SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs b/src/SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs
similarity index 92%
rename from SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs
rename to src/SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs
index 5cfeb0c..85e2cb6 100644
--- a/SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/DeserializedMafileData.cs
@@ -1,6 +1,6 @@
-using JetBrains.Annotations;
+using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Linq;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Utility.MafileSerialization;
@@ -11,14 +11,13 @@ public enum DeserializedMafileSessionResult
Valid
}
-[PublicAPI]
public class DeserializedMafileData
{
public MobileData Data { get; init; }
public DeserializedMafileInfo Info { get; }
- private DeserializedMafileData(MobileData mobileData, DeserializedMafileInfo info)
+ protected DeserializedMafileData(MobileData mobileData, DeserializedMafileInfo info)
{
Data = mobileData;
Info = info;
@@ -45,7 +44,6 @@ public class DeserializedMafileData
///
/// Represents information about deserialized mafile
///
-[PublicAPI]
public class DeserializedMafileInfo
{
public static readonly HashSet ImportantProperties =
@@ -65,7 +63,6 @@ public class DeserializedMafileInfo
];
public int? Version { get; init; }
-
public bool IsExtended { get; init; }
public DeserializedMafileSessionResult SessionResult { get; init; }
@@ -74,9 +71,16 @@ public class DeserializedMafileInfo
public Dictionary? UnusedProperties { get; init; }
public bool IsActual => Version == MafileSerializer.MAFILE_VERSION;
+
+ [MemberNotNullWhen(true, nameof(UnusedProperties))]
public bool HasUnusedProperties => UnusedProperties is {Count: > 0};
+
+ [MemberNotNullWhen(true, nameof(MissingProperties))]
public bool HasMissingProperties => MissingProperties is {Count: > 0};
+
+ [MemberNotNullWhen(true, nameof(MissingImportantProperties))]
public bool HasMissingImportantProperties => MissingImportantProperties is {Count: > 0};
+
public bool HasSession => SessionResult == DeserializedMafileSessionResult.Valid;
public bool HasIdentificationProperty { get; init; }
public bool SteamIdValid { get; init; }
diff --git a/SteamLibForked/Utility/MafileSerialization/LegacyMafile.cs b/src/SteamLibForked/Utility/MafileSerialization/LegacyMafile.cs
similarity index 100%
rename from SteamLibForked/Utility/MafileSerialization/LegacyMafile.cs
rename to src/SteamLibForked/Utility/MafileSerialization/LegacyMafile.cs
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileCredits.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileCredits.cs
similarity index 83%
rename from SteamLibForked/Utility/MafileSerialization/MafileCredits.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileCredits.cs
index 828201f..2ea3ea1 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileCredits.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileCredits.cs
@@ -1,8 +1,5 @@
-using JetBrains.Annotations;
+namespace SteamLib.Utility.MafileSerialization;
-namespace SteamLib.Utility.MafileSerialization;
-
-[PublicAPI]
public class MafileCredits : IMafileCredits
{
private const string ORIGINAL_AUTHOR = "Achies";
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs
similarity index 98%
rename from SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs
index b4af5d2..1417c33 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer.cs
@@ -1,12 +1,10 @@
-using JetBrains.Annotations;
-using Newtonsoft.Json;
+using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
-using SteamLib.Account;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.Session;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Utility.MafileSerialization;
-[PublicAPI]
public partial class MafileSerializer
{
public const int MAFILE_VERSION = 3;
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs
similarity index 73%
rename from SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs
index 155e6d9..f17cb51 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializerSettings.cs
@@ -1,10 +1,11 @@
-namespace SteamLib.Utility.MafileSerialization;
+using Newtonsoft.Json;
+
+namespace SteamLib.Utility.MafileSerialization;
public class MafileSerializerSettings
{
public MafileDeserializationOptions DeserializationOptions { get; set; } = new();
-
- [Obsolete("Currently not used")] public MafileDeserializationOptions SerializationOptions { get; set; } = new();
+ public MafileSerializationOptions SerializationOptions { get; set; } = new();
}
public class MafileDeserializationOptions
@@ -14,7 +15,7 @@ public class MafileDeserializationOptions
///
/// Throws if the is 0 or invalid. Otherwise, SerialNumber will be set
- /// to 0.
+ /// to 0 or recovered value depending on .
///
public bool ThrowIfInvalidSerialNumber { get; set; }
@@ -31,4 +32,7 @@ public class MafileDeserializationOptions
public class MafileSerializationOptions
{
+ public MafileCredits? Credits { get; set; }
+ public bool Sign { get; set; }
+ public Formatting Formatting { get; set; }
}
\ No newline at end of file
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs
similarity index 94%
rename from SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs
index 58bb4aa..a2938ab 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_SessionData.cs
@@ -1,10 +1,9 @@
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json.Linq;
-using SteamLib.Account;
using SteamLib.Authentication;
-using SteamLib.Core.Enums;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.Session;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Utility.MafileSerialization;
@@ -42,9 +41,10 @@ public partial class MafileSerializer //SessionData
var sessionData =
new MobileSessionData(sessionId, steamId.Value, refreshToken.Value, accessToken, tokens: null);
- sessionData.IsValid = SessionDataValidator.Validate(null, sessionData).Succeeded;
- if (sessionData.IsValid == false)
+ if (!SessionDataValidator.Validate(null, sessionData).Succeeded)
+ {
return null;
+ }
return sessionData;
}
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs
similarity index 99%
rename from SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs
index 07b5ed6..fec2054 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Utility.cs
@@ -1,6 +1,6 @@
using System.Numerics;
using Newtonsoft.Json.Linq;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Utility.MafileSerialization;
diff --git a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs
similarity index 98%
rename from SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs
rename to src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs
index 1d9422f..0f966e8 100644
--- a/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Validate.cs
@@ -1,7 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json.Linq;
-using SteamLib.Account;
using SteamLib.Authentication;
+using SteamLibForked.Models.Session;
namespace SteamLib.Utility.MafileSerialization;
diff --git a/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs
new file mode 100644
index 0000000..ff2ff54
--- /dev/null
+++ b/src/SteamLibForked/Utility/MafileSerialization/MafileSerializer_Write.cs
@@ -0,0 +1,277 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace SteamLib.Utility.MafileSerialization;
+
+public partial class MafileSerializer //Write
+{
+ private const string CREDITS_PROPERTY_NAME = "Credits";
+
+ #region Instance
+
+ public string Serialize(MobileData mobileData)
+ {
+ return Serialize(mobileData, Settings.SerializationOptions);
+ }
+
+ public Task SerializeAsync(MobileData mobileData)
+ {
+ return SerializeAsync(mobileData, Settings.SerializationOptions);
+ }
+
+ public string SerializeLegacy(MobileData mobileData, IDictionary? additionalProperties = null)
+ {
+ return SerializeLegacy(mobileData, Settings.SerializationOptions, additionalProperties);
+ }
+
+ public Task SerializeLegacyAsync(MobileData mobileData,
+ IDictionary? additionalProperties = null)
+ {
+ return SerializeLegacyAsync(mobileData, Settings.SerializationOptions, additionalProperties);
+ }
+
+ #endregion
+
+ #region Default
+
+ public static string Serialize(MobileData mobileData, MafileSerializationOptions? options)
+ {
+ options ??= new MafileSerializationOptions();
+ var j = CreateJObject(mobileData, options);
+ using var w = new StringWriter();
+ using var write = new JsonTextWriter(w);
+ write.Formatting = options.Formatting;
+ j.WriteTo(write);
+ return w.ToString();
+ }
+
+
+ public static async Task SerializeAsync(MobileData mobileData, MafileSerializationOptions? options)
+ {
+ options ??= new MafileSerializationOptions();
+ var j = CreateJObject(mobileData, options);
+ await using var w = new StringWriter();
+ await using var write = new JsonTextWriter(w);
+ write.Formatting = options.Formatting;
+ await j.WriteToAsync(write);
+ return w.ToString();
+ }
+
+
+ private static JObject CreateJObject(MobileData mobileData, MafileSerializationOptions options)
+ {
+ var sign = options.Sign;
+ var credits = options.Credits;
+
+
+ var j = JObject.FromObject(mobileData);
+ j.Add(SIGNATURE_PROPERTY_NAME, j);
+ if (sign)
+ {
+ credits ??= MafileCredits.Instance;
+ var obj = JObject.FromObject(credits);
+ j.Add(CREDITS_PROPERTY_NAME, obj);
+ }
+
+ return j;
+ }
+
+ #endregion
+
+ #region Legacy
+
+ public static string SerializeLegacy(MobileData mobileData, MafileSerializationOptions? options,
+ IDictionary? additionalProperties = null)
+ {
+ options ??= new MafileSerializationOptions();
+ var j = CreateLegacyJObject(mobileData, options, additionalProperties);
+ using var w = new StringWriter();
+ using var write = new JsonTextWriter(w);
+ write.Formatting = options.Formatting;
+ j.WriteTo(write);
+ return w.ToString();
+ }
+
+ public static async Task SerializeLegacyAsync(MobileData mobileData, MafileSerializationOptions? options,
+ IDictionary? additionalProperties = null)
+ {
+ options ??= new MafileSerializationOptions();
+ var j = CreateLegacyJObject(mobileData, options, additionalProperties);
+ await using var w = new StringWriter();
+ await using var write = new JsonTextWriter(w);
+ write.Formatting = options.Formatting;
+ await j.WriteToAsync(write);
+ return w.ToString();
+ }
+
+ private static JObject CreateLegacyJObject(MobileData mobileData, MafileSerializationOptions options,
+ IDictionary? additionalProperties = null)
+ {
+ var sign = options.Sign;
+ var credits = options.Credits;
+
+ var result = new LegacyMafile
+ {
+ SharedSecret = mobileData.SharedSecret,
+ IdentitySecret = mobileData.IdentitySecret,
+ DeviceId = mobileData.DeviceId
+ };
+
+ if (mobileData is MobileDataExtended ext)
+ {
+ result.RevocationCode = ext.RevocationCode ?? string.Empty;
+ result.AccountName = ext.AccountName;
+ result.SessionData = ext.SessionData == null
+ ? null
+ : new
+ {
+ AccessToken = ext.SessionData?.MobileToken?.Token,
+ steamLoginSecure = ext.SessionData?.MobileToken?.SignedToken,
+ RefreshToken = ext.SessionData?.RefreshToken.Token,
+ SteamID = ext.SessionData?.SteamId.Steam64.Id,
+ SessionID = ext.SessionData?.SessionId
+ };
+ result.ServerTime = ext.ServerTime;
+ result.SerialNumber = ext.SerialNumber.ToString();
+ result.Uri = ext.Uri;
+ result.TokenGid = ext.TokenGid;
+ result.Secret1 = ext.Secret1;
+ result.SteamId = ext.SteamId.Steam64.Id;
+ }
+
+
+ var j = JObject.FromObject(result);
+ if (additionalProperties != null)
+ {
+ foreach (var (name, value) in additionalProperties)
+ {
+ JToken? jToken = null;
+ if (value != null)
+ {
+ jToken = JToken.FromObject(value);
+ }
+
+ j.Add(name, jToken);
+ }
+ }
+
+ if (sign)
+ {
+ credits ??= MafileCredits.Instance;
+ var obj = JObject.FromObject(credits);
+ j.Add(CREDITS_PROPERTY_NAME, obj);
+ }
+
+ return j;
+ }
+
+ #endregion
+
+ #region Obsolete
+
+ [Obsolete("Use Serialize(MobileData, MafileSerializationOptions) instead.")]
+ public static string Serialize(MobileData mobileData, Formatting formatting, bool sign = true,
+ MafileCredits? credits = null)
+ {
+ using var w = new StringWriter();
+ using var write = new JsonTextWriter(w);
+ write.Formatting = formatting;
+ var j = JObject.FromObject(mobileData);
+ j.Add(SIGNATURE_PROPERTY_NAME, MAFILE_VERSION);
+ if (sign)
+ {
+ credits ??= MafileCredits.Instance;
+ var obj = JObject.FromObject(credits);
+ j.Add(CREDITS_PROPERTY_NAME, obj);
+ }
+
+ j.WriteTo(write);
+ return w.ToString();
+ }
+
+ [Obsolete("Use SerializeAsync(MobileData, MafileSerializationOptions) instead.")]
+ public static async Task SerializeAsync(MobileData mobileData, Formatting formatting, bool sign = true,
+ MafileCredits? credits = null)
+ {
+ await using var w = new StringWriter();
+ await using var write = new JsonTextWriter(w);
+ write.Formatting = formatting;
+ var j = JObject.FromObject(mobileData);
+ j.Add(SIGNATURE_PROPERTY_NAME, j);
+ if (sign)
+ {
+ credits ??= MafileCredits.Instance;
+ var obj = JObject.FromObject(credits);
+ j.Add(CREDITS_PROPERTY_NAME, obj);
+ }
+
+
+ await j.WriteToAsync(write);
+ return w.ToString();
+ }
+
+ [Obsolete("Use SerializeLegacy(MobileData, MafileSerializationOptions, Dictionary) instead.")]
+ public static string SerializeLegacy(MobileData mobileData, Formatting formatting,
+ Dictionary? additionalProperties = null, bool sign = true, MafileCredits? credits = null)
+ {
+ var result = new LegacyMafile
+ {
+ SharedSecret = mobileData.SharedSecret,
+ IdentitySecret = mobileData.IdentitySecret,
+ DeviceId = mobileData.DeviceId
+ };
+
+ if (mobileData is MobileDataExtended ext)
+ {
+ result.RevocationCode = ext.RevocationCode ?? string.Empty;
+ result.AccountName = ext.AccountName;
+ result.SessionData = ext.SessionData == null
+ ? null
+ : new
+ {
+ AccessToken = ext.SessionData?.MobileToken?.Token,
+ steamLoginSecure = ext.SessionData?.MobileToken?.SignedToken,
+ RefreshToken = ext.SessionData?.RefreshToken.Token,
+ SteamID = ext.SessionData?.SteamId.Steam64.Id,
+ SessionID = ext.SessionData?.SessionId
+ };
+ result.ServerTime = ext.ServerTime;
+ result.SerialNumber = ext.SerialNumber.ToString();
+ result.Uri = ext.Uri;
+ result.TokenGid = ext.TokenGid;
+ result.Secret1 = ext.Secret1;
+ result.SteamId = ext.SteamId.Steam64.Id;
+ }
+
+
+ using var w = new StringWriter();
+ using var write = new JsonTextWriter(w);
+ write.Formatting = formatting;
+ var j = JObject.FromObject(result);
+ if (additionalProperties != null)
+ {
+ foreach (var (name, value) in additionalProperties)
+ {
+ JToken? jToken = null;
+ if (value != null)
+ {
+ jToken = JToken.FromObject(value);
+ }
+
+ j.Add(name, jToken);
+ }
+ }
+
+ if (sign)
+ {
+ credits ??= MafileCredits.Instance;
+ var obj = JObject.FromObject(credits);
+ j.Add(CREDITS_PROPERTY_NAME, obj);
+ }
+
+ j.WriteTo(write);
+ return w.ToString();
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/SteamLibForked/Utility/SteamIdParser.cs b/src/SteamLibForked/Utility/SteamIdParser.cs
similarity index 83%
rename from SteamLibForked/Utility/SteamIdParser.cs
rename to src/SteamLibForked/Utility/SteamIdParser.cs
index 9339b0f..1bae7ae 100644
--- a/SteamLibForked/Utility/SteamIdParser.cs
+++ b/src/SteamLibForked/Utility/SteamIdParser.cs
@@ -1,17 +1,18 @@
using System.Text.RegularExpressions;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Utility;
-public static class SteamIdParser
+public static partial class SteamIdParser
{
- public static readonly Regex Steam64Regex = new("^7656119([0-9]{10})$", RegexOptions.Compiled);
+ [GeneratedRegex("^7656119([0-9]{10})$", RegexOptions.Compiled)]
+ public static partial Regex Steam64Regex { get; }
- public static readonly Regex Steam2Regex =
- new("STEAM_(?[0-9]):(?[0-9]):(?[0-9]{1,10})", RegexOptions.Compiled);
+ [GeneratedRegex(@"STEAM_(?[0-9]):(?[0-9]):(?[0-9]{1,10})", RegexOptions.Compiled)]
+ public static partial Regex Steam2Regex { get; }
- public static readonly Regex Steam3Regex =
- new("^\\[?(?[a-zA-Z]):1:(?[0-9]{1,10})\\]$", RegexOptions.Compiled);
+ [GeneratedRegex(@"^\[?(?[a-zA-Z]):1:(?[0-9]{1,10})\]$", RegexOptions.Compiled)]
+ public static partial Regex Steam3Regex { get; }
#region TryParse
@@ -125,13 +126,13 @@ public static class SteamIdParser
public static SteamId64 Parse64(string input)
{
- var match64 = Steam64Regex.Match(input);
- if (match64.Success)
+ var steamId = long.Parse(input);
+ if (steamId < SteamId64.SEED)
{
- return new SteamId64(long.Parse(match64.Value));
+ throw new FormatException($"The input string '{input}' was not in a correct format or not real SteamId64");
}
- throw new FormatException($"The input string '{input}' was not in a correct format or not real SteamId64.");
+ return new SteamId64(steamId);
}
public static SteamId2 Parse2(string input)
diff --git a/SteamLibForked/Utility/Utilities.cs b/src/SteamLibForked/Utility/Utilities.cs
similarity index 52%
rename from SteamLibForked/Utility/Utilities.cs
rename to src/SteamLibForked/Utility/Utilities.cs
index 60502ef..ee9b4df 100644
--- a/SteamLibForked/Utility/Utilities.cs
+++ b/src/SteamLibForked/Utility/Utilities.cs
@@ -2,20 +2,23 @@
namespace SteamLib.Utility;
-public static class Utilities //TODO: refactor
+public static partial class Utilities //TODO: refactor
{
- private static readonly Regex RegexInt = new("\"success\":\\s?(\\d*)", RegexOptions.Compiled);
- private static readonly Regex RegexBool = new("\"success\":\\s?(\\w*)", RegexOptions.Compiled);
+ [GeneratedRegex("\"success\":\\s?(\\w*)", RegexOptions.Compiled)]
+ private static partial Regex GetRegexBool();
+
+ [GeneratedRegex("\"success\":\\s?(\\d*)", RegexOptions.Compiled)]
+ private static partial Regex GetRegexInt();
public static int GetSuccessCode(string response)
{
var length = Math.Min(response.Length, 100);
- var matchInt = RegexInt.Match(response, 0, length);
+ var matchInt = GetRegexInt().Match(response, 0, length);
if (!string.IsNullOrEmpty(matchInt.Groups[1].Value))
return Convert.ToInt32(matchInt.Groups[1].Value);
- var matchBool = RegexBool.Match(response, 0, length);
+ var matchBool = GetRegexBool().Match(response, 0, length);
if (!string.IsNullOrEmpty(matchBool.Groups[1].Value))
return bool.Parse(matchBool.Groups[1].Value) ? 1 : 0;
diff --git a/SteamLibForked/Web/ClientBuilder.cs b/src/SteamLibForked/Web/ClientBuilder.cs
similarity index 93%
rename from SteamLibForked/Web/ClientBuilder.cs
rename to src/SteamLibForked/Web/ClientBuilder.cs
index f9741eb..ebfdf6e 100644
--- a/SteamLibForked/Web/ClientBuilder.cs
+++ b/src/SteamLibForked/Web/ClientBuilder.cs
@@ -2,7 +2,7 @@
using System.Net.Http.Headers;
using AchiesUtilities.Web.Models;
using SteamLib.Authentication;
-using SteamLib.Core.Interfaces;
+using SteamLibForked.Abstractions;
namespace SteamLib.Web;
@@ -33,7 +33,8 @@ public static class ClientBuilder
{
container.SetSteamMobileCookiesWithMobileToken(sessionData);
}
-
+ //Nebula tweak:
+ handler.CookieContainer.InjectWebTradeEligibilityCookie();
ConfigureCommon(handler, client);
return new HttpClientHandlerPair(client, handler);
}
diff --git a/SteamLibForked/Web/Converters/SteamIdConverters.cs b/src/SteamLibForked/Web/Converters/SteamIdConverters.cs
similarity index 98%
rename from SteamLibForked/Web/Converters/SteamIdConverters.cs
rename to src/SteamLibForked/Web/Converters/SteamIdConverters.cs
index df225fb..f4a5844 100644
--- a/SteamLibForked/Web/Converters/SteamIdConverters.cs
+++ b/src/SteamLibForked/Web/Converters/SteamIdConverters.cs
@@ -1,5 +1,5 @@
using Newtonsoft.Json;
-using SteamLib.Core.Models;
+using SteamLibForked.Models.SteamIds;
namespace SteamLib.Web.Converters;
diff --git a/SteamLibForked/Web/Models/Account/UserWalletSchema.cs b/src/SteamLibForked/Web/Models/Account/UserWalletSchema.cs
similarity index 100%
rename from SteamLibForked/Web/Models/Account/UserWalletSchema.cs
rename to src/SteamLibForked/Web/Models/Account/UserWalletSchema.cs
diff --git a/SteamLibForked/Web/Models/Account/WalletSchema.cs b/src/SteamLibForked/Web/Models/Account/WalletSchema.cs
similarity index 100%
rename from SteamLibForked/Web/Models/Account/WalletSchema.cs
rename to src/SteamLibForked/Web/Models/Account/WalletSchema.cs
diff --git a/SteamLibForked/Web/Models/Mobile/Confirmations.cs b/src/SteamLibForked/Web/Models/Mobile/Confirmations.cs
similarity index 95%
rename from SteamLibForked/Web/Models/Mobile/Confirmations.cs
rename to src/SteamLibForked/Web/Models/Mobile/Confirmations.cs
index fe2c242..0ee2e60 100644
--- a/SteamLibForked/Web/Models/Mobile/Confirmations.cs
+++ b/src/SteamLibForked/Web/Models/Mobile/Confirmations.cs
@@ -23,7 +23,7 @@ public class ConfirmationJson
[JsonProperty("type")] public ConfirmationType Type { get; set; }
[JsonProperty("type_name")] public string TypeName { get; set; } = string.Empty;
[JsonProperty("id")] public long Id { get; set; }
- [JsonProperty("creator_id")] public long CreatorId { get; set; }
+ [JsonProperty("creator_id")] public ulong CreatorId { get; set; }
[JsonProperty("nonce")] public ulong Nonce { get; set; }
[JsonProperty("creation_time")] public UnixTimeStamp CreationTime { get; set; }
[JsonProperty("cancel")] public string Cancel { get; set; } = string.Empty;
diff --git a/src/SteamLibForked/Web/Scrappers/HTML/ScriptHeaderScrapper.cs b/src/SteamLibForked/Web/Scrappers/HTML/ScriptHeaderScrapper.cs
new file mode 100644
index 0000000..24d2836
--- /dev/null
+++ b/src/SteamLibForked/Web/Scrappers/HTML/ScriptHeaderScrapper.cs
@@ -0,0 +1,62 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Text.RegularExpressions;
+using HtmlAgilityPack;
+using JetBrains.Annotations;
+using SteamLib.Exceptions.General;
+using SteamLib.Models;
+
+namespace SteamLib.Web.Scrappers.HTML;
+
+//TODO: Use this as universal