ReplayGuard
in package
NEW-4 (CONTRACT.md §8 "v2 — Replay Protection", hard cutover) validation gates, checked ONLY AFTER a delivery's HMAC signature has already verified (see Hmac::verify / Consumer::verifyAndDispatch).
Because Hmac::verify re-serializes the parsed body (minus
hmac_signature) in its original insertion order, nonce and
issued_at are already covered by the verified HMAC bytes — this class
adds no canonicalization logic of its own. It only enforces the three
ADDITIONAL gates the server also enforces (crates/axiam-amqp/src/messages.rs):
(a) key_version must be >= self::MIN_KEY_VERSION (2) — a v1
message (no replay protection fields) is rejected outright, no
grace window.
(b) issued_at (RFC3339/ISO8601 UTC) must lie within ±skew of "now".
(c) nonce must not have been seen before within the dedup window.
The nonce dedup store is a plain in-memory nonce => expiry map with a
TTL of 2×skew: a nonce cannot legitimately recur once its message has
aged out of the ±skew freshness window, so entries older than 2×skew are
pruned opportunistically on every check — bounded memory, no background
process. This is a defense-in-depth client-side check only (resets on
process restart); the server maintains the durable, cross-process nonce
store.
ONE instance MUST be shared across every delivery handled by a given Consumer (see Consumer::__construct) — a fresh guard per message would defeat replay dedup entirely.
Table of Contents
Constants
- DEFAULT_SKEW_SECONDS : mixed = 300
- Default freshness window (seconds) applied to `issued_at`, matching the server's DEFAULT_FRESHNESS_SKEW_SECS = 300 / AXIAM__AMQP__REPLAY_SKEW_SECS (CONTRACT.md §8 v2).
- MIN_KEY_VERSION : mixed = 2
- The lowest AMQP signed-envelope key_version this SDK will accept (NEW-4). A message with key_version below this predates the mandatory nonce/issued_at replay-protection fields and is rejected outright — a hard cutover, there is no v1 grace path (mirrors crates/axiam-amqp/src/messages.rs MIN_ACCEPTED_KEY_VERSION).
Methods
- __construct() : mixed
- check() : string|null
- Validates $message (the decoded body, `hmac_signature` already removed, HMAC already verified by the caller) against the NEW-4 replay-protection policy.
- trackedNonceCount() : int
Constants
DEFAULT_SKEW_SECONDS
Default freshness window (seconds) applied to `issued_at`, matching the server's DEFAULT_FRESHNESS_SKEW_SECS = 300 / AXIAM__AMQP__REPLAY_SKEW_SECS (CONTRACT.md §8 v2).
public
mixed
DEFAULT_SKEW_SECONDS
= 300
MIN_KEY_VERSION
The lowest AMQP signed-envelope key_version this SDK will accept (NEW-4). A message with key_version below this predates the mandatory nonce/issued_at replay-protection fields and is rejected outright — a hard cutover, there is no v1 grace path (mirrors crates/axiam-amqp/src/messages.rs MIN_ACCEPTED_KEY_VERSION).
public
mixed
MIN_KEY_VERSION
= 2
Methods
__construct()
public
__construct([int $skewSeconds = self::DEFAULT_SKEW_SECONDS ][, callable(): int|null $clock = null ]) : mixed
Parameters
- $skewSeconds : int = self::DEFAULT_SKEW_SECONDS
-
Freshness window (seconds) for
issued_at; also sets the nonce dedup TTL (2×skewSeconds). Must be > 0. - $clock : callable(): int|null = null
-
Overridable "now" source (unix timestamp), for deterministic tests. Defaults to
time().
check()
Validates $message (the decoded body, `hmac_signature` already removed, HMAC already verified by the caller) against the NEW-4 replay-protection policy.
public
check(array<string, mixed> $message) : string|null
Returns null iff all three gates pass, in which case nonce has also
been recorded (so a second delivery of the same nonce is rejected as
a replay). Otherwise returns the name of the first failing gate
('key_version', 'issued_at', or 'nonce') — callers treat any non-null
result identically (nack without requeue, security event logged,
handler never invoked); the string is for logging/debugging only.
Parameters
- $message : array<string, mixed>
Return values
string|nulltrackedNonceCount()
public
trackedNonceCount() : int
Return values
int —Number of nonces currently tracked (test/introspection helper).