fix: add self-follow guard patch for inbox Follow handler
Deploy Indiekit Server / deploy (push) Successful in 1m23s
Deploy Indiekit Server / deploy (push) Successful in 1m23s
Prevents Fedify ECONNRESET retry loop when server follows itself via Mona. Guards inbox-listeners.js Follow handler with publicationUrl check before storing follower. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* Patch: Prevent self-follows in the inbox Follow handler.
|
||||||
|
*
|
||||||
|
* When the server follows itself (e.g. via Mona), the self-entry in
|
||||||
|
* ap_followers causes Fedify to attempt delivery to the local shared
|
||||||
|
* inbox on every sendActivity("followers") call. Since the node jail
|
||||||
|
* has no outbound internet, this produces infinite ECONNRESET retries.
|
||||||
|
*
|
||||||
|
* This patch adds an early return in the Follow listener when the
|
||||||
|
* follower's actor URL matches the server's own publicationUrl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { access, readFile, writeFile } from "node:fs/promises";
|
||||||
|
|
||||||
|
const AP_BASE = "@rmdes/indiekit-endpoint-activitypub";
|
||||||
|
const AP_ROOTS = [
|
||||||
|
`node_modules/${AP_BASE}`,
|
||||||
|
`node_modules/@indiekit/indiekit/node_modules/${AP_BASE}`,
|
||||||
|
];
|
||||||
|
|
||||||
|
function apPath(rel) {
|
||||||
|
return AP_ROOTS.map(r => `${r}/${rel}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fileExists(p) {
|
||||||
|
try { await access(p); return true; } catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applyPatch(filePath, marker, oldSnippet, newSnippet) {
|
||||||
|
if (!(await fileExists(filePath))) return "file_not_found";
|
||||||
|
const src = await readFile(filePath, "utf8");
|
||||||
|
if (src.includes(marker)) return "already_applied";
|
||||||
|
if (!src.includes(oldSnippet)) return "snippet_not_found";
|
||||||
|
await writeFile(filePath, src.replace(oldSnippet, newSnippet), "utf8");
|
||||||
|
return "applied";
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCRIPT = "patch-ap-self-follow-guard";
|
||||||
|
const MARKER = "// [patch] ap-self-follow-guard";
|
||||||
|
|
||||||
|
const PATCHES = [
|
||||||
|
{
|
||||||
|
name: "self-follow-guard",
|
||||||
|
files: apPath("lib/inbox-listeners.js"),
|
||||||
|
marker: MARKER,
|
||||||
|
oldSnippet: ` const actorUrl = follow.actorId?.href || "";
|
||||||
|
if (await isServerBlocked(actorUrl, collections)) return;
|
||||||
|
await touchKeyFreshness(collections, actorUrl);
|
||||||
|
await resetDeliveryStrikes(collections, actorUrl);`,
|
||||||
|
newSnippet: ` const actorUrl = follow.actorId?.href || "";
|
||||||
|
if (await isServerBlocked(actorUrl, collections)) return;
|
||||||
|
|
||||||
|
// Reject self-follows: if the follower is our own actor, skip. // [patch] ap-self-follow-guard
|
||||||
|
// Self-follows cause infinite delivery retries because Fedify
|
||||||
|
// tries to POST to our own shared inbox, which is unreachable
|
||||||
|
// from within the jail (no outbound internet).
|
||||||
|
if (collections._publicationUrl && actorUrl.startsWith(collections._publicationUrl)) {
|
||||||
|
console.info(\`[ActivityPub] Ignoring self-follow from \${actorUrl}\`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await touchKeyFreshness(collections, actorUrl);
|
||||||
|
await resetDeliveryStrikes(collections, actorUrl);`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let total = 0;
|
||||||
|
for (const p of PATCHES) {
|
||||||
|
let done = false;
|
||||||
|
for (const f of p.files) {
|
||||||
|
const r = await applyPatch(f, p.marker, p.oldSnippet, p.newSnippet);
|
||||||
|
if (r === "applied") {
|
||||||
|
console.log(`[postinstall] ${SCRIPT}: applied ${p.name} to ${f}`);
|
||||||
|
total++; done = true; break;
|
||||||
|
} else if (r === "already_applied") {
|
||||||
|
console.log(`[postinstall] ${SCRIPT}: ${p.name} already applied in ${f}`);
|
||||||
|
done = true; break;
|
||||||
|
} else if (r === "snippet_not_found") {
|
||||||
|
console.warn(`[postinstall] ${SCRIPT}: ${p.name} — snippet not found in ${f}, skipping`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!done) console.log(`[postinstall] ${SCRIPT}: ${p.name} — no target file found`);
|
||||||
|
}
|
||||||
|
console.log(`[postinstall] ${SCRIPT}: done (${total} patch(es) applied)`);
|
||||||
Reference in New Issue
Block a user