From c6f2c874787fc10e86113d20f73ca7d3f8a4cbbe Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 24 Mar 2025 11:52:09 -0400 Subject: [PATCH] fix: do not send out ap (undo:)follow if local user or category is (not)already following --- src/api/activitypub.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/api/activitypub.js b/src/api/activitypub.js index 39cf3e5534..be6600d3a2 100644 --- a/src/api/activitypub.js +++ b/src/api/activitypub.js @@ -37,13 +37,22 @@ function enabledCheck(next) { activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => { // Privilege checks should be done upstream + const acceptedTypes = ['uid', 'cid']; const assertion = await activitypub.actors.assert(actor); - if (!assertion || (Array.isArray(assertion) && assertion.length)) { + if (!acceptedTypes.includes(type) || !assertion || (Array.isArray(assertion) && assertion.length)) { throw new Error('[[error:activitypub.invalid-id]]'); } actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; - const handle = await user.getUserField(actor, 'username'); + const [handle, isFollowing] = await Promise.all([ + user.getUserField(actor, 'username'), + db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor), + ]); + + if (isFollowing) { // already following + return; + } + const timestamp = Date.now(); await db.sortedSetAdd(`followRequests:${type}.${id}`, timestamp, actor); @@ -61,13 +70,22 @@ activitypubApi.follow = enabledCheck(async (caller, { type, id, actor } = {}) => // should be .undo.follow activitypubApi.unfollow = enabledCheck(async (caller, { type, id, actor }) => { + const acceptedTypes = ['uid', 'cid']; const assertion = await activitypub.actors.assert(actor); - if (!assertion) { + if (!acceptedTypes.includes(type) || !assertion) { throw new Error('[[error:activitypub.invalid-id]]'); } actor = actor.includes('@') ? await user.getUidByUserslug(actor) : actor; - const handle = await user.getUserField(actor, 'username'); + const [handle, isFollowing] = await Promise.all([ + user.getUserField(actor, 'username'), + db.isSortedSetMember(type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`, actor), + ]); + + if (!isFollowing) { // already not following + return; + } + const timestamps = await db.sortedSetsScore([ `followRequests:${type}.${id}`, type === 'uid' ? `followingRemote:${id}` : `cid:${id}:following`,