feat: add checks to only continue with topic assertion if there is a relation to existing content, #12442

This commit is contained in:
Julian Lam
2024-03-26 10:22:17 -04:00
parent 2688b6bbdc
commit 55e947a01d
2 changed files with 40 additions and 4 deletions

View File

@@ -245,7 +245,7 @@ inbox.accept = async (req) => {
if (type === 'Follow') { if (type === 'Follow') {
const now = Date.now(); const now = Date.now();
await db.sortedSetAdd(`followingRemote:${uid}`, now, actor); await db.sortedSetAdd(`followingRemote:${uid}`, now, actor);
await db.sortedSetAdd(`followersRemote:${actor}`, now, uid); // for followers backreference await db.sortedSetAdd(`followersRemote:${actor}`, now, uid); // for followers backreference and notes assertion checking
const followingRemoteCount = await db.sortedSetCard(`followingRemote:${uid}`); const followingRemoteCount = await db.sortedSetCard(`followingRemote:${uid}`);
await user.setUserField(uid, 'followingRemoteCount', followingRemoteCount); await user.setUserField(uid, 'followingRemoteCount', followingRemoteCount);
} }

View File

@@ -11,6 +11,7 @@ const categories = require('../categories');
const user = require('../user'); const user = require('../user');
const topics = require('../topics'); const topics = require('../topics');
const posts = require('../posts'); const posts = require('../posts');
const plugins = require('../plugins');
const utils = require('../utils'); const utils = require('../utils');
const activitypub = module.parent.exports; const activitypub = module.parent.exports;
@@ -25,7 +26,7 @@ async function unlock(value) {
await db.deleteObjectField('locks', value); await db.deleteObjectField('locks', value);
} }
Notes.assert = async (uid, input) => { Notes.assert = async (uid, input, options = { skipChecks: false }) => {
/** /**
* Given the id or object of any as:Note, traverses up to cache the entire threaded context * Given the id or object of any as:Note, traverses up to cache the entire threaded context
* *
@@ -74,10 +75,15 @@ Notes.assert = async (uid, input) => {
} }
mainPid = utils.isNumber(mainPid) ? parseInt(mainPid, 10) : mainPid; mainPid = utils.isNumber(mainPid) ? parseInt(mainPid, 10) : mainPid;
// Privilege check for local categories // Relation & privilege check for local categories
const privilege = `topics:${tid ? 'reply' : 'create'}`; const privilege = `topics:${tid ? 'reply' : 'create'}`;
const hasRelation = options.skipChecks || hasTid || await assertRelation(chain[0]);
const allowed = await privileges.categories.can(privilege, cid, activitypub._constants.uid); const allowed = await privileges.categories.can(privilege, cid, activitypub._constants.uid);
if (!allowed) { if (!hasRelation || !allowed) {
if (!hasRelation) {
winston.info(`[activitypub/notes.assert] Not asserting ${id} as it has no relation to existing tracked content.`);
}
unlock(id); unlock(id);
return null; return null;
} }
@@ -168,6 +174,36 @@ Notes.assert = async (uid, input) => {
return { tid, count }; return { tid, count };
}; };
async function assertRelation(post) {
/**
* Given a mocked post object, ensures that it is related to some other object in database
* This check ensures that random content isn't added to the database just because it is received.
*/
// Is followed by at least one local user
const isFollowed = await db.sortedSetCard(`followersRemote:${post.uid}`);
// Local user is mentioned
const { tag } = post._activitypub;
let uids = [];
if (tag.length) {
const slugs = tag.reduce((slugs, tag) => {
if (tag.type === 'Mention') {
const [slug, hostname] = tag.name.slice(1).split('@');
if (hostname === nconf.get('url_parsed').hostname) {
slugs.push(slug);
}
}
return slugs;
}, []);
uids = slugs.length ? await db.sortedSetScores('userslug:uid', slugs) : [];
uids = uids.filter(Boolean);
}
return isFollowed || uids.length;
}
Notes.updateLocalRecipients = async (id, { to, cc }) => { Notes.updateLocalRecipients = async (id, { to, cc }) => {
const recipients = new Set([...(to || []), ...(cc || [])]); const recipients = new Set([...(to || []), ...(cc || [])]);
const uids = new Set(); const uids = new Set();