ba760047ce
Deploy Indiekit Server / deploy (push) Successful in 1m29s
- rawContent extraction now handles normalized {html,text} object (content is
already normalized by the time the guard runs, so String({...}) was '[object Object]')
- IndiekitError constructor is (message, options) not (status, message) — was
passing 422 as message causing error.message=422 (number) which crashed the
Nunjucks error template with 'Input data should be a String'
71 lines
2.5 KiB
JavaScript
71 lines
2.5 KiB
JavaScript
/**
|
|
* Patch: swarm-loc-guard
|
|
*
|
|
* Only accept OwnYourSwarm Micropub posts that contain the text "Loc"
|
|
* in their content. Check-ins without "Loc" are rejected with 422.
|
|
*
|
|
* Workflow: Sven adds "Loc" to Swarm check-ins he wants published.
|
|
* Check-ins without that text (stealth, accidental, no-content) are rejected.
|
|
*/
|
|
|
|
import { readFile, writeFile, access } from "node:fs/promises";
|
|
|
|
const MARKER = "// [patch] swarm-loc-guard";
|
|
|
|
const candidates = [
|
|
"node_modules/@indiekit/endpoint-micropub/lib/post-data.js",
|
|
"node_modules/@indiekit/indiekit/node_modules/@indiekit/endpoint-micropub/lib/post-data.js",
|
|
];
|
|
|
|
const oldSnippet = ` if (
|
|
type === "note" &&
|
|
(hasCheckinProperty || hasSwarmSyndication)
|
|
) {
|
|
properties.visibility = "unlisted";
|
|
}`;
|
|
|
|
const newSnippet = ` if (
|
|
type === "note" &&
|
|
(hasCheckinProperty || hasSwarmSyndication)
|
|
) {
|
|
// Guard: only accept OwnYourSwarm posts that contain "Loc" in content. ${MARKER}
|
|
// Extract raw text before normaliseProperties converts content to {html,text} object.
|
|
// After normalisation, String(properties.content) yields "[object Object]" — not useful.
|
|
// We read .text/.html from the normalised object, then fall back to raw string.
|
|
const rawContent = (() => {
|
|
const c = properties.content;
|
|
if (!c) return "";
|
|
if (typeof c === "string") return c;
|
|
if (typeof c === "object") return String(c.text || c.html || "");
|
|
return String(c);
|
|
})();
|
|
if (hasSwarmSyndication && !rawContent.includes("Loc")) {
|
|
throw new IndiekitError("OwnYourSwarm post without 'Loc' in content rejected", { status: 422, code: "invalid_request" });
|
|
}
|
|
properties.visibility = "unlisted";
|
|
}`;
|
|
|
|
async function exists(path) {
|
|
try { await access(path); return true; } catch { return false; }
|
|
}
|
|
|
|
let patched = 0;
|
|
for (const filePath of candidates) {
|
|
if (!(await exists(filePath))) continue;
|
|
const source = await readFile(filePath, "utf8");
|
|
if (source.includes(MARKER)) {
|
|
console.log(`[postinstall] swarm-loc-guard: already patched (${filePath})`);
|
|
continue;
|
|
}
|
|
if (!source.includes(oldSnippet)) {
|
|
console.log(`[postinstall] swarm-loc-guard: target snippet not found in ${filePath} — skipping`);
|
|
continue;
|
|
}
|
|
await writeFile(filePath, source.replace(oldSnippet, newSnippet), "utf8");
|
|
console.log(`[postinstall] swarm-loc-guard: patched ${filePath}`);
|
|
patched++;
|
|
}
|
|
if (patched === 0) {
|
|
console.log("[postinstall] swarm-loc-guard: nothing patched");
|
|
}
|