diff --git a/src/activitypub/inbox.js b/src/activitypub/inbox.js index bafed33183..4308d1c9de 100644 --- a/src/activitypub/inbox.js +++ b/src/activitypub/inbox.js @@ -93,10 +93,12 @@ inbox.announce = async (req) => { tid = await posts.getPostField(id, 'tid'); } else { pid = object; - ([pid, tid] = await Promise.all([ - activitypub.notes.resolveId(0, pid), - activitypub.notes.assertTopic(0, pid), - ])); + pid = await activitypub.resolveId(0, pid); // in case wrong id is passed-in; unlikely, but still. + if (!pid) { + return; + } + + tid = await activitypub.notes.assertTopic(0, pid); if (!tid) { return; } diff --git a/src/activitypub/index.js b/src/activitypub/index.js index 6f787b7b4f..4f2235100a 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -24,6 +24,23 @@ ActivityPub.mocks = require('./mocks'); ActivityPub.notes = require('./notes'); ActivityPub.actors = require('./actors'); +ActivityPub.resolveId = async (uid, id) => { + try { + const query = new URL(id); + ({ id } = await ActivityPub.get('uid', uid, id)); + const response = new URL(id); + + if (query.host !== response.host) { + winston.warn(`[activitypub/resolveId] id resolution domain mismatch: ${query.href} != ${response.href}`); + return null; + } + + return id; + } catch (e) { + return null; + } +}; + ActivityPub.resolveInboxes = async (ids) => { const inboxes = new Set(); diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 068fd8cb51..795c807d26 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -14,11 +14,6 @@ const slugify = require('../slugify'); const activitypub = module.parent.exports; const Notes = module.exports; -Notes.resolveId = async (uid, id) => { - ({ id } = await activitypub.get('uid', uid, id)); - return id; -}; - // todo: when asserted, notes aren't added to a global sorted set // also, db.exists call is probably expensive Notes.assert = async (uid, input, options = {}) => { @@ -28,8 +23,13 @@ Notes.assert = async (uid, input, options = {}) => { await Promise.all(input.map(async (item) => { let id = activitypub.helpers.isUri(item) ? item : item.pid; if (activitypub.helpers.isUri(id)) { - id = await Notes.resolveId(uid, id); + id = await activitypub.resolveId(uid, id); + if (!id) { + winston.warn(`[activitypub/notes.assert] Not asserting ${id}`); + return; + } } + const key = `post:${id}`; const exists = await db.exists(key); winston.verbose(`[activitypub/notes.assert] Asserting note id ${id}`); diff --git a/test/activitypub.js b/test/activitypub.js index d002bca19d..e1c052e377 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -88,6 +88,40 @@ describe('ActivityPub integration', () => { }); + describe.only('.resolveId()', () => { + let url; + let resolved; + + before(() => { + url = 'https://example.org/topic/foobar'; + resolved = 'https://example.org/tid/1234'; + activitypub._cache.set(`0;${url}`, { + id: resolved, + }); + }); + + it('should return the resolved id when queried', async () => { + const id = await activitypub.resolveId(0, url); + assert.strictEqual(id, resolved); + }); + + it('should return null when the query fails', async () => { + const id = await activitypub.resolveId(0, 'https://example.org/sdlknsdfnsd'); + assert.strictEqual(id, null); + }); + + it('should return null when the resolved host does not match the queried host', async () => { + const url = 'https://example.com/topic/foobar'; // .com attempting to overwrite .org data + const resolved = 'https://example.org/tid/1234'; // .org + activitypub._cache.set(`0;${url}`, { + id: resolved, + }); + + const id = await activitypub.resolveId(0, url); + assert.strictEqual(id, null); + }); + }); + describe('.resolveLocalId()', () => { let uid; let slug;