summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRaphael Kabo <raphaelkabo@hey.com>2024-02-02 12:14:38 +0000
committerRaphael Kabo <raphaelkabo@hey.com>2024-02-02 12:14:38 +0000
commit7bd4eb728d27636321e9ac6dadd764ef5fa95af1 (patch)
tree4db3ca79cc85f3022918096cd5d443d4531f0759 /src
parentfbd2dd29739b76e76855a3d4c87d9d43da2953c2 (diff)
refactor: send and accept only spec-compliant AP headers
Diffstat (limited to 'src')
-rw-r--r--src/activitypub.js99
-rwxr-xr-xsrc/app.ts8
-rw-r--r--src/lib/activitypub.ts23
-rwxr-xr-xsrc/routes.js227
-rw-r--r--src/routes/frontend.ts13
5 files changed, 194 insertions, 176 deletions
diff --git a/src/activitypub.js b/src/activitypub.js
index 857dce8..a6f4ada 100644
--- a/src/activitypub.js
+++ b/src/activitypub.js
@@ -10,6 +10,7 @@ const domain = config.general.domain;
const siteName = config.general.site_name;
const isFederated = config.general.is_federated;
import Event from "./models/Event.js";
+import { activityPubContentType, alternateActivityPubContentType } from "./lib/activitypub.js";
// This alphabet (used to generate all event, group, etc. IDs) is missing '-'
// because ActivityPub doesn't like it in IDs
@@ -35,9 +36,9 @@ export function createActivityPubActor(
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
- "toot": "http://joinmastodon.org/ns#",
- "discoverable": "toot:discoverable",
- "indexable": "toot:indexable"
+ "toot": "http://joinmastodon.org/ns#",
+ "discoverable": "toot:discoverable",
+ "indexable": "toot:indexable"
},
],
indexable: false,
@@ -93,9 +94,9 @@ export function createActivityPubEvent(
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
- "toot": "http://joinmastodon.org/ns#",
- "discoverable": "toot:discoverable",
- "indexable": "toot:indexable"
+ "toot": "http://joinmastodon.org/ns#",
+ "discoverable": "toot:discoverable",
+ "indexable": "toot:indexable"
},
],
indexable: false,
@@ -219,8 +220,8 @@ export function signAndSend(message, eventID, targetDomain, inbox, callback) {
Date: d.toUTCString(),
Signature: header,
Digest: `SHA-256=${digest}`,
- "Content-Type": "application/activity+json",
- Accept: "application/activity+json",
+ "Content-Type": activityPubContentType,
+ Accept: activityPubContentType,
},
method: "POST",
json: true,
@@ -257,7 +258,7 @@ export function signAndSend(message, eventID, targetDomain, inbox, callback) {
"addActivityPubMessage",
"success",
"ActivityPubMessage added to event " +
- eventID,
+ eventID,
);
callback(null, message.id, 200);
})
@@ -266,9 +267,9 @@ export function signAndSend(message, eventID, targetDomain, inbox, callback) {
"addActivityPubMessage",
"error",
"Attempt to add ActivityPubMessage to event " +
- eventID +
- " failed with error: " +
- err,
+ eventID +
+ " failed with error: " +
+ err,
);
callback(err, null, 500);
});
@@ -463,7 +464,7 @@ export function broadcastUpdateMessage(apObject, followers, eventID) {
}
export function broadcastDeleteMessage(apObject, followers, eventID, callback) {
- callback = callback || function () {};
+ callback = callback || function () { };
if (!isFederated) {
callback([]);
return;
@@ -560,7 +561,7 @@ export function broadcastDeleteMessage(apObject, followers, eventID, callback) {
// this sends a message "to:" an individual fediverse user
export function sendDirectMessage(apObject, actorId, eventID, callback) {
if (!isFederated) return;
- callback = callback || function () {};
+ callback = callback || function () { };
const guidCreate = crypto.randomBytes(16).toString("hex");
const guidObject = crypto.randomBytes(16).toString("hex");
let d = new Date();
@@ -618,7 +619,7 @@ export function sendDirectMessage(apObject, actorId, eventID, callback) {
export function sendAcceptMessage(thebody, eventID, targetDomain, callback) {
if (!isFederated) return;
- callback = callback || function () {};
+ callback = callback || function () { };
const guid = crypto.randomBytes(16).toString("hex");
const actorId = thebody.actor;
let message = {
@@ -666,8 +667,8 @@ function _handleFollow(req, res) {
{
url: req.body.actor,
headers: {
- Accept: "application/activity+json",
- "Content-Type": "application/activity+json",
+ Accept: activityPubContentType,
+ "Content-Type": activityPubContentType,
},
},
function (error, response, body) {
@@ -794,9 +795,9 @@ function _handleFollow(req, res) {
"addEventFollower",
"error",
"Attempt to add follower to event " +
- eventID +
- " failed with error: " +
- err,
+ eventID +
+ " failed with error: " +
+ err,
);
return res
.status(500)
@@ -851,9 +852,9 @@ function _handleUndoFollow(req, res) {
"removeEventFollower",
"error",
"Attempt to remove follower from event " +
- eventID +
- " failed with error: " +
- err,
+ eventID +
+ " failed with error: " +
+ err,
);
return res.send(
"Database error, please try again :(",
@@ -887,8 +888,8 @@ function _handleAcceptEvent(req, res) {
{
url: actor,
headers: {
- Accept: "application/activity+json",
- "Content-Type": "application/activity+json",
+ Accept: activityPubContentType,
+ "Content-Type": activityPubContentType,
},
},
function (error, response, body) {
@@ -913,7 +914,7 @@ function _handleAcceptEvent(req, res) {
"addEventAttendee",
"success",
"Attendee added to event " +
- req.params.eventID,
+ req.params.eventID,
);
// get the new attendee with its hidden id from the full event
let fullAttendee = fullEvent.attendees.find(
@@ -947,9 +948,9 @@ function _handleAcceptEvent(req, res) {
"addEventAttendee",
"error",
"Attempt to add attendee to event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
return res
.status(500)
@@ -996,7 +997,7 @@ function _handleUndoAcceptEvent(req, res) {
"oneClickUnattend",
"success",
"Attendee removed via one click unattend " +
- req.params.eventID,
+ req.params.eventID,
);
});
}
@@ -1039,8 +1040,8 @@ function _handleCreateNote(req, res) {
{
url: attributedTo,
headers: {
- Accept: "application/activity+json",
- "Content-Type": "application/activity+json",
+ Accept: activityPubContentType,
+ "Content-Type": activityPubContentType,
},
},
function (error, response, body) {
@@ -1069,7 +1070,7 @@ function _handleCreateNote(req, res) {
"addEventAttendee",
"success",
"Attendee added to event " +
- req.params.eventID,
+ req.params.eventID,
);
// get the new attendee with its hidden id from the full event
let fullAttendee =
@@ -1105,9 +1106,9 @@ function _handleCreateNote(req, res) {
"addEventAttendee",
"error",
"Attempt to add attendee to event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
return res
.status(500)
@@ -1169,7 +1170,7 @@ function _handleDelete(req, res) {
return (
comment.activityJson &&
JSON.parse(comment.activityJson).object.id ===
- req.body.object.id
+ req.body.object.id
);
},
);
@@ -1189,11 +1190,11 @@ function _handleDelete(req, res) {
"deleteComment",
"error",
"Attempt to delete comment " +
- req.body.object.id +
- "from event " +
- eventWithComment.id +
- " failed with error: " +
- err,
+ req.body.object.id +
+ "from event " +
+ eventWithComment.id +
+ " failed with error: " +
+ err,
);
return res.sendStatus(500);
});
@@ -1233,8 +1234,8 @@ function _handleCreateNoteComment(req, res) {
{
url: req.body.actor,
headers: {
- Accept: "application/activity+json",
- "Content-Type": "application/activity+json",
+ Accept: activityPubContentType,
+ "Content-Type": activityPubContentType,
},
},
function (error, response, actor) {
@@ -1296,13 +1297,13 @@ function _handleCreateNoteComment(req, res) {
"addEventComment",
"error",
"Attempt to add comment to event " +
- eventID +
- " failed with error: " +
- err,
+ eventID +
+ " failed with error: " +
+ err,
);
res.status(500).send(
"Database error, please try again :(" +
- err,
+ err,
);
});
},
@@ -1387,7 +1388,7 @@ export function createWebfinger(eventID, domain) {
links: [
{
rel: "self",
- type: "application/activity+json",
+ type: alternateActivityPubContentType,
href: `https://${domain}/${eventID}`,
},
],
diff --git a/src/app.ts b/src/app.ts
index 3370d27..f3c99c7 100755
--- a/src/app.ts
+++ b/src/app.ts
@@ -9,6 +9,10 @@ import group from "./routes/group.js";
import staticPages from "./routes/static.js";
import { initEmailService } from "./lib/email.js";
+import {
+ activityPubContentType,
+ alternateActivityPubContentType,
+} from "./lib/activitypub.js";
const app = express();
@@ -48,8 +52,8 @@ app.set("hbsInstance", hbsInstance);
app.use(express.static("public"));
// Body parser //
-app.use(express.json({ type: "application/activity+json" }));
-app.use(express.json({ type: "application/ld+json" }));
+app.use(express.json({ type: alternateActivityPubContentType }));
+app.use(express.json({ type: activityPubContentType }));
app.use(express.json({ type: "application/json" }));
app.use(express.urlencoded({ extended: true }));
diff --git a/src/lib/activitypub.ts b/src/lib/activitypub.ts
index 0a3db7b..11f0770 100644
--- a/src/lib/activitypub.ts
+++ b/src/lib/activitypub.ts
@@ -1,9 +1,22 @@
-import { Request } from "express";
+import { Request, Response } from "express";
+// From https://www.w3.org/TR/activitypub/#client-to-server-interactions:
+// "Servers MAY interpret a Content-Type or Accept header of application/activity+json
+// as equivalent to application/ld+json; profile="https://www.w3.org/ns/activitystreams"
+// for client-to-server interactions.
+// For best compatibility, we always send application/ld+json; profile="https://www.w3.org/ns/activitystreams"
+// and accept both application/ld+json; profile="https://www.w3.org/ns/activitystreams" and application/activity+json.
+export const activityPubContentType =
+ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
+export const alternateActivityPubContentType = "application/activity+json";
+
+// Cf. https://www.w3.org/TR/activitypub/#retrieving-objects
export const acceptsActivityPub = (req: Request) => {
- return (
- req.headers.accept &&
- (req.headers.accept.includes("application/activity+json") ||
- req.headers.accept.includes("application/ld+json"))
+ const validAcceptHeaders = [
+ activityPubContentType,
+ alternateActivityPubContentType,
+ ];
+ return validAcceptHeaders.some(
+ (header) => req.headers.accept?.includes(header),
);
};
diff --git a/src/routes.js b/src/routes.js
index d59a738..360f387 100755
--- a/src/routes.js
+++ b/src/routes.js
@@ -22,6 +22,7 @@ import {
import Event from "./models/Event.js";
import EventGroup from "./models/EventGroup.js";
import path from "path";
+import { activityPubContentType } from "./lib/activitypub.js";
const config = getConfig();
const domain = config.general.domain;
@@ -104,9 +105,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {
"deleteOldEvents",
"error",
"Attempt to delete old event " +
- id +
- " failed with error: " +
- err,
+ id +
+ " failed with error: " +
+ err,
);
});
};
@@ -123,9 +124,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {
"deleteOldEvents",
"error",
"Attempt to delete event image for old event " +
- event.id +
- " failed with error: " +
- err,
+ event.id +
+ " failed with error: " +
+ err,
);
}
// Image removed
@@ -172,9 +173,9 @@ schedule.scheduleJob("59 23 * * *", function (fireDate) {
"deleteOldEvents",
"error",
"Attempt to delete old event " +
- event.id +
- " failed with error: " +
- err,
+ event.id +
+ " failed with error: " +
+ err,
);
});
@@ -227,9 +228,9 @@ router.post("/deleteimage/:eventID/:editToken", (req, res) => {
"deleteEventImage",
"error",
"Attempt to delete event image for event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
}
// Image removed
@@ -250,9 +251,9 @@ router.post("/deleteimage/:eventID/:editToken", (req, res) => {
"deleteEventImage",
"error",
"Attempt to delete event image for event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
},
@@ -294,9 +295,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
"deleteEvent",
"error",
"Attempt to delete event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
}
},
@@ -316,9 +317,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
"deleteEvent",
"error",
"Attempt to delete event image for event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
}
// Image removed
@@ -326,8 +327,8 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
"deleteEvent",
"success",
"Event " +
- req.params.eventID +
- " deleted",
+ req.params.eventID +
+ " deleted",
);
},
);
@@ -349,7 +350,7 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
if (attendeeEmails.length) {
console.log(
"Sending emails to: " +
- attendeeEmails,
+ attendeeEmails,
);
req.app.get("hbsInstance").renderView(
"./views/emails/deleteEvent/deleteEventHtml.handlebars",
@@ -408,15 +409,15 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
- err,
+ err,
);
addToLog(
"deleteEvent",
"error",
"Attempt to delete event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
},
@@ -428,8 +429,8 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
"deleteEvent",
"error",
"Attempt to delete event " +
- req.params.eventID +
- " failed with error: token does not match",
+ req.params.eventID +
+ " failed with error: token does not match",
);
}
})
@@ -439,9 +440,9 @@ router.post("/deleteevent/:eventID/:editToken", (req, res) => {
"deleteEvent",
"error",
"Attempt to delete event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
});
@@ -474,9 +475,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
"deleteEventGroup",
"error",
"Attempt to delete event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
+ req.params.eventGroupID +
+ " failed with error: " +
+ err,
);
}
},
@@ -496,9 +497,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
"deleteEventGroup",
"error",
"Attempt to delete event image for event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
+ req.params.eventGroupID +
+ " failed with error: " +
+ err,
);
}
},
@@ -515,8 +516,8 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
"deleteEventGroup",
"success",
"Event group " +
- req.params.eventGroupID +
- " deleted",
+ req.params.eventGroupID +
+ " deleted",
);
res.writeHead(302, {
Location: "/",
@@ -526,30 +527,30 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
- err,
+ err,
);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
+ req.params.eventGroupID +
+ " failed with error: " +
+ err,
);
});
})
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
- err,
+ err,
);
addToLog(
"deleteEventGroup",
"error",
"Attempt to delete event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
+ req.params.eventGroupID +
+ " failed with error: " +
+ err,
);
});
} else {
@@ -559,8 +560,8 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
"deleteEventGroup",
"error",
"Attempt to delete event group " +
- req.params.eventGroupID +
- " failed with error: token does not match",
+ req.params.eventGroupID +
+ " failed with error: token does not match",
);
}
})
@@ -570,9 +571,9 @@ router.post("/deleteeventgroup/:eventGroupID/:editToken", (req, res) => {
"deleteEventGroup",
"error",
"Attempt to delete event group " +
- req.params.eventGroupID +
- " failed with error: " +
- err,
+ req.params.eventGroupID +
+ " failed with error: " +
+ err,
);
});
});
@@ -590,9 +591,9 @@ router.post("/attendee/provision", async (req, res) => {
"provisionEventAttendee",
"error",
"Attempt to provision attendee in event " +
- req.query.eventID +
- " failed with error: " +
- e,
+ req.query.eventID +
+ " failed with error: " +
+ e,
);
return res.sendStatus(500);
});
@@ -608,9 +609,9 @@ router.post("/attendee/provision", async (req, res) => {
"provisionEventAttendee",
"error",
"Attempt to provision attendee in event " +
- req.query.eventID +
- " failed with error: " +
- e,
+ req.query.eventID +
+ " failed with error: " +
+ e,
);
return res.sendStatus(500);
});
@@ -646,9 +647,9 @@ router.post("/attendevent/:eventID", async (req, res) => {
"attendEvent",
"error",
"Attempt to attend event " +
- req.params.eventID +
- " failed with error: " +
- e,
+ req.params.eventID +
+ " failed with error: " +
+ e,
);
return res.sendStatus(500);
});
@@ -747,9 +748,9 @@ router.post("/attendevent/:eventID", async (req, res) => {
"addEventAttendee",
"error",
"Attempt to add attendee to event " +
- req.params.eventID +
- " failed with error: " +
- error,
+ req.params.eventID +
+ " failed with error: " +
+ error,
);
});
});
@@ -825,9 +826,9 @@ router.post("/unattendevent/:eventID", (req, res) => {
"removeEventAttendee",
"error",
"Attempt to remove attendee from event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
});
@@ -906,9 +907,9 @@ router.get("/oneclickunattendevent/:eventID/:attendeeID", (req, res) => {
"removeEventAttendee",
"error",
"Attempt to remove attendee by admin from event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
});
@@ -979,9 +980,9 @@ router.post("/removeattendee/:eventID/:attendeeID", (req, res) => {
"removeEventAttendee",
"error",
"Attempt to remove attendee by admin from event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
});
@@ -1055,11 +1056,11 @@ router.post("/subscribe/:eventGroupID", (req, res) => {
"addSubscription",
"error",
"Attempt to subscribe " +
- req.body.emailAddress +
- " to event group " +
- req.params.eventGroupID +
- " failed with error: " +
- error,
+ req.body.emailAddress +
+ " to event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ error,
);
return res.sendStatus(500);
});
@@ -1087,11 +1088,11 @@ router.get("/unsubscribe/:eventGroupID", (req, res) => {
"removeSubscription",
"error",
"Attempt to unsubscribe " +
- req.query.email +
- " from event group " +
- req.params.eventGroupID +
- " failed with error: " +
- error,
+ req.query.email +
+ " from event group " +
+ req.params.eventGroupID +
+ " failed with error: " +
+ error,
);
return res.sendStatus(500);
});
@@ -1217,9 +1218,9 @@ router.post("/post/comment/:eventID", (req, res) => {
"addEventComment",
"error",
"Attempt to add comment to event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
},
@@ -1250,9 +1251,9 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {
"addEventReply",
"success",
"Reply added to comment " +
- commentID +
- " in event " +
- req.params.eventID,
+ commentID +
+ " in event " +
+ req.params.eventID,
);
// broadcast an identical message to all followers, will show in their home timeline
const guidObject = crypto.randomBytes(16).toString("hex");
@@ -1348,11 +1349,11 @@ router.post("/post/reply/:eventID/:commentID", (req, res) => {
"addEventReply",
"error",
"Attempt to add reply to comment " +
- commentID +
- " in event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ commentID +
+ " in event " +
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
},
@@ -1388,17 +1389,17 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {
.catch((err) => {
res.send(
"Sorry! Something went wrong (error deleting): " +
- err,
+ err,
);
addToLog(
"deleteComment",
"error",
"Attempt to delete comment " +
- req.params.commentID +
- "from event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
} else {
@@ -1408,10 +1409,10 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {
"deleteComment",
"error",
"Attempt to delete comment " +
- req.params.commentID +
- "from event " +
- req.params.eventID +
- " failed with error: token does not match",
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: token does not match",
);
}
})
@@ -1421,11 +1422,11 @@ router.post("/deletecomment/:eventID/:commentID/:editToken", (req, res) => {
"deleteComment",
"error",
"Attempt to delete comment " +
- req.params.commentID +
- "from event " +
- req.params.eventID +
- " failed with error: " +
- err,
+ req.params.commentID +
+ "from event " +
+ req.params.eventID +
+ " failed with error: " +
+ err,
);
});
});
@@ -1452,8 +1453,8 @@ router.post("/activitypub/inbox", (req, res) => {
{
url: signature_header.keyId,
headers: {
- Accept: "application/activity+json",
- "Content-Type": "application/activity+json",
+ Accept: activityPubContentType,
+ "Content-Type": activityPubContentType,
},
},
function (error, response, actor) {
diff --git a/src/routes/frontend.ts b/src/routes/frontend.ts
index c405572..cc97ab8 100644
--- a/src/routes/frontend.ts
+++ b/src/routes/frontend.ts
@@ -6,6 +6,10 @@ import getConfig, { frontendConfig } from "../lib/config.js";
import { addToLog, exportICal } from "../helpers.js";
import Event from "../models/Event.js";
import EventGroup, { IEventGroup } from "../models/EventGroup.js";
+import {
+ acceptsActivityPub,
+ activityPubContentType,
+} from "../lib/activitypub.js";
const config = getConfig();
@@ -174,13 +178,8 @@ router.get("/:eventID", async (req: Request, res: Response) => {
: null,
url: `https://${config.general.domain}/` + req.params.eventID,
};
- if (
- req.headers.accept &&
- (req.headers.accept.includes("application/activity+json") ||
- req.headers.accept.includes("application/json") ||
- req.headers.accept.includes("application/json+ld"))
- ) {
- res.header("Content-Type", "application/activity+json").send(
+ if (acceptsActivityPub(req)) {
+ res.header("Content-Type", activityPubContentType).send(
JSON.parse(event.activityPubActor || "{}"),
);
} else {