Files
indiekit-endpoint-activitypub/lib/controllers/authorize-interaction.js
Ricardo 35ab840a56 feat: upgrade Fedify to 2.1.0 + implement 5 FEPs
Fedify 2.1.0 upgrade:
- Upgrade @fedify/fedify, @fedify/redis, @fedify/debugger to ^2.1.0
- Remove as:Endpoints type-stripping workaround (fixed upstream, fedify#576)
- Wire onUnverifiedActivity handler for Delete from actors with gone keys

FEP implementations:
- FEP-5feb: Add indexable + discoverable to actor (search indexing consent)
- FEP-f1d5/0151: Enrich NodeInfo 2.1 with metadata, staff accounts, repo info
- FEP-4f05: Soft delete with Tombstone — deleted posts serve 410 + Tombstone
  JSON-LD with formerType, published, deleted timestamps. New ap_tombstones
  collection + lib/storage/tombstones.js
- FEP-3b86: Activity Intents — WebFinger links for Follow/Create/Like/Announce
  intents, authorize_interaction routes by intent parameter
- FEP-8fcf: Collection Sync outbound via Fedify syncCollection (documented
  that receiving side is not yet implemented)
2026-03-26 17:33:28 +01:00

60 lines
2.0 KiB
JavaScript

/**
* Authorize Interaction controller — handles the remote follow / authorize
* interaction flow for ActivityPub federation.
*
* Supports:
* - OStatus subscribe template (legacy remote follow via ?uri=...)
* - FEP-3b86 Activity Intents (via ?uri=...&intent=follow|create|like|announce)
*
* Flow:
* 1. Missing uri → render error page
* 2. Unauthenticated → redirect to login, then back here
* 3. Authenticated → route to appropriate page based on intent
*/
export function authorizeInteractionController(plugin) {
return async (req, res) => {
const uri = req.query.uri || req.query.acct;
const intent = req.query.intent || "";
if (!uri) {
return res.status(400).render("activitypub-authorize-interaction", {
title: "Authorize Interaction",
mountPath: plugin.options.mountPath,
error: "Missing uri parameter",
});
}
// Clean up acct: prefix if present
const resource = uri.replace(/^acct:/, "");
// Check authentication — if not logged in, redirect to login
// then back to this page after auth
const session = req.session;
if (!session?.access_token) {
const params = `uri=${encodeURIComponent(uri)}${intent ? `&intent=${intent}` : ""}`;
const returnUrl = `${plugin.options.mountPath}/authorize_interaction?${params}`;
return res.redirect(
`/session/login?redirect=${encodeURIComponent(returnUrl)}`,
);
}
const mp = plugin.options.mountPath;
const encodedUrl = encodeURIComponent(resource);
// Route based on intent (FEP-3b86)
switch (intent) {
case "follow":
return res.redirect(`${mp}/admin/reader/profile?url=${encodedUrl}`);
case "create":
return res.redirect(`${mp}/admin/reader/compose?replyTo=${encodedUrl}`);
case "like":
case "announce":
return res.redirect(`${mp}/admin/reader/post?url=${encodedUrl}`);
default:
// Default: resolve to remote profile page
return res.redirect(`${mp}/admin/reader/profile?url=${encodedUrl}`);
}
};
}