fix: bug where privileges users could not uncrosspost others' crossposts. Tests

This commit is contained in:
Julian Lam
2025-12-29 14:20:25 -05:00
parent 6daaad810f
commit 0a0a7da9ba
2 changed files with 124 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
const db = require('../database');
const topics = require('.');
const user = require('../user');
const categories = require('../categories');
const posts = require('../posts');
const activitypub = require('../activitypub');
@@ -87,8 +88,10 @@ Crossposts.add = async function (tid, cid, uid) {
Crossposts.remove = async function (tid, cid, uid) {
let crossposts = await Crossposts.get(tid);
const isPrivileged = await user.isAdminOrGlobalMod(uid);
const isMod = await user.isModerator(uid, cid);
const crosspostId = crossposts.reduce((id, { id: _id, cid: _cid, uid: _uid }) => {
if (String(cid) === String(_cid) && String(uid) === String(_uid)) {
if (String(cid) === String(_cid) && (isPrivileged || isMod || String(uid) === String(_uid))) {
id = _id;
}

View File

@@ -8,9 +8,11 @@ const db = require('../mocks/databasemock');
const meta = require('../../src/meta');
const install = require('../../src/install');
const user = require('../../src/user');
const groups = require('../../src/groups');
const categories = require('../../src/categories');
const topics = require('../../src/topics');
const posts = require('../../src/posts');
const privileges = require('../../src/privileges');
const activitypub = require('../../src/activitypub');
const utils = require('../../src/utils');
@@ -142,6 +144,14 @@ describe('Crossposting (& related logic)', () => {
await topics.crossposts.add(tid, cid2, uid);
});
it('should not let another user uncrosspost', async () => {
const uid2 = await user.create({ username: utils.generateUUID().slice(0, 8) });
assert.rejects(
topics.crossposts.remove(tid, cid2, uid2),
'[[error:invalid-data]]',
);
});
it('should successfully uncrosspost from a cid', async () => {
const crossposts = await topics.crossposts.remove(tid, cid2, uid);
@@ -168,6 +178,116 @@ describe('Crossposting (& related logic)', () => {
});
});
describe('uncrosspost (as administrator)', () => {
let tid;
let cid1;
let cid2;
let uid;
let privUid;
before(async () => {
({ cid: cid1 } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
const crosspostCategory = await categories.create({ name: utils.generateUUID().slice(0, 8) });
cid2 = crosspostCategory.cid;
uid = await user.create({ username: utils.generateUUID().slice(0, 8) });
privUid = await user.create({ username: utils.generateUUID().slice(0, 8) });
await groups.join('administrators', privUid);
const { topicData } = await topics.post({
uid,
cid: cid1,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
tid = topicData.tid;
await topics.crossposts.add(tid, cid2, uid);
});
it('should successfully uncrosspost from a cid', async () => {
const crossposts = await topics.crossposts.remove(tid, cid2, privUid);
assert(Array.isArray(crossposts));
assert.strictEqual(crossposts.length, 0);
});
});
describe('uncrosspost (as global moderator)', () => {
let tid;
let cid1;
let cid2;
let uid;
let privUid;
before(async () => {
({ cid: cid1 } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
const crosspostCategory = await categories.create({ name: utils.generateUUID().slice(0, 8) });
cid2 = crosspostCategory.cid;
uid = await user.create({ username: utils.generateUUID().slice(0, 8) });
privUid = await user.create({ username: utils.generateUUID().slice(0, 8) });
await groups.join('Global Moderators', privUid);
const { topicData } = await topics.post({
uid,
cid: cid1,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
tid = topicData.tid;
await topics.crossposts.add(tid, cid2, uid);
});
it('should successfully uncrosspost from a cid', async () => {
const crossposts = await topics.crossposts.remove(tid, cid2, privUid);
assert(Array.isArray(crossposts));
assert.strictEqual(crossposts.length, 0);
});
});
describe('uncrosspost (as category moderator)', () => {
let tid;
let cid1;
let cid2;
let uid;
let privUid;
before(async () => {
({ cid: cid1 } = await categories.create({ name: utils.generateUUID().slice(0, 8) }));
const crosspostCategory = await categories.create({ name: utils.generateUUID().slice(0, 8) });
cid2 = crosspostCategory.cid;
uid = await user.create({ username: utils.generateUUID().slice(0, 8) });
privUid = await user.create({ username: utils.generateUUID().slice(0, 8) });
const { topicData } = await topics.post({
uid,
cid: cid1,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
tid = topicData.tid;
await topics.crossposts.add(tid, cid2, uid);
});
it('should fail to uncrosspost if not mod of passed-in category', async () => {
await privileges.categories.give(['moderate'], cid1, [privUid]);
assert.rejects(
topics.crossposts.remove(tid, cid2, privUid),
'[[error:invalid-data]]',
);
});
it('should successfully uncrosspost from a cid if proper mod', async () => {
await privileges.categories.give(['moderate'], cid2, [privUid]);
const crossposts = await topics.crossposts.remove(tid, cid2, privUid);
assert(Array.isArray(crossposts));
assert.strictEqual(crossposts.length, 0);
});
});
describe('ActivityPub effects (or lack thereof)', () => {
describe('local canonical category', () => {
let tid;