fix(patches): preserve raw body bytes for Fedify HTTP Signature verification

The inbox View-skip patch buffers the request stream but was not saving
the original bytes as req._rawBody. Without them, fromExpressRequest
falls back to JSON.stringify(req.body) which can alter byte layout,
breaking the Digest check in Fedify's HTTP Signature verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sven
2026-03-18 18:34:02 +01:00
parent 3b5d4f1243
commit 95f42df216

View File

@@ -42,9 +42,49 @@ const patchSpecs = [
body = JSON.stringify(req.body); body = JSON.stringify(req.body);
} else if (ct.includes("application/x-www-form-urlencoded")) {`, } else if (ct.includes("application/x-www-form-urlencoded")) {`,
newSnippet: ` // PeerTube activity+json body fix newSnippet: ` // PeerTube activity+json body fix
if (ct.includes("application/json") || ct.includes("activity+json") || ct.includes("ld+json")) {
// Use original raw bytes when available (set by createFedifyMiddleware buffer guard).
// JSON.stringify() changes byte layout, breaking Fedify's HTTP Signature Digest check.
body = req._rawBody || JSON.stringify(req.body); // raw body digest fix
} else if (ct.includes("application/x-www-form-urlencoded")) {`,
},
// --- Patch 1b: upgrade fromExpressRequest to use _rawBody (fixes Digest verification) ---
// Handles files where Patch 1 was already applied but without the _rawBody fix.
{
name: "from-express-request-raw-body-fix",
marker: "req._rawBody || JSON.stringify",
oldSnippet: ` // PeerTube activity+json body fix
if (ct.includes("application/json") || ct.includes("activity+json") || ct.includes("ld+json")) { if (ct.includes("application/json") || ct.includes("activity+json") || ct.includes("ld+json")) {
body = JSON.stringify(req.body); body = JSON.stringify(req.body);
} else if (ct.includes("application/x-www-form-urlencoded")) {`, } else if (ct.includes("application/x-www-form-urlencoded")) {`,
newSnippet: ` // PeerTube activity+json body fix
if (ct.includes("application/json") || ct.includes("activity+json") || ct.includes("ld+json")) {
// Use original raw bytes when available (set by createFedifyMiddleware buffer guard).
// JSON.stringify() changes byte layout, breaking Fedify's HTTP Signature Digest check.
body = req._rawBody || JSON.stringify(req.body); // raw body digest fix
} else if (ct.includes("application/x-www-form-urlencoded")) {`,
},
// --- Patch 1c: upgrade middleware buffer guard to set _rawBody (fixes Digest verification) ---
// Handles files where Patch 2 was already applied but without the _rawBody fix.
{
name: "inbox-buffer-raw-body-fix",
marker: "req._rawBody = _raw",
oldSnippet: ` const _chunks = [];
for await (const _chunk of req) {
_chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk));
}
try {
req.body = JSON.parse(Buffer.concat(_chunks).toString("utf8"));`,
newSnippet: ` const _chunks = [];
for await (const _chunk of req) {
_chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk));
}
const _raw = Buffer.concat(_chunks); // raw body digest fix
req._rawBody = _raw; // Preserve original bytes for Fedify HTTP Signature Digest verification
try {
req.body = JSON.parse(_raw.toString("utf8"));`,
}, },
// --- Patch 2a: replace the old (broken) v1 guard with the buffering v2 guard --- // --- Patch 2a: replace the old (broken) v1 guard with the buffering v2 guard ---
@@ -78,8 +118,10 @@ const patchSpecs = [
for await (const _chunk of req) { for await (const _chunk of req) {
_chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk)); _chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk));
} }
const _raw = Buffer.concat(_chunks); // raw body digest fix
req._rawBody = _raw; // Preserve original bytes for Fedify HTTP Signature Digest verification
try { try {
req.body = JSON.parse(Buffer.concat(_chunks).toString("utf8")); req.body = JSON.parse(_raw.toString("utf8"));
} catch { } catch {
req.body = {}; req.body = {};
} }
@@ -117,8 +159,10 @@ const patchSpecs = [
for await (const _chunk of req) { for await (const _chunk of req) {
_chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk)); _chunks.push(Buffer.isBuffer(_chunk) ? _chunk : Buffer.from(_chunk));
} }
const _raw = Buffer.concat(_chunks); // raw body digest fix
req._rawBody = _raw; // Preserve original bytes for Fedify HTTP Signature Digest verification
try { try {
req.body = JSON.parse(Buffer.concat(_chunks).toString("utf8")); req.body = JSON.parse(_raw.toString("utf8"));
} catch { } catch {
req.body = {}; req.body = {};
} }