diff --git a/index.js b/index.js index a2e5331..37cb6b1 100644 --- a/index.js +++ b/index.js @@ -87,6 +87,30 @@ export default class ActivityPubEndpoint { return self._fedifyMiddleware(req, res, next); }); + // Catch-all for federation paths that Fedify didn't handle (e.g. GET + // on inbox). Without this, they fall through to Indiekit's auth + // middleware and redirect to the login page. + router.all("/users/:identifier/inbox", (req, res) => { + res + .status(405) + .set("Allow", "POST") + .type("application/activity+json") + .json({ + error: "Method Not Allowed", + message: "The inbox only accepts POST requests", + }); + }); + router.all("/inbox", (req, res) => { + res + .status(405) + .set("Allow", "POST") + .type("application/activity+json") + .json({ + error: "Method Not Allowed", + message: "The shared inbox only accepts POST requests", + }); + }); + return router; } diff --git a/lib/inbox-listeners.js b/lib/inbox-listeners.js index e3dd477..7db8ea2 100644 --- a/lib/inbox-listeners.js +++ b/lib/inbox-listeners.js @@ -7,14 +7,18 @@ import { Accept, + Add, Announce, + Block, Create, Delete, Follow, Like, Move, Note, + Remove, Undo, + Update, } from "@fedify/fedify"; /** @@ -201,6 +205,46 @@ export function registerInboxListeners(inboxChain, options) { objectUrl: newActorUrl, summary: `${oldActorUrl} moved to ${newActorUrl}`, }); + }) + .on(Update, async (ctx, update) => { + // Remote actor updated their profile — refresh stored follower data + const actorObj = await update.getActor(); + const actorUrl = actorObj?.id?.href || ""; + if (!actorUrl) return; + + const existing = await collections.ap_followers.findOne({ actorUrl }); + if (existing) { + await collections.ap_followers.updateOne( + { actorUrl }, + { + $set: { + name: + actorObj.name?.toString() || + actorObj.preferredUsername?.toString() || + actorUrl, + handle: actorObj.preferredUsername?.toString() || "", + avatar: actorObj.icon + ? (await actorObj.icon)?.url?.href || "" + : "", + updatedAt: new Date().toISOString(), + }, + }, + ); + } + }) + .on(Block, async (ctx, block) => { + // Remote actor blocked us — remove them from followers + const actorObj = await block.getActor(); + const actorUrl = actorObj?.id?.href || ""; + if (actorUrl) { + await collections.ap_followers.deleteOne({ actorUrl }); + } + }) + .on(Add, async () => { + // Mastodon uses Add for pinning posts to featured collections — safe to ignore + }) + .on(Remove, async () => { + // Mastodon uses Remove for unpinning posts from featured collections — safe to ignore }); } diff --git a/package.json b/package.json index a7d4793..887ed39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "1.0.0", + "version": "1.0.1", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit",