diff --git a/public/src/admin/manage/users.js b/public/src/admin/manage/users.js index 657cfb3231..81e0f812fa 100644 --- a/public/src/admin/manage/users.js +++ b/public/src/admin/manage/users.js @@ -246,7 +246,7 @@ define('admin/manage/users', [ bootbox.confirm((uids.length > 1 ? '[[admin/manage/users:alerts.confirm-ban-multi]]' : '[[admin/manage/users:alerts.confirm-ban]]'), function (confirm) { if (confirm) { Promise.all(uids.map(function (uid) { - return api.put('/users/' + uid + '/ban'); + return api.put('/users/' + encodeURIComponent(uid) + '/ban'); })).then(() => { onSuccess('[[admin/manage/users:alerts.ban-success]]', '.ban', true); }).catch(alerts.error); @@ -284,7 +284,7 @@ define('admin/manage/users', [ ) : 0; Promise.all(uids.map(function (uid) { - return api.put('/users/' + uid + '/ban', { + return api.put('/users/' + encodeURIComponent(uid) + '/ban', { until: until, reason: formData.reason, }); @@ -326,7 +326,7 @@ define('admin/manage/users', [ Promise.all(uids.map(function (uid) { - return api.del('/users/' + uid + '/ban', { + return api.del('/users/' + encodeURIComponent(uid) + '/ban', { reason: formData.reason || '', }); })).then(() => { diff --git a/public/src/modules/accounts/moderate.js b/public/src/modules/accounts/moderate.js index 9b1308a8e1..6afc86076d 100644 --- a/public/src/modules/accounts/moderate.js +++ b/public/src/modules/accounts/moderate.js @@ -18,7 +18,7 @@ define('forum/account/moderate', [ const until = formData.length > 0 ? ( Date.now() + (formData.length * 1000 * 60 * 60 * (parseInt(formData.unit, 10) ? 24 : 1)) ) : 0; - api.put('/users/' + theirid + '/ban', { + api.put('/users/' + encodeURIComponent(theirid) + '/ban', { until: until, reason: formData.reason || '', }).then(() => { @@ -37,7 +37,7 @@ define('forum/account/moderate', [ tpl: 'modals/unban', title: '[[user:unban-account]]', onSubmit: function (formData) { - api.del('/users/' + theirid + '/ban', { + api.del('/users/' + encodeURIComponent(theirid) + '/ban', { reason: formData.reason || '', }).then(() => { ajaxify.refresh(); diff --git a/src/activitypub/notes.js b/src/activitypub/notes.js index 01ead62530..278c195925 100644 --- a/src/activitypub/notes.js +++ b/src/activitypub/notes.js @@ -111,6 +111,12 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { let { pid: mainPid, tid, uid: authorId, timestamp, title, content, sourceContent, _activitypub } = mainPost; const hasTid = !!tid; + const authorBanned = await user.bans.isBanned(authorId); + if (!hasTid && authorBanned) { // New topics only + activitypub.helpers.log('[notes/assert] OP is banned, not asserting topic.'); + return null; + } + const cid = hasTid ? await topics.getTopicField(tid, 'cid') : options.cid || -1; let crosspostCid = false; @@ -263,8 +269,19 @@ Notes.assert = async (uid, input, options = { skipChecks: false }) => { } } + const uids = Array.from(unprocessed.reduce((uids, post) => { + uids.add(post.uid); + return uids; + }, new Set())); + const isBanned = await user.bans.isBanned(uids); + const banned = uids.filter((_, idx) => isBanned[idx]); + let added = []; await Promise.all(unprocessed.map(async (post) => { + if (banned.includes(post.uid)) { + return; + } + const { to, cc } = post._activitypub; try { diff --git a/src/middleware/activitypub.js b/src/middleware/activitypub.js index 730b4e78af..2805801561 100644 --- a/src/middleware/activitypub.js +++ b/src/middleware/activitypub.js @@ -1,6 +1,7 @@ 'use strict'; const db = require('../database'); +const user = require('../user'); const meta = require('../meta'); const activitypub = require('../activitypub'); const analytics = require('../analytics'); @@ -64,6 +65,12 @@ middleware.assertPayload = helpers.try(async function (req, res, next) { // Checks the validity of the incoming payload against the sender and rejects on failure activitypub.helpers.log('[middleware/activitypub] Validating incoming payload...'); + // Reject from banned users + const isBanned = await user.bans.isBanned(req.uid); + if (isBanned) { + return res.sendStatus(403); + } + // Sanity-check payload schema const required = ['id', 'type', 'actor', 'object']; if (!required.every(prop => req.body.hasOwnProperty(prop))) { diff --git a/test/activitypub/notes.js b/test/activitypub/notes.js index d6ea16bd31..470c7c821c 100644 --- a/test/activitypub/notes.js +++ b/test/activitypub/notes.js @@ -430,6 +430,45 @@ describe('Notes', () => { }); }); + describe('from a banned account', () => { + before(async function () { + const { id: bannedUid } = helpers.mocks.person(); + this.bannedUid = bannedUid; + + const { note } = helpers.mocks.note({ + attributedTo: bannedUid, + }); + + const uid = await user.create({ username: utils.generateUUID() }); + const { id: boosterUid } = helpers.mocks.person(); + await db.sortedSetAdd(`followersRemote:${boosterUid}`, Date.now(), uid); + const { activity } = helpers.mocks.announce({ + actor: boosterUid, + object: note, + }); + this.activity = activity; + this.pid = note.id; + + await user.bans.ban(bannedUid, 0, 'testing'); + }); + + it('should list the remote user as banned, when queried', async function () { + const isBanned = await user.bans.isBanned(this.bannedUid); + assert.strictEqual(isBanned, true); + }); + + // Can't actually test the middleware because I can't sign a request for a test + + it('should not assert a note if authored by a banned user (boosted by third-party)', async function () { + await activitypub.inbox.announce({ + body: this.activity, + }); + + const exists = await posts.exists(this.pid); + assert.strictEqual(exists, false); + }); + }); + describe('Create', () => { let uid; let cid;