Skip to main content

max / makenotwork

multithreaded: upgrade sha2 to 0.11 and hmac to 0.13 The two move together — hmac 0.12 is pinned to digest 0.10. The only API break is new_from_slice, which moved from Mac to KeyInit, so KeyInit now has to be in scope at both call sites. The internal request signature is a cross-repo contract (the MNW server signs, this verifies), and every existing test only checks it agrees with itself. Pin it against an independent HMAC-SHA256 of the documented message layout so a hasher swap has to reproduce a fixed string. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-22 00:41 UTC
Commit: 6d28b848660e596bdc8a4ce0b3c579ee3a5d4e3a
Parent: fb66fe9
4 files changed, +19 insertions, -6 deletions
@@ -2243,7 +2243,7 @@ dependencies = [
2243 2243 "dotenvy",
2244 2244 "governor",
2245 2245 "hex",
2246 - "hmac 0.12.1",
2246 + "hmac 0.13.0",
2247 2247 "http-body-util",
2248 2248 "mt-core",
2249 2249 "mt-db",
@@ -2255,7 +2255,7 @@ dependencies = [
2255 2255 "s3-storage",
2256 2256 "serde",
2257 2257 "serde_json",
2258 - "sha2 0.10.9",
2258 + "sha2 0.11.0",
2259 2259 "sqlx",
2260 2260 "tagtree",
2261 2261 "time",
@@ -33,8 +33,8 @@ reqwest = { version = "0.13", default-features = false, features = ["json", "rus
33 33 # Pinned to the exact major reqwest resolves so the SSRF pre-check parses the
34 34 # host with the same parser reqwest connects through (link_preview::validate_url).
35 35 url = "2"
36 - sha2 = "0.10"
37 - hmac = "0.12"
36 + sha2 = "0.11"
37 + hmac = "0.13"
38 38 base64 = "0.22"
39 39 rand = "0.10"
40 40
@@ -22,7 +22,7 @@ use axum::{
22 22 http::StatusCode,
23 23 response::{IntoResponse, Response},
24 24 };
25 - use hmac::{Hmac, Mac};
25 + use hmac::{Hmac, KeyInit, Mac};
26 26 use sha2::Sha256;
27 27
28 28 use crate::AppState;
@@ -267,6 +267,19 @@ mod tests {
267 267 }
268 268
269 269 #[test]
270 + fn signature_matches_the_reference_hmac() {
271 + // The signer lives in the MNW server and the verifier lives here, so
272 + // the exact bytes are a cross-repo contract that no test in either
273 + // repo can catch by agreeing with itself. Pinned against an
274 + // independent HMAC-SHA256 over the documented message layout:
275 + // key "secret", message "100\nPOST\n/x\nn\nbody".
276 + assert_eq!(
277 + v2("secret", "100", "POST", "/x", "n", b"body"),
278 + "0e97f90cb4e4ca7aaa5499e67a22fb5b7ad45ad3cc966f37d225f39da2728098"
279 + );
280 + }
281 +
282 + #[test]
270 283 fn signature_changes_with_secret() {
271 284 // Pins that the secret feeds into the MAC key.
272 285 assert_ne!(
@@ -4,7 +4,7 @@ use axum::Router;
4 4 use axum::body::Body;
5 5 use axum::extract::ConnectInfo;
6 6 use axum::http::{Method, Request, StatusCode};
7 - use hmac::{Hmac, Mac};
7 + use hmac::{Hmac, KeyInit, Mac};
8 8 use http_body_util::BodyExt;
9 9 use sha2::Sha256;
10 10 use sqlx::PgPool;