diff --git a/src/NebulaAuth/Converters/Converters.xaml b/src/NebulaAuth/Converters/Converters.xaml
index d99c88e..97888f1 100644
--- a/src/NebulaAuth/Converters/Converters.xaml
+++ b/src/NebulaAuth/Converters/Converters.xaml
@@ -12,7 +12,6 @@
-
diff --git a/src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs b/src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
deleted file mode 100644
index 89acb45..0000000
--- a/src/NebulaAuth/Converters/PortableMaClientStatusToColorConverter.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Globalization;
-using System.Windows.Data;
-using System.Windows.Media;
-
-namespace NebulaAuth.Converters;
-
-public class PortableMaClientStatusToColorConverter : IValueConverter
-{
- public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
- {
- if (value is false)
- {
- return new SolidColorBrush(Color.FromRgb(187, 224, 139));
- }
-
-
- return new SolidColorBrush(Color.FromRgb(224, 139, 139));
- }
-
- public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
- {
- throw new NotSupportedException();
- }
-}
\ No newline at end of file
diff --git a/src/NebulaAuth/MainWindow.xaml b/src/NebulaAuth/MainWindow.xaml
index 40f25d5..ab49375 100644
--- a/src/NebulaAuth/MainWindow.xaml
+++ b/src/NebulaAuth/MainWindow.xaml
@@ -294,18 +294,42 @@
-
-
-
-
+
+
+
+
+
-
-
-
+
@@ -393,7 +417,9 @@
-
+
diff --git a/src/NebulaAuth/Model/MAAC/MAACRequestHandler.cs b/src/NebulaAuth/Model/MAAC/MAACRequestHandler.cs
new file mode 100644
index 0000000..4ab9e9b
--- /dev/null
+++ b/src/NebulaAuth/Model/MAAC/MAACRequestHandler.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Concurrent;
+using System.Threading.Tasks;
+using NebulaAuth.Core;
+using NebulaAuth.Model.Entities;
+using SteamLib.Exceptions.Authorization;
+
+namespace NebulaAuth.Model.MAAC;
+
+public static class MAACRequestHandler
+{
+ private const string LOC_PATH = "MAAC";
+ private static readonly ConcurrentDictionary _errors = new();
+
+ public static void Register(Mafile mafile)
+ {
+ _errors[mafile] = new PortableMaClientErrorData();
+ }
+
+ public static void Unregister(Mafile mafile)
+ {
+ _errors.TryRemove(mafile, out _);
+ }
+
+ public static PortableMaClientStatus ClearErrors(Mafile mafile)
+ {
+ if (_errors.TryGetValue(mafile, out var data))
+ {
+ data.Clear();
+ }
+
+ return PortableMaClientStatus.Ok();
+ }
+
+ ///
+ /// Handles a MAAC request with progressive error handling strategy: retries and status management based on error
+ /// history.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task HandleRequest(PortableMaClient client, Func> func)
+ {
+ var result = await client.DoRequest(func, client.Mafile.PreviouslyHadNoErrors());
+ if (result.IsSuccess)
+ {
+ InformRequestSuccessful(client.Mafile);
+ return result.Data;
+ }
+
+ if (client.Mafile.PreviouslyHadNoErrors())
+ {
+ client.SetStatus(PortableMaClientStatus.Warning(GetPortableMaClientStatus("SessionError")));
+ }
+ else if (client.Mafile.LastErrorWasAtLeast(Settings.Instance.MaacRetryInterval))
+ {
+ Shell.Logger.Info("Retrying MAAC request for {name} MAAC account after previous error.",
+ client.Mafile.AccountName);
+ result = await client.DoRequest(func);
+ if (result.IsSuccess)
+ {
+ InformRequestSuccessful(client.Mafile);
+ return result.Data;
+ }
+ }
+
+ if (client.Mafile.ErrorPersistedFor(Settings.Instance.MaacErrorThreshold))
+ {
+ client.SetStatus(PortableMaClientStatus.Error(GetPortableMaClientStatus("SessionError")));
+ }
+
+ AddError(client.Mafile, result.Exception!);
+ throw result.Exception!;
+ }
+
+
+ private static async Task> DoRequest(this PortableMaClient client, Func> req,
+ bool withSessionHandler = true)
+ {
+ try
+ {
+ return withSessionHandler
+ ? Result.Success(await SessionHandler.Handle(req, client.Mafile, client.Chp(),
+ GetTimerPrefix(client.Mafile)))
+ : Result.Success(await req());
+ }
+ catch (SessionInvalidException ex)
+ {
+ Shell.Logger.Warn("SessionInvalidException caught in MAAC request handler.");
+ return Result.Error(ex);
+ }
+ }
+
+ private static void InformRequestSuccessful(Mafile mafile)
+ {
+ if (_errors.TryGetValue(mafile, out var data))
+ {
+ Shell.Logger.Info("MAAC request for {name} MAAC account succeeded, clearing error history.",
+ mafile.AccountName);
+ data.Clear();
+ }
+ }
+
+ private static void AddError(Mafile mafile, Exception ex)
+ {
+ if (_errors.TryGetValue(mafile, out var data))
+ {
+ Shell.Logger.Info("Registering error for {name} MAAC account: {ex}", mafile.AccountName, ex.Message);
+ data.AddEntry(ex);
+ }
+ }
+
+ private static bool ErrorPersistedFor(this Mafile mafile, TimeSpan span)
+ {
+ if (_errors.TryGetValue(mafile, out var data))
+ {
+ var oldestError = data.GetOldestErrorTime();
+ if (oldestError.HasValue && DateTime.UtcNow - oldestError.Value > span)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ private static bool PreviouslyHadNoErrors(this Mafile mafile)
+ {
+ if (_errors.TryGetValue(mafile, out var data))
+ {
+ return data.NoErrors;
+ }
+
+ return true;
+ }
+
+ private static bool LastErrorWasAtLeast(this Mafile mafile, TimeSpan timeAgo)
+ {
+ if (!_errors.TryGetValue(mafile, out var data)) return false;
+ var latestError = data.GetTimeFromLastError();
+ if (latestError.HasValue && latestError.Value > timeAgo)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private static string GetTimerPrefix(Mafile mafile)
+ {
+ return GetLocalization("TimerPrefix") + mafile.AccountName + ": ";
+ }
+
+ private static string GetLocalization(string key)
+ {
+ return LocManager.GetCodeBehindOrDefault(key, LOC_PATH, key);
+ }
+
+ private static string GetPortableMaClientStatus(string key)
+ {
+ return LocManager.GetCodeBehindOrDefault(key, LOC_PATH, key);
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs b/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
index 8d3714b..d01be16 100644
--- a/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
+++ b/src/NebulaAuth/Model/MAAC/MultiAccountAutoConfirmer.cs
@@ -59,7 +59,8 @@ 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 {Status.StatusType: PortableMaClientStatusType.Ok})
+ .ToArray();
enabledClients = DistributeEvenly(enabledClients).ToArray();
var confirmed = 0;
await Task.Run(async () =>
@@ -69,7 +70,8 @@ public static class MultiAccountAutoConfirmer
var conf = 0;
try
{
- conf = await client.LinkedClient!.Confirm();
+ conf = await MAACRequestHandler.HandleRequest(client.LinkedClient!,
+ () => client.LinkedClient!.Confirm());
}
catch (ObjectDisposedException)
{
@@ -114,7 +116,6 @@ public static class MultiAccountAutoConfirmer
}
}
-
public static bool TryAddToConfirm(Mafile mafile)
{
return Lock.WriteLock(() =>
@@ -122,6 +123,7 @@ public static class MultiAccountAutoConfirmer
if (Clients.Contains(mafile)) return false;
mafile.LinkedClient = new PortableMaClient(mafile);
Clients.Add(mafile);
+ MAACRequestHandler.Register(mafile);
return true;
});
}
@@ -134,6 +136,7 @@ public static class MultiAccountAutoConfirmer
Clients.Remove(mafile);
mafile.LinkedClient?.Dispose();
mafile.LinkedClient = null;
+ MAACRequestHandler.Unregister(mafile);
});
}
diff --git a/src/NebulaAuth/Model/MAAC/PortableMaClient.cs b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
index 0de4ec7..1b8ec3b 100644
--- a/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
+++ b/src/NebulaAuth/Model/MAAC/PortableMaClient.cs
@@ -11,11 +11,9 @@ using AchiesUtilities.Web.Proxy;
using CommunityToolkit.Mvvm.ComponentModel;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
-using NebulaAuth.Utility;
using SteamLib.Api.Mobile;
using SteamLib.Api.Trade;
using SteamLib.Authentication;
-using SteamLib.Exceptions.Authorization;
using SteamLib.SteamMobile.Confirmations;
using SteamLib.Web;
using SteamLibForked.Abstractions;
@@ -34,7 +32,7 @@ public partial class PortableMaClient : ObservableObject, IDisposable
[ObservableProperty] private bool _autoConfirmMarket;
[ObservableProperty] private bool _autoConfirmTrades;
- [ObservableProperty] private bool _isError;
+ [ObservableProperty] private PortableMaClientStatus _status = PortableMaClientStatus.Ok();
public PortableMaClient(Mafile mafile)
{
@@ -46,6 +44,7 @@ public partial class PortableMaClient : ObservableObject, IDisposable
ClientHandler = pair.Handler;
UpdateCookies(mafile.SessionData);
Mafile.PropertyChanged += Mafile_PropertyChanged;
+ SetStatus(PortableMaClientStatus.Error("123123"));
}
private void Mafile_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@@ -56,37 +55,21 @@ public partial class PortableMaClient : ObservableObject, IDisposable
}
}
-
private void UpdateCookies(IMobileSessionData? sessionData)
{
- Application.Current.Dispatcher.Invoke(() => IsError = sessionData == null);
+ var newStatus = MAACRequestHandler.ClearErrors(Mafile);
+ if (!newStatus.Equals(Status))
+ SetStatus(newStatus);
+
ClientHandler.CookieContainer.ClearAllCookies();
- if (sessionData != null)
- {
- ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(sessionData);
- }
- else
- {
- ClientHandler.CookieContainer.ClearSteamCookies();
- ClientHandler.CookieContainer.AddMinimalMobileCookies();
- AdmissionHelper.TransferCommunityCookies(ClientHandler.CookieContainer);
- }
+ ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(sessionData);
}
public async Task Confirm()
{
Proxy.SetData(Mafile.Proxy?.Data ?? MaClient.DefaultProxy);
- List 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 conf = (await GetConfirmations()).ToList();
var toConfirm = new List();
if (AutoConfirmMarket)
@@ -103,20 +86,12 @@ public partial class PortableMaClient : ObservableObject, IDisposable
}
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));
- //TODO: handle success == false
- 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;
- }
+ Shell.Logger.Debug("Timer {accountName}: Sending confirmations. Count: {count}", Mafile.AccountName,
+ toConfirm.Count);
+ var success = await SendConfirmations(toConfirm);
+ //TODO: handle success == false
+ Shell.Logger.Debug("Timer {accountName}: Confirmation sent: {confirmResult}", Mafile.AccountName, success);
+ return toConfirm.Count;
}
@@ -148,58 +123,7 @@ public partial class PortableMaClient : ObservableObject, IDisposable
Mafile.SessionData!.SteamId, Mafile, true, _cts.Token);
}
- private async Task HandleTimerRequest(Func> 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) 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()
+ public HttpClientHandlerPair Chp()
{
return new HttpClientHandlerPair(Client, ClientHandler);
}
@@ -214,11 +138,14 @@ public partial class PortableMaClient : ObservableObject, IDisposable
return GetLocalization("TimerPrefix") + Mafile.AccountName + ": ";
}
- public void SetError()
+ public void SetStatus(PortableMaClientStatus status)
{
- Application.Current.Dispatcher.Invoke(() => IsError = true);
- Shell.Logger.Warn("Timer {accountName}: disabled due to error.", Mafile.AccountName);
- SnackbarController.SendSnackbar(GetTimerPrefix() + GetLocalization("TimerSessionError"));
+ Application.Current.Dispatcher.Invoke(() => Status = status);
+ if (status.StatusType == PortableMaClientStatusType.Error)
+ {
+ Shell.Logger.Warn("Timer {accountName}: disabled due to error.", Mafile.AccountName);
+ SnackbarController.SendSnackbar(GetTimerPrefix() + status.Message);
+ }
}
public void Dispose()
diff --git a/src/NebulaAuth/Model/MAAC/PortableMaClientErrorData.cs b/src/NebulaAuth/Model/MAAC/PortableMaClientErrorData.cs
new file mode 100644
index 0000000..9235ed5
--- /dev/null
+++ b/src/NebulaAuth/Model/MAAC/PortableMaClientErrorData.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NebulaAuth.Model.MAAC;
+
+public sealed class PortableMaClientErrorData
+{
+ public SortedDictionary Values { get; } = new();
+ public bool NoErrors => Values.Count == 0;
+ private readonly object _lock = new();
+
+
+ public DateTime? GetOldestErrorTime()
+ {
+ if (Values.Count == 0) return null;
+ return Values.Keys.First();
+ }
+
+ public void AddEntry(Exception ex)
+ {
+ lock (_lock)
+ Values[DateTime.UtcNow] = ex;
+ }
+
+ public void Clear()
+ {
+ lock (_lock)
+ Values.Clear();
+ }
+
+ public TimeSpan? GetTimeFromLastError()
+ {
+ if (Values.Count == 0) return null;
+ var lastEntry = Values.Keys.Last();
+ return DateTime.UtcNow - lastEntry;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/Model/MAAC/PortableMaClientStatus.cs b/src/NebulaAuth/Model/MAAC/PortableMaClientStatus.cs
new file mode 100644
index 0000000..2cd95b6
--- /dev/null
+++ b/src/NebulaAuth/Model/MAAC/PortableMaClientStatus.cs
@@ -0,0 +1,26 @@
+namespace NebulaAuth.Model.MAAC;
+
+public record PortableMaClientStatus(PortableMaClientStatusType StatusType, string? Message = null)
+{
+ public static PortableMaClientStatus Ok()
+ {
+ return new PortableMaClientStatus(PortableMaClientStatusType.Ok);
+ }
+
+ public static PortableMaClientStatus Warning(string? message)
+ {
+ return new PortableMaClientStatus(PortableMaClientStatusType.Warning, message);
+ }
+
+ public static PortableMaClientStatus Error(string? message)
+ {
+ return new PortableMaClientStatus(PortableMaClientStatusType.Error, message);
+ }
+}
+
+public enum PortableMaClientStatusType
+{
+ Ok,
+ Warning,
+ Error
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/Model/MAAC/Result.cs b/src/NebulaAuth/Model/MAAC/Result.cs
new file mode 100644
index 0000000..d7af708
--- /dev/null
+++ b/src/NebulaAuth/Model/MAAC/Result.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace NebulaAuth.Model.MAAC;
+
+public struct Result
+{
+ public bool IsSuccess { get; }
+ public T Data => !IsSuccess ? throw new InvalidOperationException("No data available") : _data!;
+ public Exception? Exception { get; }
+
+ private readonly T? _data;
+
+ private Result(bool success, T? data, Exception? exception)
+ {
+ IsSuccess = success;
+ _data = data;
+ Exception = exception;
+ }
+
+ public static Result Success(T data)
+ {
+ return new Result(true, data, null);
+ }
+
+ public static Result Error(Exception ex)
+ {
+ return new Result(false, default, ex);
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/Model/MaClient.cs b/src/NebulaAuth/Model/MaClient.cs
index 3be9ca6..115f5e3 100644
--- a/src/NebulaAuth/Model/MaClient.cs
+++ b/src/NebulaAuth/Model/MaClient.cs
@@ -38,17 +38,7 @@ public static class MaClient
{
ClientHandler.CookieContainer.ClearAllCookies();
if (account == null) return;
- if (account.SessionData != null)
- {
- ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(account.SessionData);
- }
- else
- {
- ClientHandler.CookieContainer.ClearSteamCookies();
- ClientHandler.CookieContainer.AddMinimalMobileCookies();
- AdmissionHelper.TransferCommunityCookies(ClientHandler.CookieContainer);
- }
-
+ ClientHandler.CookieContainer.SetSteamMobileCookiesWithMobileToken(account.SessionData);
Proxy.SetData(account.Proxy?.Data);
}
diff --git a/src/NebulaAuth/Model/MafileExport/MafileExporter.cs b/src/NebulaAuth/Model/MafileExport/MafileExporter.cs
index 141cd38..9774193 100644
--- a/src/NebulaAuth/Model/MafileExport/MafileExporter.cs
+++ b/src/NebulaAuth/Model/MafileExport/MafileExporter.cs
@@ -6,6 +6,7 @@ using AchiesUtilities.Extensions;
using NebulaAuth.Core;
using NebulaAuth.Model.Entities;
using NebulaAuth.Model.Mafiles;
+using SteamLibForked.Models.Session;
using SteamLibForked.Models.SteamIds;
namespace NebulaAuth.Model.MafileExport;
@@ -71,6 +72,12 @@ public static class MafileExporter
private static async Task ExportMafile(string path, MafileExportTemplate template, Mafile mafile)
{
+ // We preserve SteamId even if other info is not included
+ var session = template.IncludeSessionData
+ ? mafile.SessionData
+ : new MobileSessionData(null!, mafile.SteamId, default, null, tokens: null);
+
+
var serializeMaf = new Mafile
{
SharedSecret = template.IncludeSharedSecret ? mafile.SharedSecret : null!,
@@ -78,7 +85,7 @@ public static class MafileExporter
DeviceId = template.IncludeIdentitySecret ? mafile.DeviceId : null!,
RevocationCode = template.IncludeRCode ? mafile.RevocationCode : null!,
AccountName = mafile.AccountName,
- SessionData = template.IncludeSessionData ? mafile.SessionData : null!,
+ SessionData = session,
SteamId = mafile.SteamId,
ServerTime = template.IncludeOtherInfo ? mafile.ServerTime : 0,
SerialNumber = template.IncludeOtherInfo ? mafile.SerialNumber : 0,
diff --git a/src/NebulaAuth/Model/Mafiles/Storage.cs b/src/NebulaAuth/Model/Mafiles/Storage.cs
index f11f93f..77c66dd 100644
--- a/src/NebulaAuth/Model/Mafiles/Storage.cs
+++ b/src/NebulaAuth/Model/Mafiles/Storage.cs
@@ -67,7 +67,6 @@ public static class Storage
}, token);
MaFiles = new ObservableCollection(localList.OrderBy(m => m.AccountName));
-
}
///
diff --git a/src/NebulaAuth/Model/SessionHandler.cs b/src/NebulaAuth/Model/SessionHandler/SessionHandler.cs
similarity index 66%
rename from src/NebulaAuth/Model/SessionHandler.cs
rename to src/NebulaAuth/Model/SessionHandler/SessionHandler.cs
index 7e3a0e3..b1c9979 100644
--- a/src/NebulaAuth/Model/SessionHandler.cs
+++ b/src/NebulaAuth/Model/SessionHandler/SessionHandler.cs
@@ -34,37 +34,28 @@ public static partial class SessionHandler
string? snackbarPrefix = null)
{
using var scope = Shell.Logger.PushScopeProperty("Scope", "SessionHandler");
- var mobileTokenExpired = MobileTokenExpired(mafile);
- var refreshTokenExpired = RefreshTokenExpired(mafile);
- var password = GetPassword(mafile);
+ Exception? currentException = null;
- if (!mobileTokenExpired)
+ if (!mafile.MobileTokenExpired())
{
try
{
return await func();
}
catch (SessionInvalidException ex)
- when (!refreshTokenExpired || password != null)
{
- if (ex is SessionPermanentlyExpiredException)
- {
- Shell.Logger.Debug(ex, "RefreshToken on mafile {name} {steamid} is expired", mafile.AccountName,
- mafile.SessionData?.SteamId);
- refreshTokenExpired = true;
- }
- else
- {
- Shell.Logger.Debug(ex, "MobileToken on mafile {name} {steamid} is expired", mafile.AccountName,
- mafile.SessionData?.SteamId);
- }
+ Shell.Logger.Warn(ex, "Session on mafile {name} {steamid} is invalid when mobile token is not expired",
+ mafile.AccountName, mafile.SessionData?.SteamId);
+ currentException = ex;
}
}
-
- //State: mobileToken invalid/expired, refreshToken maybe not expired
- if (!refreshTokenExpired)
+ if (!mafile.RefreshTokenExpired())
{
+ Shell.Logger.Info("Trying to refresh session on mafile {name} {steamid} using refresh token",
+ mafile.AccountName,
+ mafile.SessionData?.SteamId);
+
var refreshed = await RefreshInternal(chp, mafile);
if (refreshed)
{
@@ -77,19 +68,14 @@ public static partial class SessionHandler
}
catch (SessionInvalidException ex)
{
- Shell.Logger.Info(ex, "MobileToken on {name} {steamid} was refreshed but after it, error occured",
+ Shell.Logger.Warn(ex, "MobileToken on {name} {steamid} was refreshed but after it, error occured",
mafile.AccountName, mafile.SessionData?.SteamId);
- if (password == null)
- throw;
+ currentException = ex;
}
}
}
- Shell.Logger.Debug("Session on mafile {name} {steamid} is invalid/expired", mafile.AccountName,
- mafile.SessionData?.SteamId);
-
- //State: mobileToken invalid/expired, refreshToken invalid/expired
- if (password != null)
+ if (mafile.HasPassword(out var password))
{
var logged = await LoginAgainInternal(chp, mafile, password, true);
if (logged)
@@ -100,41 +86,10 @@ public static partial class SessionHandler
}
}
- //Nothing to do more, everything is expired
- throw new SessionPermanentlyExpiredException(SessionPermanentlyExpiredException.SESSION_EXPIRED_MSG);
+ throw new SessionPermanentlyExpiredException(SessionPermanentlyExpiredException.SESSION_EXPIRED_MSG,
+ currentException);
}
-
- private static bool MobileTokenExpired(Mafile mafile)
- {
- var mobileToken = mafile.SessionData?.GetMobileToken();
- return mobileToken == null || mobileToken.Value.IsExpired;
- }
-
- private static bool RefreshTokenExpired(Mafile mafile)
- {
- var refreshToken = mafile.SessionData?.RefreshToken;
- return refreshToken == null || refreshToken.Value.IsExpired;
- }
-
- private static string? GetPassword(Mafile mafile)
- {
- try
- {
- if (PHandler.IsPasswordSet && !string.IsNullOrWhiteSpace(mafile.Password))
- {
- return PHandler.Decrypt(mafile.Password);
- }
- }
- catch
- {
- // ignored
- }
-
- return null;
- }
-
-
private static async Task RefreshInternal(HttpClientHandlerPair chp, Mafile mafile)
{
try
diff --git a/src/NebulaAuth/Model/SessionHandler_API.cs b/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
similarity index 90%
rename from src/NebulaAuth/Model/SessionHandler_API.cs
rename to src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
index 0b38909..b644462 100644
--- a/src/NebulaAuth/Model/SessionHandler_API.cs
+++ b/src/NebulaAuth/Model/SessionHandler/SessionHandler_API.cs
@@ -28,7 +28,6 @@ public partial class SessionHandler //API
mafile.SessionData.SetMobileToken(newToken);
//Trigger PropertyChanged event for PortableMaClient handling session updated from MaClient
- //RETHINK: it makes double operation when session handled from PortableMaClient (more often scenario) which is unwanted behaviour
mafile.SetSessionData(mafile.SessionData);
await Storage.UpdateMafileAsync(mafile);
chp.Handler.CookieContainer.SetSteamMobileCookiesWithMobileToken(mafile.SessionData);
@@ -50,7 +49,6 @@ public partial class SessionHandler //API
AdmissionHelper.TransferCommunityCookies(chp.Handler.CookieContainer);
//Triggers PropertyChanged event for PortableMaClient handling session updated from MaClient
- //RETHINK: it makes double operation when session handled from PortableMaClient (more often scenario) which is unwanted behaviour
mafile.SetSessionData((MobileSessionData) result);
if (PHandler.IsPasswordSet)
mafile.Password = savePassword ? PHandler.Encrypt(password) : null;
diff --git a/src/NebulaAuth/Model/SessionHandler/SessionHandler_Helpers.cs b/src/NebulaAuth/Model/SessionHandler/SessionHandler_Helpers.cs
new file mode 100644
index 0000000..448472e
--- /dev/null
+++ b/src/NebulaAuth/Model/SessionHandler/SessionHandler_Helpers.cs
@@ -0,0 +1,42 @@
+using System.Diagnostics.CodeAnalysis;
+using NebulaAuth.Model.Entities;
+
+namespace NebulaAuth.Model;
+
+public partial class SessionHandler //Helpers
+{
+ private static bool MobileTokenExpired(this Mafile mafile)
+ {
+ var mobileToken = mafile.SessionData?.GetMobileToken();
+ return mobileToken == null || mobileToken.Value.IsExpired;
+ }
+
+ private static bool RefreshTokenExpired(this Mafile mafile)
+ {
+ var refreshToken = mafile.SessionData?.RefreshToken;
+ return refreshToken == null || refreshToken.Value.IsExpired;
+ }
+
+ private static bool HasPassword(this Mafile mafile, [NotNullWhen(true)] out string? plainPassword)
+ {
+ plainPassword = GetPassword(mafile);
+ return !string.IsNullOrWhiteSpace(plainPassword);
+ }
+
+ private static string? GetPassword(Mafile mafile)
+ {
+ try
+ {
+ if (PHandler.IsPasswordSet && !string.IsNullOrWhiteSpace(mafile.Password))
+ {
+ return PHandler.Decrypt(mafile.Password);
+ }
+ }
+ catch
+ {
+ // ignored
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/NebulaAuth/Model/Settings.cs b/src/NebulaAuth/Model/Settings.cs
index e4d3963..afa052b 100644
--- a/src/NebulaAuth/Model/Settings.cs
+++ b/src/NebulaAuth/Model/Settings.cs
@@ -94,7 +94,6 @@ public partial class Settings : ObservableObject
[ObservableProperty] private bool _legacyMode = true;
[ObservableProperty] private bool _allowAutoUpdate;
[ObservableProperty] private bool _useAccountNameAsMafileName;
- [ObservableProperty] private bool _ignorePatchTuesdayErrors;
[ObservableProperty] private BackgroundMode _backgroundMode = BackgroundMode.Default;
[ObservableProperty] private double _leftOpacity = 0.4;
@@ -108,6 +107,9 @@ public partial class Settings : ObservableObject
[ObservableProperty] private bool _proxyManagerDisplayProtocol;
[ObservableProperty] private bool _proxyManagerDisplayCredentials;
+ [ObservableProperty] private TimeSpan _maacErrorThreshold = TimeSpan.FromHours(3);
+ [ObservableProperty] private TimeSpan _maacRetryInterval = TimeSpan.FromMinutes(15);
+
#endregion
}
diff --git a/src/NebulaAuth/NLog.config b/src/NebulaAuth/NLog.config
index 259810c..d35ee8f 100644
--- a/src/NebulaAuth/NLog.config
+++ b/src/NebulaAuth/NLog.config
@@ -5,7 +5,11 @@
throwExceptions="true">
-
+
diff --git a/src/NebulaAuth/NebulaAuth.csproj b/src/NebulaAuth/NebulaAuth.csproj
index 6237b34..e626474 100644
--- a/src/NebulaAuth/NebulaAuth.csproj
+++ b/src/NebulaAuth/NebulaAuth.csproj
@@ -10,7 +10,7 @@
en;ru;ua
Theme\lock.ico
7.0
- 1.8.0
+ 1.8.1
true
diff --git a/src/NebulaAuth/View/SettingsView.xaml b/src/NebulaAuth/View/SettingsView.xaml
index 44c0f15..b0015e6 100644
--- a/src/NebulaAuth/View/SettingsView.xaml
+++ b/src/NebulaAuth/View/SettingsView.xaml
@@ -63,14 +63,6 @@
Content="{Tr SettingsDialog.LegacyMafileMode}"
ToolTip="{Tr SettingsDialog.LegacyMafileModeHint}" />
-
-
-