From 0d77e860bf5cc8bdd428e438e85f5f35d68ab76f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 25 Mar 2025 10:20:50 -0400 Subject: [PATCH] fix: regression that caused resolveInboxes to always return empty, added tests for resolveInboxes --- src/activitypub/index.js | 22 +++++++++++---- test/activitypub/actors.js | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/activitypub/index.js b/src/activitypub/index.js index d57e9ad5c6..e055522d81 100644 --- a/src/activitypub/index.js +++ b/src/activitypub/index.js @@ -120,13 +120,23 @@ ActivityPub.resolveInboxes = async (ids) => { const exists = await db.isSortedSetMembers('usersRemote:lastCrawled', ids); ids = ids.filter((_, idx) => exists[idx]); - const isCategory = await db.exists(ids.map(id => `categoryRemote:${id}`)); await batch.processArray(ids, async (currentIds) => { - const method = isCategory ? categories.getCategoriesFields : user.getUsersFields; - const usersData = await method(currentIds, ['inbox', 'sharedInbox']); - usersData.forEach((u) => { - if (u && (u.sharedInbox || u.inbox)) { - inboxes.add(u.sharedInbox || u.inbox); + const isCategory = await db.exists(currentIds.map(id => `categoryRemote:${id}`)); + const [cids, uids] = currentIds.reduce(([cids, uids], id, idx) => { + const array = isCategory[idx] ? cids : uids; + array.push(id); + return [cids, uids]; + }, [[], []]); + const categoryData = await categories.getCategoriesFields(cids, ['inbox', 'sharedInbox']); + const userData = await user.getUsersFields(uids, ['inbox', 'sharedInbox']); + + currentIds.forEach((id) => { + if (cids.includes(id)) { + const data = categoryData[cids.indexOf(id)]; + inboxes.add(data.sharedInbox || data.inbox); + } else if (uids.includes(id)) { + const data = userData[uids.indexOf(id)]; + inboxes.add(data.sharedInbox || data.inbox); } }); }, { diff --git a/test/activitypub/actors.js b/test/activitypub/actors.js index 90a246bd9f..6cfa93de27 100644 --- a/test/activitypub/actors.js +++ b/test/activitypub/actors.js @@ -353,6 +353,64 @@ describe('as:Group', () => { }); }); +describe('Inbox resolution', () => { + describe('remote users', () => { + it('should return an inbox if present', async () => { + const { id, actor } = helpers.mocks.person(); + await activitypub.actors.assert(id); + + const inboxes = await activitypub.resolveInboxes([id]); + + assert(inboxes && Array.isArray(inboxes)); + assert.strictEqual(inboxes.length, 1); + assert.strictEqual(inboxes[0], actor.inbox); + }); + + it('should return a shared inbox if present', async () => { + const { id, actor } = helpers.mocks.person({ + endpoints: { + sharedInbox: 'https://example.org/inbox', + } + }); + await activitypub.actors.assert(id); + + const inboxes = await activitypub.resolveInboxes([id]); + + assert(inboxes && Array.isArray(inboxes)); + assert.strictEqual(inboxes.length, 1); + assert.strictEqual(inboxes[0], 'https://example.org/inbox'); + }); + }); + + describe('remote categories', () => { + it('should return an inbox if present', async () => { + const { id, actor } = helpers.mocks.group(); + await activitypub.actors.assertGroup(id); + + const inboxes = await activitypub.resolveInboxes([id]); + + assert(inboxes && Array.isArray(inboxes)); + assert.strictEqual(inboxes.length, 1); + assert.strictEqual(inboxes[0], actor.inbox); + }); + + it('should return a shared inbox if present', async () => { + const { id, actor } = helpers.mocks.group({ + endpoints: { + sharedInbox: 'https://example.org/inbox', + } + }); + await activitypub.actors.assertGroup(id); + + const inboxes = await activitypub.resolveInboxes([id]); + + assert(inboxes && Array.isArray(inboxes)); + assert.strictEqual(inboxes.length, 1); + assert.strictEqual(inboxes[0], 'https://example.org/inbox'); + }); + }); +}); + describe('Controllers', () => { describe('User Actor endpoint', () => { let uid;