Two regressions surfaced when running the suite (9 + 3 errors):
- setDb(DatabaseHandler) rejects the SQLite double: the DatabaseAware
refactor gave setDb() a strict DatabaseHandler hint, but TestDb was a
standalone class. Make TestDb extend DatabaseHandler (a real subtype) so
it satisfies the seam; its own constructor wires sqlite::memory: and never
calls the MySQL-connecting parent constructor. Overridden methods widen
parameter types (contravariant) and add return types, so LSP holds.
- validateHMAC(int|string $rExpiry) rejects null: HmacTokenTest passed null
for an intentionally-empty expiry. Pass '' — identical HMAC input, and the
strict type stays correct (the sole production caller always passes a value).
Suite is green again: 580 tests, 0 errors.
validateHMAC accepted a link when md5($genuine) == md5($given). PHP's loose
== reads two digests of the form 0e<digits> as the number 0 and so as equal:
for any request whose genuine HMAC has such an MD5 (about one in 3·10^8,
over parameters the requester chooses — identifier, expiry, max), a given
`hmac` like 240610708 passed as the key, and the stream was served under
that key's connection limits. The regression test carries a concrete case
found by search.
The HMAC is now compared with hash_equals against the given value itself.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EuZvjFSdodqgpyXtaoH1Xt