mirror of
https://github.com/achiez/NebulaAuth-Steam-Desktop-Authenticator-by-Achies.git
synced 2026-07-25 22:31:42 +00:00
c39660fc55
- Replace snackbar with interactive LoginAgainDialog when session cannot be recovered automatically on user-initiated actions - Show proxy warning hint in dialog when no proxy assigned to account or set as default - Pass allowInteractiveLogin: false from MAACRequestHandler to skip dialog in automated MAAC confirmations
183 lines
6.2 KiB
C#
183 lines
6.2 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using AchiesUtilities.Web.Models;
|
|
using MaterialDesignThemes.Wpf;
|
|
using NebulaAuth.Core;
|
|
using NebulaAuth.Model.Entities;
|
|
using NebulaAuth.Utility;
|
|
using NebulaAuth.View.Dialogs;
|
|
using NebulaAuth.ViewModel.Other;
|
|
using SteamLib.Exceptions.Authorization;
|
|
|
|
namespace NebulaAuth.Model;
|
|
|
|
public static partial class SessionHandler
|
|
{
|
|
private static readonly SemaphoreSlim Semaphore = new(1, 1);
|
|
|
|
public static async Task<T> Handle<T>(Func<Task<T>> func, Mafile mafile,
|
|
HttpClientHandlerPair? chp = null, string? snackbarPrefix = null, bool allowInteractiveLogin = true)
|
|
{
|
|
chp ??= MaClient.GetHttpClientHandlerPair(mafile);
|
|
await Semaphore.WaitAsync();
|
|
try
|
|
{
|
|
return await HandleInternal(func, chp.Value, mafile, snackbarPrefix, allowInteractiveLogin);
|
|
}
|
|
finally
|
|
{
|
|
Semaphore.Release();
|
|
}
|
|
}
|
|
|
|
private static async Task<T> HandleInternal<T>(Func<Task<T>> func, HttpClientHandlerPair chp, Mafile mafile,
|
|
string? snackbarPrefix = null, bool allowInteractiveLogin = true)
|
|
{
|
|
using var scope = Shell.Logger.PushScopeProperty("Scope", "SessionHandler");
|
|
Exception? currentException = null;
|
|
|
|
if (!mafile.MobileTokenExpired())
|
|
{
|
|
try
|
|
{
|
|
return await func();
|
|
}
|
|
catch (SessionInvalidException ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "Session on mafile {name} {steamid} is invalid when mobile token is not expired",
|
|
mafile.AccountName, mafile.SessionData?.SteamId);
|
|
currentException = ex;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
SnackbarController.SendSnackbar(snackbarPrefix +
|
|
LocManager.GetCodeBehindOrDefault("SessionWasRefreshedAutomatically",
|
|
"SessionHandler", "SessionWasRefreshedAutomatically"));
|
|
try
|
|
{
|
|
return await func();
|
|
}
|
|
catch (SessionInvalidException ex)
|
|
{
|
|
Shell.Logger.Warn(ex, "MobileToken on {name} {steamid} was refreshed but after it, error occured",
|
|
mafile.AccountName, mafile.SessionData?.SteamId);
|
|
currentException = ex;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mafile.HasPassword(out var password))
|
|
{
|
|
var logged = await LoginAgainInternal(chp, mafile, password, true);
|
|
if (logged)
|
|
{
|
|
Shell.Logger.Debug("Mafile {name} {steamid} was succesfully auto-relogined", mafile.AccountName,
|
|
mafile.SessionData?.SteamId);
|
|
return await func();
|
|
}
|
|
}
|
|
|
|
if (allowInteractiveLogin && !DialogHost.IsDialogOpen(null))
|
|
{
|
|
var noProxy = mafile.Proxy == null && MaClient.DefaultProxy == null;
|
|
var currentPassword = GetPassword(mafile);
|
|
|
|
Task<LoginAgainVM?> dialogTask = null!;
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
dialogTask = DialogsController.ShowLoginAgainDialog(mafile.AccountName, currentPassword, noProxy);
|
|
});
|
|
|
|
var vm = await dialogTask;
|
|
if (vm != null)
|
|
{
|
|
Shell.Logger.Info("User provided credentials interactively for {name}, attempting login",
|
|
mafile.AccountName);
|
|
var logged = await LoginAgainInternal(chp, mafile, vm.Password, vm.SavePassword);
|
|
if (logged)
|
|
{
|
|
Shell.Logger.Debug("Interactive login for {name} succeeded, retrying operation",
|
|
mafile.AccountName);
|
|
return await func();
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new SessionPermanentlyExpiredException(SessionPermanentlyExpiredException.SESSION_EXPIRED_MSG,
|
|
currentException);
|
|
}
|
|
|
|
private static async Task<bool> RefreshInternal(HttpClientHandlerPair chp, Mafile mafile)
|
|
{
|
|
try
|
|
{
|
|
await RefreshMobileToken(chp, mafile);
|
|
return true;
|
|
}
|
|
catch (SessionInvalidException ex)
|
|
{
|
|
Shell.Logger.Debug(ex, "Failed to refresh session on mafile {name} {steamid}", mafile.AccountName,
|
|
mafile.SessionData?.SteamId);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static async Task<bool> LoginAgainInternal(HttpClientHandlerPair chp, Mafile mafile, string password,
|
|
bool savePassword)
|
|
{
|
|
var t = Task.Run(OnLoginStarted);
|
|
try
|
|
{
|
|
await LoginAgain(chp, mafile, password, savePassword);
|
|
return true;
|
|
}
|
|
catch (Exception ex) //TODO: this will catch any error, even Proxy/Http/Socket errors.
|
|
{
|
|
Shell.Logger.Debug(ex, "Failed to relogin mafile {name} {steamid}", mafile.AccountName,
|
|
mafile.SessionData?.SteamId);
|
|
ExceptionHandler.Handle(ex);
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
OnLoginCompleted();
|
|
await t;
|
|
}
|
|
}
|
|
|
|
private static async Task OnLoginStarted()
|
|
{
|
|
if (DialogHost.IsDialogOpen(null)) return;
|
|
await Application.Current.Dispatcher.BeginInvoke(async () => { await DialogHost.Show(new WaitLoginDialog()); });
|
|
}
|
|
|
|
private static void OnLoginCompleted()
|
|
{
|
|
var currentSession = DialogHost.GetDialogSession(null);
|
|
Application.Current.Dispatcher.BeginInvoke(() =>
|
|
{
|
|
if (currentSession is {Content: WaitLoginDialog, IsEnded: false})
|
|
{
|
|
try
|
|
{
|
|
currentSession.Close();
|
|
}
|
|
catch
|
|
{
|
|
//Ignored
|
|
}
|
|
}
|
|
});
|
|
}
|
|
} |