From df2c7851272f56ec119141f6c7668550fda4cf5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 24 Jan 2020 15:24:01 -0500 Subject: [PATCH 1/7] feat: add test for change post owner --- test/posts.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/posts.js b/test/posts.js index adcc4a7ec2..dc82563463 100644 --- a/test/posts.js +++ b/test/posts.js @@ -142,6 +142,14 @@ describe('Post\'s', function () { } }); + it('should fail to change owner if user is not authorized', async function () { + try { + await socketPosts.changeOwner({ uid: voterUid }, { pids: [1, 2], toUid: voterUid }); + } catch (err) { + assert.strictEqual(err.message, '[[error:no-privileges]]'); + } + }); + it('should return falsy if post does not exist', function (done) { posts.getPostData(9999, function (err, postData) { assert.ifError(err); From 3cca929a889120c089ce508a74ce40789e0c02d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 26 Jan 2020 21:35:04 -0500 Subject: [PATCH 2/7] fix: add missing await --- src/user/online.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/user/online.js b/src/user/online.js index 3f07cd619d..05c40464f7 100644 --- a/src/user/online.js +++ b/src/user/online.js @@ -30,11 +30,8 @@ module.exports = function (User) { const now = Date.now(); const isArray = Array.isArray(uid); uid = isArray ? uid : [uid]; - const lastonline = db.sortedSetScores('users:online', uid); - const isOnline = uid.map(function (uid, index) { - return (now - lastonline[index]) < (meta.config.onlineCutoff * 60000); - }); - + const lastonline = await db.sortedSetScores('users:online', uid); + const isOnline = uid.map((uid, index) => (now - lastonline[index]) < (meta.config.onlineCutoff * 60000)); return isArray ? isOnline : isOnline[0]; }; }; From 66febb80710985bf34540e13ffa43841424bc6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 26 Jan 2020 21:51:05 -0500 Subject: [PATCH 3/7] feat: add test for isOnline --- test/user.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/user.js b/test/user.js index 2faf71fb70..66654cd649 100644 --- a/test/user.js +++ b/test/user.js @@ -2164,10 +2164,20 @@ describe('User', function () { }); }); - it('should return offline if user is guest', function (done) { - var status = User.getStatus({ uid: 0 }); - assert.strictEqual(status, 'offline'); - done(); + describe('status/online', function () { + it('should return offline if user is guest', function (done) { + var status = User.getStatus({ uid: 0 }); + assert.strictEqual(status, 'offline'); + done(); + }); + + it('should return offline if user is guest', async function () { + assert.strictEqual(await User.isOnline(0), false); + }); + + it('should return true', async function () { + assert.strictEqual(await User.isOnline(testUid), true); + }); }); describe('isPrivilegedOrSelf', function () { From d927b763c1cd5a2325de83118a8076051731829f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 26 Jan 2020 22:18:07 -0500 Subject: [PATCH 4/7] fix: escape invalid rules --- src/meta/blacklist.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js index ae3412832d..2c7ddf4678 100644 --- a/src/meta/blacklist.js +++ b/src/meta/blacklist.js @@ -3,6 +3,7 @@ const ipaddr = require('ipaddr.js'); const winston = require('winston'); const _ = require('lodash'); +const validator = require('validator'); const db = require('../database'); const pubsub = require('../pubsub'); @@ -128,7 +129,7 @@ Blacklist.validate = function (rules) { } if (!addr || whitelist.includes(rule)) { - invalid.push(rule); + invalid.push(validator.escape(rule)); return false; } From 9969dd63355e6a82d7e07483d3221889def4fa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 28 Jan 2020 12:42:57 -0500 Subject: [PATCH 5/7] fix: use view_deleted when filtering, closes #8137 --- src/privileges/categories.js | 1 + src/privileges/posts.js | 7 ++++--- src/privileges/topics.js | 9 +++++---- src/topics/index.js | 3 +-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 397796b4a4..6f380b6563 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -110,6 +110,7 @@ module.exports = function (privileges) { return await utils.promiseParallel({ categories: categories.getCategoriesFields(cids, ['disabled']), allowedTo: helpers.isUserAllowedTo(privilege, uid, cids), + view_deleted: helpers.isUserAllowedTo('posts:view_deleted', uid, cids), isAdmin: user.isAdministrator(uid), }); }; diff --git a/src/privileges/posts.js b/src/privileges/posts.js index f8d824f943..ac595c0c31 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -88,16 +88,17 @@ module.exports = function (privileges) { cids = _.uniq(cids); const results = await privileges.categories.getBase(privilege, cids, uid); - cids = cids.filter(function (cid, index) { + const allowedCids = cids.filter(function (cid, index) { return !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin); }); - const cidsSet = new Set(cids); + const cidsSet = new Set(allowedCids); + const canViewDeleted = _.zipObject(cids, results.view_deleted); pids = postData.filter(function (post) { return post.topic && cidsSet.has(post.topic.cid) && - ((!post.topic.deleted && !post.deleted) || results.isAdmin); + ((!post.topic.deleted && !post.deleted) || canViewDeleted[post.topic.cid] || results.isAdmin); }).map(post => post.pid); const data = await plugins.fireHook('filter:privileges.posts.filter', { diff --git a/src/privileges/topics.js b/src/privileges/topics.js index af9e57698d..ee1f6b5ea1 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -68,14 +68,15 @@ module.exports = function (privileges) { } const topicsData = await topics.getTopicsFields(tids, ['tid', 'cid', 'deleted']); - let cids = _.uniq(topicsData.map(topic => topic.cid)); + const cids = _.uniq(topicsData.map(topic => topic.cid)); const results = await privileges.categories.getBase(privilege, cids, uid); - cids = cids.filter((cid, index) => !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin)); + const allowedCids = cids.filter((cid, index) => !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin)); - const cidsSet = new Set(cids); + const cidsSet = new Set(allowedCids); + const canViewDeleted = _.zipObject(cids, results.view_deleted); - tids = topicsData.filter(t => cidsSet.has(t.cid) && (!t.deleted || results.isAdmin)).map(t => t.tid); + tids = topicsData.filter(t => cidsSet.has(t.cid) && (!t.deleted || canViewDeleted[t.cid] || results.isAdmin)).map(t => t.tid); const data = await plugins.fireHook('filter:privileges.topics.filter', { privilege: privilege, diff --git a/src/topics/index.js b/src/topics/index.js index 7473f5754a..57f738b282 100644 --- a/src/topics/index.js +++ b/src/topics/index.js @@ -50,8 +50,7 @@ Topics.getTopics = async function (tids, options) { } tids = await privileges.topics.filterTids('topics:read', tids, uid); - const topics = await Topics.getTopicsByTids(tids, options); - return topics; + return await Topics.getTopicsByTids(tids, options); }; Topics.getTopicsByTids = async function (tids, options) { From 8c48f94b9607ce04afbb0d6d8690bf2ffea5fdcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 28 Jan 2020 13:03:58 -0500 Subject: [PATCH 6/7] fix: #8139, dont allow restore if not deleted by self --- src/privileges/topics.js | 5 +++-- src/topics/data.js | 1 + test/topics.js | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/privileges/topics.js b/src/privileges/topics.js index ee1f6b5ea1..d4b34194ff 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -116,7 +116,7 @@ module.exports = function (privileges) { }; privileges.topics.canDelete = async function (tid, uid) { - const topicData = await topics.getTopicFields(tid, ['cid', 'postcount']); + const topicData = await topics.getTopicFields(tid, ['uid', 'cid', 'postcount', 'deleterUid']); const [isModerator, isAdministrator, isOwner, allowedTo] = await Promise.all([ user.isModerator(uid, topicData.cid), user.isAdministrator(uid), @@ -136,7 +136,8 @@ module.exports = function (privileges) { throw new Error(langKey); } - return allowedTo[0] && (isOwner || isModerator); + const deleterUid = topicData.deleterUid; + return allowedTo[0] && ((isOwner && (deleterUid === 0 || deleterUid === topicData.uid)) || isModerator); }; privileges.topics.canEdit = async function (tid, uid) { diff --git a/src/topics/data.js b/src/topics/data.js index 8ca113fbaf..44625c47f2 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -11,6 +11,7 @@ const intFields = [ 'tid', 'cid', 'uid', 'mainPid', 'postcount', 'viewcount', 'deleted', 'locked', 'pinned', 'timestamp', 'upvotes', 'downvotes', 'lastposttime', + 'deleterUid', ]; module.exports = function (Topics) { diff --git a/test/topics.js b/test/topics.js index 00976ba3f3..c91395407b 100644 --- a/test/topics.js +++ b/test/topics.js @@ -23,9 +23,11 @@ describe('Topic\'s', function () { var categoryObj; var adminUid; var adminJar; + var fooUid; before(async function () { adminUid = await User.create({ username: 'admin', password: '123456' }); + fooUid = await User.create({ username: 'foo' }); await groups.join('administrators', adminUid); adminJar = await helpers.loginUser('admin', '123456'); @@ -572,6 +574,21 @@ describe('Topic\'s', function () { }); }); }); + + it('should not allow user to restore their topic if it was deleted by an admin', async function () { + const result = await topics.post({ + uid: fooUid, + title: 'topic for restore test', + content: 'topic content', + cid: categoryObj.cid, + }); + await socketTopics.delete({ uid: adminUid }, { tids: [result.topicData.tid], cid: categoryObj.cid }); + try { + await socketTopics.restore({ uid: fooUid }, { tids: [result.topicData.tid], cid: categoryObj.cid }); + } catch (err) { + assert.strictEqual(err.message, '[[error:no-privileges]]'); + } + }); }); describe('order pinned topics', function () { From 6d7131fbc5249fe9cf38e9c2afce4d3cdacfb794 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Jan 2020 13:33:31 -0500 Subject: [PATCH 7/7] fix(deps): update dependency nodebb-theme-persona to v10.1.34 (#8140) Co-authored-by: WhiteSource Renovate --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 47938c1133..858a663b79 100644 --- a/install/package.json +++ b/install/package.json @@ -89,7 +89,7 @@ "nodebb-plugin-spam-be-gone": "0.6.7", "nodebb-rewards-essentials": "0.1.2", "nodebb-theme-lavender": "5.0.11", - "nodebb-theme-persona": "10.1.33", + "nodebb-theme-persona": "10.1.34", "nodebb-theme-slick": "1.2.28", "nodebb-theme-vanilla": "11.1.15", "nodebb-widget-essentials": "4.0.18",