diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index 9fe4a52a4d..9a9381f43f 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -13,6 +13,7 @@ const notifications = require('../notifications'); const messaging = require('../messaging'); const flags = require('../flags'); const api = require('../api'); +const utils = require('../utils'); const activitypub = require('.'); const socketHelpers = require('../socket.io/helpers'); @@ -78,6 +79,42 @@ inbox.add = async (req) => { } }; +inbox.remove = async (req) => { + const { actor, object } = req.body; + + const isContext = activitypub._constants.acceptable.contextTypes.has(object.type); + if (!isContext) { + return; // don't know how to handle other types + } + console.log('isContext?', isContext); + + const mainPid = await activitypub.contexts.getItems(0, object.id, { returnRootId: true }); + const exists = await posts.exists(mainPid); + if (!exists) { + return; // post not cached; do nothing. + } + console.log('mainPid is', mainPid); + + // Ensure that cid is same-origin as the actor + const tid = await posts.getPostField(mainPid, 'tid'); + const cid = await topics.getTopicField(tid, 'cid'); + if (utils.isNumber(cid)) { + // remote removal of topic in local cid; what?? + return; + } + const actorHostname = new URL(actor).hostname; + const cidHostname = new URL(cid).hostname; + if (actorHostname !== cidHostname) { + throw new Error('[[error:activitypub.origin-mismatch]]'); + } + + activitypub.helpers.log(`[activitypub/inbox/remove] Removing topic ${tid} from ${cid}`); + await topics.tools.move(tid, { + cid: -1, + uid: 'system', + }); +}; + inbox.update = async (req) => { const { actor, object } = req.body; const isPublic = publiclyAddressed([...(object.to || []), ...(object.cc || [])]); @@ -200,8 +237,6 @@ inbox.delete = async (req) => { if (type === 'Tombstone') { method = 'delete'; // soft delete - } else if (activitypub._constants.acceptable.contextTypes.includes(type)) { - method = 'move'; // move to cid -1 } } catch (e) { // probably 410/404 @@ -221,11 +256,6 @@ inbox.delete = async (req) => { // db.isSortedSetMember('usersRemote:lastCrawled', object.id), ]); - // 'move' method only applicable for contexts - if (method === 'move' && !isContext) { - return reject('Delete', object, actor); - } - switch (true) { case isNote: { const cid = await posts.getCidByPid(id); @@ -248,13 +278,8 @@ inbox.delete = async (req) => { return; } const { tid, uid } = await posts.getPostFields(pid, ['tid', 'uid']); - if (method === 'move') { - activitypub.helpers.log(`[activitypub/inbox.delete] Moving tid ${tid} to cid -1.`); - await api.topics.move({ uid }, { tid, cid: -1 }); - } else { - activitypub.helpers.log(`[activitypub/inbox.delete] Deleting tid ${tid}.`); - await api.topics[method]({ uid }, { tids: [tid] }); - } + activitypub.helpers.log(`[activitypub/inbox.delete] Deleting tid ${tid}.`); + await api.topics[method]({ uid }, { tids: [tid] }); break; } @@ -347,12 +372,6 @@ inbox.announce = async (req) => { break; } - case object.type === 'Delete': { - req.body = object; - await inbox.delete(req); - break; - } - case object.type === 'Create': { object = object.object; // falls through diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 3d1d3ff546..12c1989238 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -412,63 +412,6 @@ activitypubApi.announce.user = enabledCheck(async (caller, { tid }) => { }); }); -activitypubApi.announce.delete = enabledCheck(async ({ uid }, { tid }) => { - const now = new Date(); - const { mainPid: pid, cid } = await topics.getTopicFields(tid, ['mainPid', 'cid']); - - // Only local categories - if (!utils.isNumber(cid) || parseInt(cid, 10) < 1) { - return; - } - - const allowed = await privileges.categories.can('topics:read', cid, activitypub._constants.uid); - if (!allowed) { - activitypub.helpers.log(`[activitypub/api] Not federating announce of pid ${pid} to the fediverse due to privileges.`); - return; - } - - const { to, cc, targets } = await activitypub.buildRecipients({ - to: [activitypub._constants.publicAddress], - cc: [`${nconf.get('url')}/category/${cid}/followers`], - }, { cid }); - - const deleteTpl = { - id: `${nconf.get('url')}/topic/${tid}#activity/delete/${now.getTime()}`, - type: 'Delete', - actor: `${nconf.get('url')}/category/${cid}`, - to, - cc, - origin: `${nconf.get('url')}/category/${cid}`, - }; - - // 7888 variant - await activitypub.send('cid', cid, Array.from(targets), { - id: `${nconf.get('url')}/topic/${tid}#activity/announce/delete/${now.getTime()}`, - type: 'Announce', - actor: `${nconf.get('url')}/category/${cid}`, - to, - cc, - object: { - ...deleteTpl, - object: `${nconf.get('url')}/topic/${tid}`, - }, - }); - - // 1b12 variant - await activitypub.send('cid', cid, Array.from(targets), { - id: `${nconf.get('url')}/post/${encodeURIComponent(pid)}#activity/announce/delete/${now.getTime()}`, - type: 'Announce', - actor: `${nconf.get('url')}/category/${cid}`, - to, - cc, - object: { - ...deleteTpl, - actor: `${nconf.get('url')}/uid/${uid}`, - object: utils.isNumber(pid) ? `${nconf.get('url')}/post/${pid}` : pid, - }, - }); -}); - activitypubApi.undo = {}; // activitypubApi.undo.follow = @@ -573,3 +516,38 @@ activitypubApi.undo.flag = enabledCheck(async (caller, flag) => { }); await db.sortedSetRemove(`flag:${flag.flagId}:remote`, caller.uid); }); + +activitypubApi.remove = {}; + +activitypubApi.remove.context = enabledCheck(async ({ uid }, { tid }) => { + // Federates Remove(Context); where Context is the tid + const now = new Date(); + const cid = await topics.getTopicField(tid, 'oldCid'); + + // Only local categories + if (!utils.isNumber(cid) || parseInt(cid, 10) < 1) { + return; + } + + const allowed = await privileges.categories.can('topics:read', cid, activitypub._constants.uid); + if (!allowed) { + activitypub.helpers.log(`[activitypub/api] Not federating deletion of tid ${tid} to the fediverse due to privileges.`); + return; + } + + const { to, cc, targets } = await activitypub.buildRecipients({ + to: [activitypub._constants.publicAddress], + cc: [`${nconf.get('url')}/category/${cid}/followers`], + }, { cid }); + + // Remove(Context) + await activitypub.send('uid', uid, Array.from(targets), { + id: `${nconf.get('url')}/topic/${tid}#activity/remove/${now.getTime()}`, + type: 'Remove', + actor: `${nconf.get('url')}/uid/${uid}`, + to, + cc, + object: `${nconf.get('url')}/topic/${tid}`, + origin: `${nconf.get('url')}/category/${cid}`, + }); +}); \ No newline at end of file diff --git a/src/api/topics.js b/src/api/topics.js index 38468f5956..964c49e2ec 100644 --- a/src/api/topics.js +++ b/src/api/topics.js @@ -8,6 +8,7 @@ const meta = require('../meta'); const privileges = require('../privileges'); const events = require('../events'); const batch = require('../batch'); +const utils = require('../utils'); const activitypubApi = require('./activitypub'); const apiHelpers = require('./helpers'); @@ -321,13 +322,12 @@ topicsAPI.move = async (caller, { tid, cid }) => { if (!topicData.deleted) { socketHelpers.sendNotificationToTopicOwner(tid, caller.uid, 'move', 'notifications:moved-your-topic'); - // AP: Announce(Delete(Object)) - if (cid === -1) { - await activitypubApi.announce.delete({ uid: caller.uid }, { tid }); + if (utils.isNumber(cid) && parseInt(cid, 10) === -1) { + activitypubApi.remove.context(caller, { tid }); // tbd: activitypubApi.undo.announce? } else { + // tbd: activitypubApi.move activitypubApi.announce.category(caller, { tid }); - // tbd: api.activitypub.announce.move } } diff --git a/src/topics/delete.js b/src/topics/delete.js index 3557349d9d..ee9d39e107 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -25,7 +25,7 @@ module.exports = function (Topics) { deleterUid: uid, deletedTimestamp: Date.now(), }), - api.activitypub.announce.delete({ uid }, { tid }), + api.activitypub.remove.context({ uid }, { tid }), ]); await categories.updateRecentTidForCid(cid); @@ -82,7 +82,6 @@ module.exports = function (Topics) { } deletedTopic.tags = tags; await deleteFromFollowersIgnorers(tid); - await api.activitypub.announce.delete({ uid }, { tid }), await Promise.all([ db.deleteAll([