Prose and hunks, sitting in a tree.
Each chapter weaves together the prose explanation with the actual diff hunks it's talking about — interleaved, not separated. Read the story, see the code in the same breath, and never lose the plot.
toSignableString — the HMAC now operates on raw bytes
high risk Mark reviewed Before: computeSignature
always called
JSON.stringify(payload)
before computing the HMAC — even when the caller had the exact bytes the server originally signed. Any
semantically-equivalent-but-bytewise-different JSON (whitespace, key order, unicode escapes) would produce a
valid signature, opening a window for byte-level mutation.
Now: toSignableString
dispatches on the runtime type: strings and binary buffers pass through as-is (decoded to UTF-8 for buffers), and only
plain objects fall back to JSON.stringify. The HMAC is computed over whatever
toSignableString returns.
This is the highest-risk hunk in the PR: it changes what bytes are fed into the cryptographic signature. Dad would like you to give this one a real look.
The new toSignableString helper is a pure function with straightforward branching. Note the fallthrough: anything that isn't a string, Uint8Array, or ArrayBuffer gets JSON.stringify'd — including null, undefined, numbers, or any other unexpected type. This is the legacy back-compat path. Heads up: callers who accidentally pass a non-buffer, non-string value get silent behavior rather than an error.