From ee6ee9aef071162b86c72aea21da483b0bb3e050 Mon Sep 17 00:00:00 2001 From: Raphael Kabo Date: Tue, 16 Jul 2024 13:24:20 +0100 Subject: fix: router bug in activitypub router We had a middleware applied in the activitypub router which would return 404 for all routes if activitypub wasn't enabled. Unfortunately due to the way Express works, that middleware also applied to every route below that router's routes in the base router chain. Instead, we now apply the middleware specifically to the individual routes in the activitypub file. --- src/routes/activitypub.ts | 284 ++++++++++++++++++++++++---------------------- 1 file changed, 150 insertions(+), 134 deletions(-) diff --git a/src/routes/activitypub.ts b/src/routes/activitypub.ts index fc61dd7..5f141ec 100644 --- a/src/routes/activitypub.ts +++ b/src/routes/activitypub.ts @@ -21,71 +21,79 @@ const send404IfNotFederated = ( next(); }; -router.use(send404IfNotFederated); - // return the JSON for the featured/pinned post for this event -router.get("/:eventID/featured", (req: Request, res: Response) => { - const { eventID } = req.params; - const featured = { - "@context": "https://www.w3.org/ns/activitystreams", - id: `https://${res.locals.config?.general.domain}/${eventID}/featured`, - type: "OrderedCollection", - orderedItems: [createFeaturedPost(eventID)], - }; - if (acceptsActivityPub(req)) { - res.header("Content-Type", "application/activity+json").send(featured); - } else { - res.header("Content-Type", "application/json").send(featured); - } -}); +router.get( + "/:eventID/featured", + send404IfNotFederated, + (req: Request, res: Response) => { + const { eventID } = req.params; + const featured = { + "@context": "https://www.w3.org/ns/activitystreams", + id: `https://${res.locals.config?.general.domain}/${eventID}/featured`, + type: "OrderedCollection", + orderedItems: [createFeaturedPost(eventID)], + }; + if (acceptsActivityPub(req)) { + res.header("Content-Type", "application/activity+json").send( + featured, + ); + } else { + res.header("Content-Type", "application/json").send(featured); + } + }, +); // return the JSON for a given activitypub message -router.get("/:eventID/m/:hash", async (req: Request, res: Response) => { - const { hash, eventID } = req.params; - const id = `https://${res.locals.config?.general.domain}/${eventID}/m/${hash}`; +router.get( + "/:eventID/m/:hash", + send404IfNotFederated, + async (req: Request, res: Response) => { + const { hash, eventID } = req.params; + const id = `https://${res.locals.config?.general.domain}/${eventID}/m/${hash}`; - try { - const event = await Event.findOne({ - id: eventID, - }); - if (!event) { - return res.status(404).render("404", frontendConfig(res)); - } else { - if (!event.activityPubMessages) { + try { + const event = await Event.findOne({ + id: eventID, + }); + if (!event) { return res.status(404).render("404", frontendConfig(res)); - } - const message = event.activityPubMessages.find( - (el) => el.id === id, - ); - if (message) { - if (acceptsActivityPub(req)) { - res.header( - "Content-Type", - "application/activity+json", - ).send(JSON.parse(message.content || "{}")); + } else { + if (!event.activityPubMessages) { + return res.status(404).render("404", frontendConfig(res)); + } + const message = event.activityPubMessages.find( + (el) => el.id === id, + ); + if (message) { + if (acceptsActivityPub(req)) { + res.header( + "Content-Type", + "application/activity+json", + ).send(JSON.parse(message.content || "{}")); + } else { + res.header("Content-Type", "application/json").send( + JSON.parse(message.content || "{}"), + ); + } } else { - res.header("Content-Type", "application/json").send( - JSON.parse(message.content || "{}"), - ); + return res.status(404).render("404", frontendConfig(res)); } - } else { - return res.status(404).render("404", frontendConfig(res)); } + } catch (err) { + addToLog( + "getActivityPubMessage", + "error", + "Attempt to get Activity Pub Message for " + + id + + " failed with error: " + + err, + ); + return res.status(404).render("404", frontendConfig(res)); } - } catch (err) { - addToLog( - "getActivityPubMessage", - "error", - "Attempt to get Activity Pub Message for " + - id + - " failed with error: " + - err, - ); - return res.status(404).render("404", frontendConfig(res)); - } -}); + }, +); -router.get("/.well-known/nodeinfo", (req, res) => { +router.get("/.well-known/nodeinfo", send404IfNotFederated, (req, res) => { if (!res.locals.config?.general.is_federated) { return res.status(404).render("404", frontendConfig(res)); } @@ -103,94 +111,102 @@ router.get("/.well-known/nodeinfo", (req, res) => { ).send(nodeInfo); }); -router.get("/.well-known/nodeinfo/2.2", async (req, res) => { - const eventCount = await Event.countDocuments(); +router.get( + "/.well-known/nodeinfo/2.2", + send404IfNotFederated, + async (req, res) => { + const eventCount = await Event.countDocuments(); - if (!res.locals.config?.general.is_federated) { - return res.status(404).render("404", frontendConfig(res)); - } - const nodeInfo = { - version: "2.2", - instance: { - name: res.locals.config?.general.site_name, - description: - "Federated, no-registration, privacy-respecting event hosting.", - }, - software: { - name: "Gathio", - version: process.env.npm_package_version || "unknown", - repository: "https://github.com/lowercasename/gathio", - homepage: "https://gath.io", - }, - protocols: ["activitypub"], - services: { - inbound: [], - outbound: [], - }, - openRegistrations: true, - usage: { - users: { - total: eventCount, + if (!res.locals.config?.general.is_federated) { + return res.status(404).render("404", frontendConfig(res)); + } + const nodeInfo = { + version: "2.2", + instance: { + name: res.locals.config?.general.site_name, + description: + "Federated, no-registration, privacy-respecting event hosting.", }, - }, - }; - res.header( - "Content-Type", - 'application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.1#"', - ).send(nodeInfo); -}); - -router.get("/.well-known/webfinger", async (req, res) => { - let resource = req.query.resource as string; - if (!resource || !resource.includes("acct:")) { - return res - .status(400) - .send( - 'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.', - ); - } else { - // "foo@domain" - let activityPubAccount = resource.replace("acct:", ""); - // "foo" - let eventID = activityPubAccount.replace(/@.*/, ""); + software: { + name: "Gathio", + version: process.env.npm_package_version || "unknown", + repository: "https://github.com/lowercasename/gathio", + homepage: "https://gath.io", + }, + protocols: ["activitypub"], + services: { + inbound: [], + outbound: [], + }, + openRegistrations: true, + usage: { + users: { + total: eventCount, + }, + }, + }; + res.header( + "Content-Type", + 'application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.1#"', + ).send(nodeInfo); + }, +); + +router.get( + "/.well-known/webfinger", + send404IfNotFederated, + async (req, res) => { + let resource = req.query.resource as string; + if (!resource || !resource.includes("acct:")) { + return res + .status(400) + .send( + 'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.', + ); + } else { + // "foo@domain" + let activityPubAccount = resource.replace("acct:", ""); + // "foo" + let eventID = activityPubAccount.replace(/@.*/, ""); - try { - const event = await Event.findOne({ id: eventID }); + try { + const event = await Event.findOne({ id: eventID }); - if (!event) { - return res.status(404).render("404", frontendConfig(res)); - } else { - if (acceptsActivityPub(req)) { - res.header( - "Content-Type", - "application/activity+json", - ).send( - createWebfinger( - eventID, - res.locals.config?.general.domain, - ), - ); + if (!event) { + return res.status(404).render("404", frontendConfig(res)); } else { - res.header("Content-Type", "application/json").send( - createWebfinger( - eventID, - res.locals.config?.general.domain, - ), - ); + if (acceptsActivityPub(req)) { + res.header( + "Content-Type", + "application/activity+json", + ).send( + createWebfinger( + eventID, + res.locals.config?.general.domain, + ), + ); + } else { + res.header("Content-Type", "application/json").send( + createWebfinger( + eventID, + res.locals.config?.general.domain, + ), + ); + } } + } catch (err) { + addToLog( + "renderWebfinger", + "error", + `Attempt to render webfinger for ${resource} failed with error: ${err}`, + ); + return res.status(404).render("404", frontendConfig(res)); } - } catch (err) { - addToLog( - "renderWebfinger", - "error", - `Attempt to render webfinger for ${resource} failed with error: ${err}`, - ); - return res.status(404).render("404", frontendConfig(res)); } - } -}); + }, +); -router.get("/:eventID/followers", async (req, res) => { +router.get("/:eventID/followers", send404IfNotFederated, async (req, res) => { const eventID = req.params.eventID; try { -- cgit v1.2.3