mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-09-14 06:10:28 -04:00
The staleness window was unsound. calculateAuthHash() keys the hash to the clock hour it was minted in and getAuthUser() accepts the last ZM_AUTH_HASH_TTL hourly buckets, so a hash dies at the top of an hour rather than at some age. generateAuthHash() then serves the cached one until it is half a TTL old, so what arrives can already be nearly spent: on the defaults a hash minted at 10:59 is still handed out at 11:58 and is refused at 12:00. A client stamping that arrival as fresh for an hour skips the probe until 12:58 and restarts its streams on a dead hash - the exact failure this was written to prevent. No fixed window is safe, because the remaining life of a hash we hold can be anything down to zero, and AUTH_STALE_MS also ignored the configured ZM_AUTH_HASH_TTL. So drop AUTH_STALE_MS, authIsStale() and authFreshAt, and have whenAuthFresh() revalidate. The one case that can still skip the probe is having no hash at all - authentication off, or a relay form that does not use one - where there is nothing that can expire and nothing a probe would report. revalidateAuth() already shares one request between concurrent callers, so a resume that wakes several of these still costs a single probe, and that is what the montage code did unconditionally before any of this. refreshTablesPendingVisibility() now returns as soon as it finds nothing was deferred. It is bound on every classic page including the unauthenticated ones, and the version before this ran the whole auth path on an empty queue, so merely becoming visible could fire a probe with no work behind it. Tests: two authIsStale cases removed with the function, two whenAuthFresh cases added - a probe is sent and the callback held until it answers, and no probe is sent when there is no hash. Reintroducing a fast path fails the first. Full JS suite green, ESLint clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkQwahn9pi1y4wJe9BTxjM