mirror of
https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies.git
synced 2026-07-25 14:24:32 +00:00
8ff960189e
- Update: Added "Copy Password" to Mafile context menu (if available) - Update: "Save Password" now pre-fills the current password in the "Login Again" dialog when encryption is enabled - Fix: Prevented overlapping confirmation cycles in AutoConfirmer - Fix: Added a Snackbar notification when a confirmation cycle is skipped due to a too frequent timer interval - Fix: Fixed a rare bug where the previous proxy was used instead of the current one during session refresh - Fix: Corrected "Session Permanently Expired" message showing on unrelated errors (e.g. network issues) - UI-Fix: Fixed visual glitch where proxy input appeared non-empty when switching to a mafile-specific proxy - Cleanup: Refactored and cleaned up codebase, improved styling and formatting via ReSharper
213 lines
6.8 KiB
C#
213 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using AchiesUtilities.Web.Models;
|
|
using AchiesUtilities.Web.Proxy;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using NebulaAuth.Core;
|
|
using NebulaAuth.Model.Entities;
|
|
using NebulaAuth.Utility;
|
|
using SteamLib.Api.Mobile;
|
|
using SteamLib.Authentication;
|
|
using SteamLib.Core.Interfaces;
|
|
using SteamLib.Exceptions;
|
|
using SteamLib.SteamMobile.Confirmations;
|
|
using SteamLib.Web;
|
|
|
|
namespace NebulaAuth.Model.MAAC;
|
|
|
|
public partial class PortableMaClient : ObservableObject, IDisposable
|
|
{
|
|
private const string LOC_PATH = "MAAC";
|
|
public Mafile Mafile { get; }
|
|
private HttpClient Client { get; }
|
|
private HttpClientHandler ClientHandler { get; }
|
|
private DynamicProxy Proxy { get; }
|
|
|
|
private readonly CancellationTokenSource _cts = new();
|
|
[ObservableProperty] private bool _autoConfirmMarket;
|
|
|
|
[ObservableProperty] private bool _autoConfirmTrades;
|
|
[ObservableProperty] private bool _isError;
|
|
|
|
public PortableMaClient(Mafile mafile)
|
|
{
|
|
Mafile = mafile;
|
|
Proxy = new DynamicProxy();
|
|
Proxy.SetData(mafile.Proxy?.Data);
|
|
var pair = ClientBuilder.BuildMobileClient(Proxy, mafile.SessionData);
|
|
Client = pair.Client;
|
|
ClientHandler = pair.Handler;
|
|
UpdateCookies(mafile.SessionData);
|
|
Mafile.PropertyChanged += Mafile_PropertyChanged;
|
|
}
|
|
|
|
private void Mafile_PropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == nameof(Mafile.SessionData))
|
|
{
|
|
UpdateCookies(Mafile.SessionData);
|
|
}
|
|
}
|
|
|
|
|
|
private void UpdateCookies(IMobileSessionData? sessionData)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() => IsError = sessionData == null);
|
|
ClientHandler.CookieContainer.ClearAllCookies();
|
|
if (sessionData != null)
|
|
{
|
|
ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(sessionData);
|
|
}
|
|
else
|
|
{
|
|
ClientHandler.CookieContainer.ClearSteamCookies();
|
|
ClientHandler.CookieContainer.AddMinimalMobileCookies();
|
|
AdmissionHelper.TransferCommunityCookies(ClientHandler.CookieContainer);
|
|
}
|
|
}
|
|
|
|
|
|
public async Task<int> Confirm()
|
|
{
|
|
Proxy.SetData(Mafile.Proxy?.Data ?? MaClient.DefaultProxy);
|
|
List<Confirmation> conf;
|
|
try
|
|
{
|
|
conf = (await HandleTimerRequest(GetConfirmations)).ToList();
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "Timer {accountName}: Error GetConf in timer.", Mafile.AccountName);
|
|
return 0;
|
|
}
|
|
|
|
var toConfirm = new List<Confirmation>();
|
|
if (AutoConfirmMarket)
|
|
{
|
|
var market = conf.Where(c => c.ConfType == ConfirmationType.MarketSellTransaction);
|
|
toConfirm.AddRange(market);
|
|
}
|
|
|
|
if (AutoConfirmTrades)
|
|
{
|
|
var trade = conf.Where(c => c.ConfType == ConfirmationType.Trade);
|
|
toConfirm.AddRange(trade);
|
|
}
|
|
|
|
if (toConfirm.Count == 0) return 0;
|
|
try
|
|
{
|
|
Shell.Logger.Debug("Timer {accountName}: Sending confirmations. Count: {count}", Mafile.AccountName,
|
|
toConfirm.Count);
|
|
var success = await HandleTimerRequest(() => SendConfirmations(toConfirm));
|
|
Shell.Logger.Debug("Timer {accountName}: Confirmation sent: {confirmResult}", Mafile.AccountName, success);
|
|
return toConfirm.Count;
|
|
}
|
|
catch (ApplicationException ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "Timer {accountName}: MultiConf error in Timer.", Mafile.AccountName);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
private async Task<IEnumerable<Confirmation>> GetConfirmations()
|
|
{
|
|
return await SteamMobileConfirmationsApi.GetConfirmations(Client, Mafile, Mafile.SessionData!.SteamId,
|
|
_cts.Token);
|
|
}
|
|
|
|
private async Task<bool> SendConfirmations(IEnumerable<Confirmation> confirmations)
|
|
{
|
|
return await SteamMobileConfirmationsApi.SendMultipleConfirmations(Client, confirmations,
|
|
Mafile.SessionData!.SteamId, Mafile, true, _cts.Token);
|
|
}
|
|
|
|
private async Task<T> HandleTimerRequest<T>(Func<Task<T>> func)
|
|
{
|
|
Exception innerException;
|
|
try
|
|
{
|
|
return await SessionHandler.Handle(func, Mafile, Chp(), GetTimerPrefix());
|
|
}
|
|
catch (OperationCanceledException ex)
|
|
{
|
|
innerException = ex; //Ignored
|
|
}
|
|
catch (SessionInvalidException ex)
|
|
{
|
|
if (IgnoreTimerErrors())
|
|
{
|
|
Shell.Logger.Warn(
|
|
"Timer {accountName}: Session error while requesting in timer. Ignored due to IgnorePatchTuesdayErrors setting",
|
|
Mafile.AccountName);
|
|
}
|
|
else
|
|
{
|
|
Shell.Logger.Warn("Timer {accountName}: Session error while requesting in timer. Timer disabled",
|
|
Mafile.AccountName);
|
|
SetError();
|
|
}
|
|
|
|
innerException = ex;
|
|
}
|
|
catch (Exception ex) when (ExceptionHandler.Handle(ex, GetTimerPrefix()))
|
|
{
|
|
innerException = ex;
|
|
}
|
|
|
|
throw new ApplicationException("Swallowed", innerException);
|
|
}
|
|
|
|
|
|
private bool IgnoreTimerErrors()
|
|
{
|
|
if (Settings.Instance.IgnorePatchTuesdayErrors == false) return false;
|
|
|
|
var pstZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
|
|
var pstNow = TimeZoneInfo.ConvertTime(DateTime.UtcNow, pstZone);
|
|
|
|
var startTime = pstNow.Date.AddHours(15).AddMinutes(55); // 15:55 PST //22:55 GMT //00:55 GMT+2
|
|
var endTime = pstNow.Date.AddHours(17).AddMinutes(15); // 17:15 PST //00:15 GMT //02:15 GMT+2
|
|
|
|
return pstNow.DayOfWeek == DayOfWeek.Tuesday && pstNow >= startTime && pstNow <= endTime;
|
|
}
|
|
|
|
|
|
private HttpClientHandlerPair Chp()
|
|
{
|
|
return new HttpClientHandlerPair(Client, ClientHandler);
|
|
}
|
|
|
|
private static string GetLocalization(string key)
|
|
{
|
|
return LocManager.GetCodeBehindOrDefault(key, LOC_PATH, key);
|
|
}
|
|
|
|
private string GetTimerPrefix()
|
|
{
|
|
return GetLocalization("TimerPrefix") + Mafile.AccountName + ": ";
|
|
}
|
|
|
|
public void SetError()
|
|
{
|
|
Application.Current.Dispatcher.Invoke(() => IsError = true);
|
|
Shell.Logger.Warn("Timer {accountName}: disabled due to error.", Mafile.AccountName);
|
|
SnackbarController.SendSnackbar(GetTimerPrefix() + GetLocalization("TimerSessionError"));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_cts.Cancel();
|
|
_cts.Dispose();
|
|
Mafile.PropertyChanged -= Mafile_PropertyChanged;
|
|
Client.Dispose();
|
|
ClientHandler.Dispose();
|
|
}
|
|
} |