diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 51d8a1a03f..eafb1f8cb6 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -98,16 +98,23 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { if (hasTid) { mainPid = await topics.getTopicField(tid, 'mainPid'); } else { - // Check recipients/audience for local category + // Check recipients/audience for category (local or remote) const set = activitypub.helpers.makeSet(_activitypub, ['to', 'cc', 'audience']); + + // Local const resolved = await Promise.all(Array.from(set).map(async id => await activitypub.helpers.resolveLocalId(id))); const recipientCids = resolved .filter(Boolean) .filter(({ type }) => type === 'category') .map(obj => obj.id); - if (recipientCids.length) { + + // Remote + const assertedGroups = await db.exists(Array.from(set).map(id => `categoryRemote:${id}`)); + const remoteCid = Array.from(set).filter((_, idx) => assertedGroups[idx]).shift(); + + if (remoteCid || recipientCids.length) { // Overrides passed-in value, respect addressing from main post over booster - options.cid = recipientCids.shift(); + options.cid = remoteCid || recipientCids.shift(); } // mainPid ok to leave as-is @@ -131,7 +138,7 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { options.skipChecks || options.cid || await assertRelation(chain[inputIndex !== -1 ? inputIndex : 0]); const privilege = `topics:${tid ? 'reply' : 'create'}`; - const allowed = await privileges.categories.can(privilege, cid, activitypub._constants.uid); + const allowed = await privileges.categories.can(privilege, options.cid || cid, activitypub._constants.uid); if (!hasRelation || !allowed) { if (!hasRelation) { activitypub.helpers.log(`[activitypub/notes.assert] Not asserting ${id} as it has no relation to existing tracked content.`); diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index c858eebe60..cfdfee428d 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -9,6 +9,7 @@ const user = require('../user'); const categories = require('../categories'); const plugins = require('../plugins'); const translator = require('../translator'); +const utils = require('../utils'); const helpers = module.exports; @@ -29,6 +30,13 @@ helpers.isUsersAllowedTo = async function (privilege, uids, cid) { }; helpers.isAllowedTo = async function (privilege, uidOrGroupName, cid) { + // Remote categories (non-numeric) inherit world privileges + if (Array.isArray(cid)) { + cid = cid.map(cid => (utils.isNumber(cid) ? cid : -1)); + } else { + cid = utils.isNumber(cid) ? cid : -1; + } + let allowed; if (Array.isArray(privilege) && !Array.isArray(cid)) { allowed = await isAllowedToPrivileges(privilege, uidOrGroupName, cid); diff --git a/src/topics/index.js b/src/topics/index.js index 5717f26126..871d010dcf 100644 --- a/src/topics/index.js +++ b/src/topics/index.js @@ -74,8 +74,7 @@ Topics.getTopicsByTids = async function (tids, options) { .map(t => t && t.uid && t.uid.toString()) .filter(v => utils.isNumber(v) || activitypub.helpers.isUri(v))); const cids = _.uniq(topics - .map(t => t && t.cid && t.cid.toString()) - .filter(v => utils.isNumber(v))); + .map(t => t && t.cid && t.cid.toString())); const guestTopics = topics.filter(t => t && t.uid === 0); async function loadGuestHandles() {