From 98280d30e7a56209b28316abd40d9752e38b37d3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 15 Jan 2025 14:19:39 -0500 Subject: [PATCH] fix: #12990, local references via remote posts are not linkified properly, + tests for helper --- src/activitypub/helpers.js | 16 +++++++++--- test/activitypub.js | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/activitypub/helpers.js b/src/activitypub/helpers.js index aa00528717..9a5ac54e33 100644 --- a/src/activitypub/helpers.js +++ b/src/activitypub/helpers.js @@ -366,19 +366,29 @@ Helpers.remoteAnchorToLocalProfile = async (content) => { return content; } - // Filter out urls that don't backreference to a remote id + const urlMap = new Map(); const urlsArray = Array.from(urls); + + // Local references + const localUrls = urlsArray.filter(url => url.startsWith(nconf.get('url'))); + await Promise.all(localUrls.map(async (url) => { + const { type, id } = await Helpers.resolveLocalId(url); + if (type === 'user') { + urlMap.set(url, id); + } // else if (type === 'category') { + })); + + // Remote references const [backrefs, urlAsIdExists] = await Promise.all([ db.getObjectFields('remoteUrl:uid', urlsArray), db.isSortedSetMembers('usersRemote:lastCrawled', urlsArray), ]); - - const urlMap = new Map(); urlsArray.forEach((url, index) => { if (backrefs[url] || urlAsIdExists[index]) { urlMap.set(url, backrefs[url] || url); } }); + let slugs = await user.getUsersFields(Array.from(urlMap.values()), ['userslug']); slugs = slugs.map(({ userslug }) => userslug); Array.from(urlMap.keys()).forEach((url, idx) => { diff --git a/test/activitypub.js b/test/activitypub.js index 9fa2c757af..3465707203 100644 --- a/test/activitypub.js +++ b/test/activitypub.js @@ -158,6 +158,58 @@ describe('ActivityPub integration', () => { meta.config.maximumTitleLength = value; }); }); + + describe.only('.remoteAnchorToLocalProfile', () => { + const uuid1 = utils.generateUUID(); + const id1 = `https://example.org/uuid/${uuid1}`; + const url1 = `https://example.org/test`; + const uuid2 = utils.generateUUID(); + const id2 = `https://example.org/uuid/${uuid2}`; + const localUsername = utils.generateUUID(); + const localSlug = slugify(localUsername); + let localUid; + before(async () => { + // Mock up a fake remote user + [,,,, localUid] = await Promise.all([ + db.setObjectField('remoteUrl:uid', url1, id1), + db.sortedSetAdd('usersRemote:lastCrawled', Date.now(), id2), + db.setObject(`userRemote:${id1}`, { uid: id1, userslug: uuid1 }), + db.setObject(`userRemote:${id2}`, { uid: id2, userslug: id2 }), + user.create({ username: localUsername }), + ]); + }); + + it('should convert an anchor pointing to a remote user URL', async () => { + const content = `adsf @${uuid1} asdf`; + const converted = await activitypub.helpers.remoteAnchorToLocalProfile(content); + assert.strictEqual(converted, `adsf @${uuid1} asdf`); + }); + + it('should convert an anchor pointing to a remote user id', async () => { + const content = `adsf @${uuid2} asdf`; + const converted = await activitypub.helpers.remoteAnchorToLocalProfile(content); + assert.strictEqual(converted, `adsf @${uuid2} asdf`); + }); + + it('should convert an anchor pointing to a local user URL', async () => { + const content = `adsf @${localSlug} asdf`; + const converted = await activitypub.helpers.remoteAnchorToLocalProfile(content); + assert.strictEqual(converted, `adsf @${localSlug} asdf`); + }); + + it('should convert an anchor pointing to a local user URL', async () => { + const content = `adsf @${localSlug} asdf`; + const converted = await activitypub.helpers.remoteAnchorToLocalProfile(content); + assert.strictEqual(converted, `adsf @${localSlug} asdf`); + }); + + after(async () => { + await Promise.all([ + db.deleteObjectField('remoteUrl:uid', url1), + db.sortedSetRemove('usersRemote:lastCrawled', id2), + ]); + }); + }); }); describe('ActivityPub screener middleware', () => {