Commit graph

4 commits

Author SHA1 Message Date
333b066e66 Identity reloaded 2026-07-05 23:56:10 +01:00
514549c5f9 postit: traceable OIDC login UX + session persistence + 2nd-instance early exit
- OidcLoginPhase enum + IProgress<OidcLoginPhase> on
  YavscApiClient.LoginInteractiveAsync, surfaced in the UI as
  PhaseLabel (FR). Lets operators see where the flow actually
  stalls, in particular whether the postit://callback ever arrives
  on the running instance.
- YavscApiClient.TrySilentLoginAsync: silent refresh at boot.
  Returns false (and purges the store) when the refresh token is
  rejected by the OP.
- App.OnFrameworkInitializationCompleted auto-routes: HomePage is
  the navigation root; on Opened the app calls TrySilentLoginAsync
  and pushes MainPage if a session is restored. Logout pops back
  to HomePage via the new persistent SessionStatusBanner (Connecté
  / Déconnecté + Logout button).
- PostIt.Desktop.Program.Main now detects the postit://callback
  URL BEFORE Avalonia boots, hands it off via SingleInstance, and
  exits. Stops the 2nd PostIt instance from flashing its own
  MainWindow while the 1st instance is still waiting on the named
  pipe. The check in App.OnFrameworkInitializationCompleted is
  kept as belt-and-braces defence-in-depth.
- SchemeUrlDetector: pure platform-independent detector extracted
  for unit testing.
- Tests: 7 new SchemeUrlDetectorTests + 5 new phase / silent
  refresh tests in YavscApiClientTests.
2026-06-27 12:47:52 +01:00
f3a3b63595 WIP PostIt login 2026-06-25 00:08:25 +01:00
f96d84dc5b postit: wire BlogApiClient through YavscApiClient and unify auth
BlogApiClient is a thin DTO↔path mapper on top of YavscApiClient:
- No more HttpClient, no more accessToken constructor argument.
- Single responsibility: turn Yavsc.Blogs endpoint paths into typed
  BlogPost payloads and back, while YavscApiClient owns auth +
  refresh + JSON shape.
- Default path prefix is 'api/blog', overridable for tests.

MainPageViewModel and App.axaml.cs are now free of any direct
OidcClient / IBrowser / BearerToken plumbing. The MainPage receives
a fully-configured BlogApiClient (which holds a YavscApiClient, which
holds a TokenStore) at construction. The duplicate LoginAsync method
on MainPageViewModel is gone; the LoginPage is the single entry point
for the interactive PKCE flow.

PlatformBootstrap.Desktop no longer overrides the redirect URI to
loopback. PostIt runs the postit://callback custom scheme
(SingleInstance hand-off) as the production path on desktop; the
loopback constant stays for tests and for platforms that cannot
register a custom scheme.

Settings.cs: DefaultLoopbackRedirectUri is now documented as a
fallback; DefaultDesktopRedirectUri ('postit://callback') is
introduced as the canonical desktop default.

TokenStore.Load() tolerates an empty file (returns null) so
first-launch races and stubbed test fixtures don't blow up the
constructor.

YavscApiClient:
- HasValidSession is exposed for warm-start UI logic.
- CurrentAccessToken / CurrentIdToken are exposed so the LoginPage
  ViewModel can mirror the result onto its observable properties.
- CallAsync<T> is now virtual (and the class is no longer sealed)
  to allow stubbing in PostItViewModelTests.

Tests (PostIt.Tests):
- YavscApiClientTests covers the silent refresh path (cache the
  token, mark it expired, observe a new Bearer in the API server),
  the 401 → refresh → retry path (forceFirstRequest on the stub),
  HasValidSession after login, and the throw-when-no-token guard.
- OidcStubAuthority now mints a refresh_token in the token response
  so YavscApiClient.RefreshTokenAsync can hit /connect/token in
  tests.
- PostItViewModelTests uses a ThrowingYavscApiClient / StubYavscApiClient
  pair instead of the old HttpClient injection point, matching the
  new constructor shape.

dotnet test: 21/21 green. dotnet build: 0 errors.
2026-06-23 21:25:17 +01:00