Identity reloaded
This commit is contained in:
parent
ef0f5ddcac
commit
333b066e66
33 changed files with 195 additions and 180 deletions
|
|
@ -12,7 +12,7 @@ namespace PostIt.Services;
|
|||
/// The set is deliberately small: each value is a milestone an
|
||||
/// operator can grep for in logs / StatusMessage, not a heartbeat.
|
||||
/// </summary>
|
||||
public enum OidcLoginPhase
|
||||
public enum OIDCLoginPhase
|
||||
{
|
||||
/// <summary>No login in flight (or login has settled).</summary>
|
||||
Idle,
|
||||
|
|
|
|||
|
|
@ -91,15 +91,15 @@ public class YavscApiClient : IAsyncDisposable
|
|||
/// <see cref="LoginPageViewModel.StatusMessage"/> for the human
|
||||
/// text (URLs, error detail).</param>
|
||||
public async Task LoginInteractiveAsync(
|
||||
IProgress<OidcLoginPhase>? progress = null,
|
||||
IProgress<OIDCLoginPhase>? progress = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Discovering);
|
||||
progress?.Report(OIDCLoginPhase.Discovering);
|
||||
|
||||
var browser = Platform.CreateBrowser?.Invoke();
|
||||
if (browser is null)
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Error);
|
||||
progress?.Report(OIDCLoginPhase.Error);
|
||||
throw new InvalidOperationException("No browser is available on this platform.");
|
||||
}
|
||||
|
||||
|
|
@ -114,20 +114,20 @@ public class YavscApiClient : IAsyncDisposable
|
|||
// the moment we ask the browser to open (covers the entire
|
||||
// user-driven window including the AwaitingCallback wait), and
|
||||
// the moment we trade the code for tokens.
|
||||
progress?.Report(OidcLoginPhase.OpeningBrowser);
|
||||
progress?.Report(OIDCLoginPhase.OpeningBrowser);
|
||||
var result = await client.LoginAsync(new LoginRequest(), ct).ConfigureAwait(false);
|
||||
|
||||
if (result.IsError)
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Error);
|
||||
progress?.Report(OIDCLoginPhase.Error);
|
||||
throw new InvalidOperationException($"OIDC login failed: {result.Error}");
|
||||
}
|
||||
|
||||
progress?.Report(OidcLoginPhase.ExchangingCode);
|
||||
progress?.Report(OIDCLoginPhase.ExchangingCode);
|
||||
|
||||
if (string.IsNullOrEmpty(result.RefreshToken))
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Error);
|
||||
progress?.Report(OIDCLoginPhase.Error);
|
||||
throw new InvalidOperationException(
|
||||
"Missing refresh_token — vérifie le scope 'offline_access'.");
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ public class YavscApiClient : IAsyncDisposable
|
|||
IdToken: result.IdentityToken);
|
||||
|
||||
_store.Save(_tokens);
|
||||
progress?.Report(OidcLoginPhase.Success);
|
||||
progress?.Report(OIDCLoginPhase.Success);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -152,7 +152,7 @@ public class YavscApiClient : IAsyncDisposable
|
|||
/// phase and returns false so the UI can keep going.
|
||||
/// </summary>
|
||||
public async Task<bool> TrySilentLoginAsync(
|
||||
IProgress<OidcLoginPhase>? progress = null,
|
||||
IProgress<OIDCLoginPhase>? progress = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
if (!HasValidSession) return false;
|
||||
|
|
@ -161,7 +161,7 @@ public class YavscApiClient : IAsyncDisposable
|
|||
// Access token still has plenty of life — nothing to do.
|
||||
if (_tokens.AccessTokenExpiresAt - DateTimeOffset.UtcNow > RefreshSkew)
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Success);
|
||||
progress?.Report(OIDCLoginPhase.Success);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -172,19 +172,19 @@ public class YavscApiClient : IAsyncDisposable
|
|||
// the user back to the login page.
|
||||
try
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.ExchangingCode);
|
||||
progress?.Report(OIDCLoginPhase.ExchangingCode);
|
||||
await ForceRefreshAsync(ct).ConfigureAwait(false);
|
||||
progress?.Report(OidcLoginPhase.Success);
|
||||
progress?.Report(OIDCLoginPhase.Success);
|
||||
return true;
|
||||
}
|
||||
catch (RefreshFailedException)
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Idle);
|
||||
progress?.Report(OIDCLoginPhase.Idle);
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
progress?.Report(OidcLoginPhase.Idle);
|
||||
progress?.Report(OIDCLoginPhase.Idle);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
/// callback hand-off: when AwaitingCallback never resolves,
|
||||
/// the OS never re-launched PostIt with the postit:// URL.
|
||||
/// </summary>
|
||||
private OidcLoginPhase _phase = OidcLoginPhase.Idle;
|
||||
public OidcLoginPhase Phase
|
||||
private OIDCLoginPhase _phase = OIDCLoginPhase.Idle;
|
||||
public OIDCLoginPhase Phase
|
||||
{
|
||||
get => _phase;
|
||||
private set
|
||||
|
|
@ -122,13 +122,13 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
/// </summary>
|
||||
public string PhaseLabel => _phase switch
|
||||
{
|
||||
OidcLoginPhase.Idle => "En attente",
|
||||
OidcLoginPhase.Discovering => "Découverte OIDC…",
|
||||
OidcLoginPhase.OpeningBrowser => "Ouverture du navigateur…",
|
||||
OidcLoginPhase.AwaitingCallback => "En attente du callback postit://…",
|
||||
OidcLoginPhase.ExchangingCode => "Échange du code contre les jetons…",
|
||||
OidcLoginPhase.Success => "Connecté",
|
||||
OidcLoginPhase.Error => "Erreur",
|
||||
OIDCLoginPhase.Idle => "En attente",
|
||||
OIDCLoginPhase.Discovering => "Découverte OIDC…",
|
||||
OIDCLoginPhase.OpeningBrowser => "Ouverture du navigateur…",
|
||||
OIDCLoginPhase.AwaitingCallback => "En attente du callback postit://…",
|
||||
OIDCLoginPhase.ExchangingCode => "Échange du code contre les jetons…",
|
||||
OIDCLoginPhase.Success => "Connecté",
|
||||
OIDCLoginPhase.Error => "Erreur",
|
||||
_ => _phase.ToString(),
|
||||
};
|
||||
|
||||
|
|
@ -275,7 +275,7 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
// The progress sink drives Phase / PhaseLabel; StatusMessage
|
||||
// keeps the text detail (URLs, error messages). Same
|
||||
// underlying flow, two views.
|
||||
var progress = new Progress<OidcLoginPhase>(p => Phase = p);
|
||||
var progress = new Progress<OIDCLoginPhase>(p => Phase = p);
|
||||
await LoginInteractiveCoreAsync(_api, progress);
|
||||
|
||||
IsBusy = false;
|
||||
|
|
@ -299,7 +299,7 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
/// </summary>
|
||||
private async Task LoginInteractiveCoreAsync(
|
||||
YavscApiClient api,
|
||||
IProgress<OidcLoginPhase>? progress = null)
|
||||
IProgress<OIDCLoginPhase>? progress = null)
|
||||
{
|
||||
var original = Platform.CreateBrowser;
|
||||
try
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue