diff --git a/src/activitypub/feps.js b/src/activitypub/feps.js new file mode 100644 index 0000000000..3c4cf5ef1c --- /dev/null +++ b/src/activitypub/feps.js @@ -0,0 +1,36 @@ +'use strict'; + +const nconf = require('nconf'); +const winston = require('winston'); + +const posts = require('../posts'); + +const activitypub = module.parent.exports; +const Feps = module.exports; + +Feps.announce = async function announce(id, activity) { + let localId; + if (String(id).startsWith(nconf.get('url'))) { + ({ id: localId } = await activitypub.helpers.resolveLocalId(id)); + } + const cid = await posts.getCidByPid(localId || id); + + const followers = await activitypub.notes.getCategoryFollowers(cid); + if (!followers.length) { + return; + } + + const { actor } = activity; + if (actor && !actor.startsWith(nconf.get('url'))) { + followers.unshift(actor); + } + + winston.info(`[activitypub/inbox.announce(1b12)] Announcing ${activity.type} to followers of cid ${cid}`); + await activitypub.send('cid', cid, followers, { + id: `${nconf.get('url')}/post/${encodeURIComponent(id)}#activity/announce/${Date.now()}`, + type: 'Announce', + to: [`${nconf.get('url')}/category/${cid}/followers`], + cc: [actor, activitypub._constants.publicAddress], + object: activity, + }); +}; diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 2887caac04..0087f34b24 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -32,34 +32,6 @@ function reject(type, object, target, senderType = 'uid', id = 0) { }).catch(err => winston.error(err.stack)); } -// FEP 1b12 -async function announce(id, activity) { - let localId; - if (id.startsWith(nconf.get('url'))) { - ({ id: localId } = await activitypub.helpers.resolveLocalId(id)); - } - const cid = await posts.getCidByPid(localId || id); - - const followers = await activitypub.notes.getCategoryFollowers(cid); - if (!followers.length) { - return; - } - - const { actor } = activity; - followers.unshift(actor); - - winston.info(`[activitypub/inbox.announce(1b12)] Announcing ${activity.type} to followers of cid ${cid}`); - await Promise.all([activity, activity.object].map(async (object) => { - await activitypub.send('cid', cid, followers, { - id: `${nconf.get('url')}/post/${encodeURIComponent(id)}#activity/announce/${Date.now()}`, - type: 'Announce', - to: [`${nconf.get('url')}/category/${cid}/followers`], - cc: [actor, activitypub._constants.publicAddress], - object, - }); - })); -} - inbox.create = async (req) => { const { object } = req.body; @@ -71,7 +43,7 @@ inbox.create = async (req) => { const asserted = await activitypub.notes.assert(0, object); if (asserted) { - announce(object.id, req.body); + activitypub.feps.announce(object.id, req.body); api.activitypub.add(req, { pid: object.id }); } }; @@ -141,7 +113,7 @@ inbox.update = async (req) => { const asserted = await activitypub.notes.assert(0, object.id); if (asserted) { - announce(object.id, req.body); + activitypub.feps.announce(object.id, req.body); } break; } @@ -229,7 +201,7 @@ inbox.delete = async (req) => { switch (true) { case isNote: { const uid = await posts.getPostField(pid, 'uid'); - await announce(pid, req.body); + await activitypub.feps.announce(pid, req.body); await api.posts[method]({ uid }, { pid }); break; } @@ -263,7 +235,7 @@ inbox.like = async (req) => { winston.verbose(`[activitypub/inbox/like] id ${id} via ${actor}`); const result = await posts.upvote(id, actor); - announce(object.id, req.body); + activitypub.feps.announce(object.id, req.body); socketHelpers.upvote(result, 'notifications:upvoted-your-post-in'); }; @@ -529,7 +501,7 @@ inbox.undo = async (req) => { } await posts.unvote(id, actor); - announce(object.object, req.body); + activitypub.feps.announce(object.object, req.body); notifications.rescind(`upvote:post:${id}:uid:${actor}`); break; } diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 1884eb76ef..501ac3402a 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -56,6 +56,7 @@ ActivityPub.notes = require('./notes'); ActivityPub.contexts = require('./contexts'); ActivityPub.actors = require('./actors'); ActivityPub.instances = require('./instances'); +ActivityPub.feps = require('./feps'); ActivityPub.startJobs = () => { ActivityPub.helpers.log('[activitypub/jobs] Registering jobs.'); diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 76abcc9c51..c66cf9bde9 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -128,8 +128,6 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => { const { to, cc, targets } = await activitypub.buildRecipients(object, { pid, uid: post.user.uid }); object.to = to; object.cc = cc; - const { cid } = post.category; - const followers = await activitypub.notes.getCategoryFollowers(cid); const payload = { id: `${object.id}#activity/create/${Date.now()}`, @@ -140,22 +138,11 @@ activitypubApi.create.note = enabledCheck(async (caller, { pid, post }) => { object, }; - await activitypub.send('uid', caller.uid, Array.from(targets), payload); - - setTimeout(() => { // Delay sending to avoid potential race condition - if (followers.length) { - Promise.all([payload, payload.object].map(async (object) => { - await activitypub.send('cid', cid, followers, { - id: `${nconf.get('url')}/post/${encodeURIComponent(object.object ? object.object.id : object.id)}#activity/announce/${Date.now()}`, - type: 'Announce', - to: [activitypub._constants.publicAddress], - cc: [`${nconf.get('url')}/category/${cid}/followers`], - object, - }); - })).catch(err => winston.error(err.stack)); - } - activitypubApi.add(caller, { pid }); - }, 5000); + await Promise.all([ + activitypub.send('uid', caller.uid, Array.from(targets), payload), + activitypub.feps.announce(pid, payload), + activitypubApi.add(caller, { pid }), + ]); }); activitypubApi.create.privateNote = enabledCheck(async (caller, { messageObj }) => { @@ -232,7 +219,10 @@ activitypubApi.update.note = enabledCheck(async (caller, { post }) => { object, }; - await activitypub.send('uid', caller.uid, Array.from(targets), payload); + await Promise.all([ + activitypub.send('uid', caller.uid, Array.from(targets), payload), + activitypub.feps.announce(post.pid, payload), + ]); }); activitypubApi.update.privateNote = enabledCheck(async (caller, { messageObj }) => { @@ -286,7 +276,10 @@ activitypubApi.delete.note = enabledCheck(async (caller, { pid }) => { origin: object.context, }; - await activitypub.send('uid', caller.uid, Array.from(targets), payload); + await Promise.all([ + activitypub.send('uid', caller.uid, Array.from(targets), payload), + activitypub.feps.announce(pid, payload), + ]); }); activitypubApi.like = {}; @@ -301,11 +294,17 @@ activitypubApi.like.note = enabledCheck(async (caller, { pid }) => { return; } - await activitypub.send('uid', caller.uid, [uid], { + const payload = { id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, type: 'Like', + actor: `${nconf.get('url')}/uid/${caller.uid}`, object: pid, - }); + }; + + await Promise.all([ + activitypub.send('uid', caller.uid, [uid], payload), + activitypub.feps.announce(pid, payload), + ]); }); activitypubApi.announce = {}; @@ -355,16 +354,22 @@ activitypubApi.undo.like = enabledCheck(async (caller, { pid }) => { return; } - await activitypub.send('uid', caller.uid, [uid], { + const payload = { id: `${nconf.get('url')}/uid/${caller.uid}#activity/undo:like/${encodeURIComponent(pid)}/${Date.now()}`, type: 'Undo', + actor: `${nconf.get('url')}/uid/${caller.uid}`, object: { actor: `${nconf.get('url')}/uid/${caller.uid}`, id: `${nconf.get('url')}/uid/${caller.uid}#activity/like/${encodeURIComponent(pid)}`, type: 'Like', object: pid, }, - }); + }; + + await Promise.all([ + activitypub.send('uid', caller.uid, [uid], payload), + activitypub.feps.announce(pid, payload), + ]); }); activitypubApi.flag = enabledCheck(async (caller, flag) => {