Resolve all high-severity architecture review findings

This commit is contained in:
Joseph Doherty
2026-09-09 16:13:58 -04:00
parent 8bfe65512e
commit 146a13238f
192 changed files with 3160 additions and 753 deletions
@@ -2,28 +2,11 @@
@inject NavigationManager Navigation
@inject IJSRuntime JS
<AntiforgeryToken />
@code {
// CentralUI-005 / CentralUI-020: session expiry is a sliding window owned by
// the cookie authentication middleware (ZB.MOM.WW.ScadaBridge.Security AddCookie:
// ExpireTimeSpan = idle timeout, SlidingExpiration = true). An active user's
// cookie is continually renewed; an idle user's cookie lapses after the idle
// timeout. There is no fixed login-time deadline to redirect at.
//
// This component must NOT poll the Blazor AuthenticationStateProvider:
// CookieAuthenticationStateProvider serves a frozen constructor-time
// principal for the whole circuit (CentralUI-004), so the polled auth state
// can never transition to "expired" and the redirect would never fire
// (CentralUI-020).
//
// Instead it polls the server endpoint GET /auth/ping via fetch(). Being a
// normal HTTP request, the cookie middleware re-validates — and slides — the
// cookie on every hit, and answers 200 while the session is live or 401 once
// it has lapsed. A genuine idle user's circuit produces no other HTTP
// traffic, so once the cookie lapses the next ping returns 401 and this
// component redirects to /login. (The ping itself slides the cookie, but the
// poll interval is well under the idle timeout, so an idle session still
// lapses on schedule once the poll catches the lapsed state — the ping only
// ever observes expiry, it does not keep a dead session alive.)
// Passive HTTP probes observe expiry but never advance activity. The JS module
// separately reports trusted browser input through an antiforgery-protected POST.
/// <summary>Server endpoint that reports live session validity.</summary>
internal const string PingUrl = "/auth/ping";
@@ -49,6 +32,14 @@
_ = PollSessionAsync(_cts.Token);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender || IsOnLoginPage) return;
try { _module ??= await JS.InvokeAsync<IJSObjectReference>("import", ModulePath); }
catch (JSDisconnectedException) { }
catch (JSException) { }
}
private bool IsOnLoginPage =>
Navigation.ToBaseRelativePath(Navigation.Uri)
.StartsWith("login", StringComparison.OrdinalIgnoreCase);