fix(patches): restore lost AP patches and fix broken patch chain
The signatureTimeWindow patch was deleted ine52e98c5c(assumed fixed in fork), but the lockfile still pins the fork to v2.10.1 which lacks it. This broke the patch-ap-allow-private-address patch chain: it expected signatureTimeWindow in its OLD_SNIPPET, never matched, and silently skipped — leaving the server without both signatureTimeWindow AND allowPrivateAddress. Without allowPrivateAddress, Fedify's SSRF guard blocks own-site URL resolution (blog.giersig.eu → 10.100.0.10), breaking federation delivery. - Fix patch-ap-allow-private-address to handle fresh v2.10.1 (adds both signatureTimeWindow and allowPrivateAddress in one step) - Restore patch-ap-object-url-trailing-slash (also lost ine52e98c5c) - Add both patches to postinstall and serve scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -4,8 +4,8 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "xattr -w com.apple.fileprovider.ignore#P 1 node_modules 2>/dev/null || true && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-endpoint-posts-prefill-url.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-endpoint-posts-search-tags.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-ap-url-lookup-api.mjs && node scripts/patch-ap-allow-private-address.mjs && node scripts/patch-inbox-skip-view-activity-parse.mjs && node scripts/patch-inbox-ignore-view-activity.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-ap-normalize-nested-tags.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs",
|
"postinstall": "xattr -w com.apple.fileprovider.ignore#P 1 node_modules 2>/dev/null || true && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-endpoint-posts-prefill-url.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-endpoint-posts-search-tags.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-ap-url-lookup-api.mjs && node scripts/patch-ap-object-url-trailing-slash.mjs && node scripts/patch-ap-allow-private-address.mjs && node scripts/patch-inbox-skip-view-activity-parse.mjs && node scripts/patch-inbox-ignore-view-activity.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-ap-normalize-nested-tags.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs",
|
||||||
"serve": "export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-endpoint-posts-prefill-url.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-endpoint-posts-search-tags.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-ap-url-lookup-api.mjs && node scripts/patch-ap-allow-private-address.mjs && node scripts/patch-inbox-skip-view-activity-parse.mjs && node scripts/patch-inbox-ignore-view-activity.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-ap-normalize-nested-tags.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
|
"serve": "export NODE_ENV=${NODE_ENV:-production} INDIEKIT_DEBUG=${INDIEKIT_DEBUG:-0} && node scripts/preflight-production-security.mjs && node scripts/preflight-mongo-connection.mjs && node scripts/preflight-activitypub-rsa-key.mjs && node scripts/preflight-activitypub-profile-urls.mjs && node scripts/patch-lightningcss.mjs && node scripts/patch-endpoint-media-scope.mjs && node scripts/patch-endpoint-media-sharp-runtime.mjs && node scripts/patch-frontend-sharp-runtime.mjs && node scripts/patch-endpoint-files-upload-route.mjs && node scripts/patch-endpoint-files-upload-locales.mjs && node scripts/patch-endpoint-activitypub-locales.mjs && node scripts/patch-endpoint-homepage-locales.mjs && node scripts/patch-endpoint-homepage-identity-defaults.mjs && node scripts/patch-federation-unlisted-guards.mjs && node scripts/patch-endpoint-micropub-where-note-visibility.mjs && node scripts/patch-endpoint-posts-ai-fields.mjs && node scripts/patch-endpoint-posts-ai-cleanup.mjs && node scripts/patch-endpoint-podroll-opml-upload.mjs && node scripts/patch-preset-eleventy-ai-frontmatter.mjs && node scripts/patch-micropub-ai-block-resync.mjs && node scripts/patch-frontend-serviceworker-file.mjs && node scripts/patch-endpoint-comments-locales.mjs && node scripts/patch-endpoint-posts-locales.mjs && node scripts/patch-endpoint-conversations-locales.mjs && node scripts/patch-conversations-collection-guards.mjs && node scripts/patch-indiekit-routes-rate-limits.mjs && node scripts/patch-indiekit-error-production-stack.mjs && node scripts/patch-indieauth-devmode-guard.mjs && node scripts/patch-listening-endpoint-runtime-guards.mjs && node scripts/patch-endpoint-github-changelog-categories.mjs && node scripts/patch-microsub-reader-ap-dispatch.mjs && node scripts/patch-endpoint-blogroll-feeds-alias.mjs && node scripts/patch-endpoint-posts-uid-lookup.mjs && node scripts/patch-endpoint-posts-prefill-url.mjs && node scripts/patch-conversations-bluesky-self-filter.mjs && node scripts/patch-conversations-bluesky-cursor-fix.mjs && node scripts/patch-endpoint-micropub-source-filter.mjs && node scripts/patch-endpoint-posts-search-tags.mjs && node scripts/patch-syndicate-force-checked-default.mjs && node scripts/patch-ap-url-lookup-api.mjs && node scripts/patch-ap-object-url-trailing-slash.mjs && node scripts/patch-ap-allow-private-address.mjs && node scripts/patch-inbox-skip-view-activity-parse.mjs && node scripts/patch-inbox-ignore-view-activity.mjs && node scripts/patch-endpoint-posts-fetch-diagnostic.mjs && node scripts/patch-micropub-fetch-internal-url.mjs && node scripts/patch-ap-normalize-nested-tags.mjs && node scripts/patch-webmention-sender-retry.mjs && node scripts/patch-webmention-sender-livefetch.mjs && node scripts/patch-webmention-sender-empty-details.mjs && node scripts/patch-bluesky-syndicator-internal-url.mjs && node node_modules/@indiekit/indiekit/bin/cli.js serve --config indiekit.config.mjs",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
|||||||
@@ -32,16 +32,19 @@ const candidates = [
|
|||||||
|
|
||||||
const MARKER = "// allow private address fix";
|
const MARKER = "// allow private address fix";
|
||||||
|
|
||||||
const OLD_SNIPPET = ` const federation = createFederation({
|
const patchSpecs = [
|
||||||
|
// Case 1: signatureTimeWindow already present (from old patch or fork)
|
||||||
|
{
|
||||||
|
name: "with-signature-time-window",
|
||||||
|
oldSnippet: ` const federation = createFederation({
|
||||||
kv,
|
kv,
|
||||||
queue,
|
queue,
|
||||||
// Accept signatures up to 12 h old. // signature time window fix
|
// Accept signatures up to 12 h old. // signature time window fix
|
||||||
// Mastodon retries failed deliveries with the original signature, which
|
// Mastodon retries failed deliveries with the original signature, which
|
||||||
// can be hours old by the time the delivery succeeds.
|
// can be hours old by the time the delivery succeeds.
|
||||||
signatureTimeWindow: { hours: 12 },
|
signatureTimeWindow: { hours: 12 },
|
||||||
});`;
|
});`,
|
||||||
|
newSnippet: ` const federation = createFederation({
|
||||||
const NEW_SNIPPET = ` const federation = createFederation({
|
|
||||||
kv,
|
kv,
|
||||||
queue,
|
queue,
|
||||||
// Accept signatures up to 12 h old. // signature time window fix
|
// Accept signatures up to 12 h old. // signature time window fix
|
||||||
@@ -52,7 +55,29 @@ const NEW_SNIPPET = ` const federation = createFederation({
|
|||||||
// blog.giersig.eu resolves to 10.100.0.10 on the home LAN. Without this,
|
// blog.giersig.eu resolves to 10.100.0.10 on the home LAN. Without this,
|
||||||
// Fedify's SSRF guard blocks lookupObject() / WebFinger for own posts.
|
// Fedify's SSRF guard blocks lookupObject() / WebFinger for own posts.
|
||||||
allowPrivateAddress: true,
|
allowPrivateAddress: true,
|
||||||
});`;
|
});`,
|
||||||
|
},
|
||||||
|
// Case 2: fresh v2.10.1 without signatureTimeWindow — add both
|
||||||
|
{
|
||||||
|
name: "fresh-without-signature-time-window",
|
||||||
|
oldSnippet: ` const federation = createFederation({
|
||||||
|
kv,
|
||||||
|
queue,
|
||||||
|
});`,
|
||||||
|
newSnippet: ` const federation = createFederation({
|
||||||
|
kv,
|
||||||
|
queue,
|
||||||
|
// Accept signatures up to 12 h old. // signature time window fix
|
||||||
|
// Mastodon retries failed deliveries with the original signature, which
|
||||||
|
// can be hours old by the time the delivery succeeds.
|
||||||
|
signatureTimeWindow: { hours: 12 },
|
||||||
|
// Allow fetching own-site URLs that resolve to private IPs. // allow private address fix
|
||||||
|
// blog.giersig.eu resolves to 10.100.0.10 on the home LAN. Without this,
|
||||||
|
// Fedify's SSRF guard blocks lookupObject() / WebFinger for own posts.
|
||||||
|
allowPrivateAddress: true,
|
||||||
|
});`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
async function exists(filePath) {
|
async function exists(filePath) {
|
||||||
try {
|
try {
|
||||||
@@ -72,26 +97,27 @@ for (const filePath of candidates) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checked += 1;
|
checked += 1;
|
||||||
const source = await readFile(filePath, "utf8");
|
let source = await readFile(filePath, "utf8");
|
||||||
|
|
||||||
if (source.includes(MARKER) || source.includes("allowPrivateAddress")) {
|
if (source.includes(MARKER) || source.includes("allowPrivateAddress")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!source.includes(OLD_SNIPPET)) {
|
let applied = false;
|
||||||
console.log(`[postinstall] patch-ap-allow-private-address: snippet not found in ${filePath} — skipping`);
|
for (const spec of patchSpecs) {
|
||||||
continue;
|
if (!source.includes(spec.oldSnippet)) continue;
|
||||||
}
|
const updated = source.replace(spec.oldSnippet, spec.newSnippet);
|
||||||
|
if (updated === source) continue;
|
||||||
const updated = source.replace(OLD_SNIPPET, NEW_SNIPPET);
|
|
||||||
|
|
||||||
if (updated === source) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeFile(filePath, updated, "utf8");
|
await writeFile(filePath, updated, "utf8");
|
||||||
patched += 1;
|
patched += 1;
|
||||||
console.log(`[postinstall] Applied patch-ap-allow-private-address to ${filePath}`);
|
applied = true;
|
||||||
|
console.log(`[postinstall] Applied patch-ap-allow-private-address (${spec.name}) to ${filePath}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!applied) {
|
||||||
|
console.log(`[postinstall] patch-ap-allow-private-address: no matching snippet in ${filePath} — skipping`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checked === 0) {
|
if (checked === 0) {
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Patch: make the Fedify object dispatcher's post lookup tolerate trailing-slash
|
||||||
|
* differences between the AP object URL and the stored post URL.
|
||||||
|
*
|
||||||
|
* Root cause:
|
||||||
|
* setupObjectDispatchers resolvePost() builds postUrl from the {+id} template
|
||||||
|
* variable (e.g. "replies/bd78a") and does an exact findOne() match against
|
||||||
|
* posts.properties.url. Posts in MongoDB are stored with a trailing slash
|
||||||
|
* ("https://blog.giersig.eu/replies/bd78a/"), but the AP object URL returned
|
||||||
|
* by the /api/ap-url lookup endpoint has no trailing slash. The exact match
|
||||||
|
* fails → Fedify returns 404 → remote instance shows "Could not connect".
|
||||||
|
*
|
||||||
|
* Fix:
|
||||||
|
* Replace the single-value findOne() with a $in query that tries both the
|
||||||
|
* bare URL and the URL with a trailing slash appended.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { access, readFile, writeFile } from "node:fs/promises";
|
||||||
|
|
||||||
|
const candidates = [
|
||||||
|
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
||||||
|
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
||||||
|
];
|
||||||
|
|
||||||
|
const MARKER = "// trailing-slash url fix";
|
||||||
|
|
||||||
|
const OLD_SNIPPET = ` const postUrl = \`\${publicationUrl.replace(/\\/$/, "")}/\${id}\`;
|
||||||
|
const post = await collections.posts.findOne({ "properties.url": postUrl });`;
|
||||||
|
|
||||||
|
const NEW_SNIPPET = ` const postUrl = \`\${publicationUrl.replace(/\\/$/, "")}/\${id}\`; // trailing-slash url fix
|
||||||
|
const post = await collections.posts.findOne({
|
||||||
|
"properties.url": { $in: [postUrl, postUrl + "/"] },
|
||||||
|
});`;
|
||||||
|
|
||||||
|
async function exists(filePath) {
|
||||||
|
try {
|
||||||
|
await access(filePath);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let checked = 0;
|
||||||
|
let patched = 0;
|
||||||
|
|
||||||
|
for (const filePath of candidates) {
|
||||||
|
if (!(await exists(filePath))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
checked += 1;
|
||||||
|
const source = await readFile(filePath, "utf8");
|
||||||
|
|
||||||
|
if (source.includes(MARKER)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!source.includes(OLD_SNIPPET)) {
|
||||||
|
console.log(`[postinstall] patch-ap-object-url-trailing-slash: snippet not found in ${filePath}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = source.replace(OLD_SNIPPET, NEW_SNIPPET);
|
||||||
|
|
||||||
|
if (updated === source) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeFile(filePath, updated, "utf8");
|
||||||
|
patched += 1;
|
||||||
|
console.log(`[postinstall] Applied patch-ap-object-url-trailing-slash to ${filePath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checked === 0) {
|
||||||
|
console.log("[postinstall] patch-ap-object-url-trailing-slash: no target files found");
|
||||||
|
} else if (patched === 0) {
|
||||||
|
console.log("[postinstall] patch-ap-object-url-trailing-slash: already up to date");
|
||||||
|
} else {
|
||||||
|
console.log(`[postinstall] patch-ap-object-url-trailing-slash: patched ${patched}/${checked} file(s)`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user