From 36ebda5269bb6891db2eeedf6400fc17cd9994e8 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sun, 5 Feb 2023 14:43:46 -0700 Subject: [PATCH] Fix shared inbox delivery for private + public --- core/activitypub/actor.js | 2 +- core/activitypub/note.js | 32 ++++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/core/activitypub/actor.js b/core/activitypub/actor.js index 979b2f1e..01d2ccdc 100644 --- a/core/activitypub/actor.js +++ b/core/activitypub/actor.js @@ -28,7 +28,7 @@ const { getISOTimestampString } = require('../database.js'); const moment = require('moment'); const paths = require('path'); -const ActorCacheTTL = moment.duration(1, 'day'); +const ActorCacheTTL = moment.duration(120, 'days'); // https://www.w3.org/TR/activitypub/#actor-objects module.exports = class Actor extends ActivityPubObject { diff --git a/core/activitypub/note.js b/core/activitypub/note.js index 566515b1..8904e339 100644 --- a/core/activitypub/note.js +++ b/core/activitypub/note.js @@ -13,7 +13,7 @@ const Collection = require('./collection'); const async = require('async'); const { isString, isObject, truncate } = require('lodash'); -const APMessageIdNamespace = '307bc7b3-3735-4573-9a20-e3f9eaac29c5'; +const PublicMessageIdNamespace = 'a26ae389-5dfb-4b24-a58e-5472085c8e42'; const APDefaultSummary = '[ActivityPub]'; module.exports = class Note extends ActivityPubObject { @@ -154,10 +154,26 @@ module.exports = class Note extends ActivityPubObject { return cb(Errors.MissingParam('Missing one or more required options!')); } - // stable ID based on Note ID - const message = new Message({ - uuid: UUIDv5(this.id, APMessageIdNamespace), - }); + const isPrivate = isObject(options.toUser); + + // + // Message UUIDs are unique in the message database; + // However, we may need to deliver a particular message to: + // - #Public / sharedInbox + // - 1:N private user inboxes + // + // In both cases, the UUID is stable. That is, the same ID + // will equal the same UUID as to prevent dupes. + // + const makeMessageUuid = () => { + if (isPrivate) { + // UUID specific to the target user + const url = `${this.id}/${options.toUser.userId}`; + return UUIDv5(url, UUIDv5.URL); + } else { + return UUIDv5(this.id, PublicMessageIdNamespace); + } + }; // Fetch the remote actor info to get their user info Actor.fromId(this.attributedTo, (err, attributedToActor, fromActorSubject) => { @@ -165,13 +181,17 @@ module.exports = class Note extends ActivityPubObject { return cb(err); } + const message = new Message({ + uuid: makeMessageUuid(), + }); + message.fromUserName = fromActorSubject || this.attributedTo; // // Note's can be addressed to 1:N users, but a Message is a 1:1 // relationship. This method requires the mapping up front via options // - if (isObject(options.toUser)) { + if (isPrivate) { message.toUserName = options.toUser.username; message.meta.System[Message.SystemMetaNames.LocalToUserID] = options.toUser.userId;