mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-13 06:07:30 -04:00
Ported from #1949. The reporter's log paused auto-scan on a second account that had never been logged in, while the dialog blamed an expired session and named no account, so there was nothing to act on. AccountCredentialStatus tells a never-registered account apart from one holding an expired access token, by looking for a refresh token to renew from. AutoScanRunner now hands the AuthenticationRequiredException to the notification so the prompt can name the account, which means digging that exception back out of the wrappers the scan adds on the way up. Same distinction in the log line and in the exception message ApiExtended throws when interactive login is unavailable, which is what the CLI and Docker users see. Co-authored-by: rmcrackan <rmcrackan@gmail.com>
52 lines
1.4 KiB
C#
52 lines
1.4 KiB
C#
using AudibleApi.Authentication;
|
|
|
|
namespace AudibleUtilities;
|
|
|
|
public static class AuthenticationExceptionHelper
|
|
{
|
|
public static bool IsAuthenticationFailure(Exception ex)
|
|
{
|
|
if (ex is AggregateException aggregate)
|
|
{
|
|
return aggregate.InnerExceptions.Any(IsAuthenticationFailure)
|
|
|| (aggregate.InnerException is not null && IsAuthenticationFailure(aggregate.InnerException));
|
|
}
|
|
|
|
for (var current = ex; current is not null; current = current.InnerException)
|
|
{
|
|
if (current is AuthenticationRequiredException or LoginFailedException)
|
|
return true;
|
|
|
|
if (current is InvalidOperationException { Message: var message }
|
|
&& message.Contains("ADP token is null", StringComparison.Ordinal))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the <see cref="AuthenticationRequiredException"/> in <paramref name="ex"/> or its inner chain, which is
|
|
/// the one that knows which account needs a login.
|
|
/// </summary>
|
|
public static AuthenticationRequiredException? FindAuthenticationRequired(Exception ex)
|
|
{
|
|
for (var current = ex; current is not null; current = current.InnerException)
|
|
{
|
|
if (current is AuthenticationRequiredException auth)
|
|
return auth;
|
|
}
|
|
|
|
if (ex is AggregateException aggregate)
|
|
{
|
|
foreach (var inner in aggregate.InnerExceptions)
|
|
{
|
|
if (FindAuthenticationRequired(inner) is { } found)
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|