diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index 1b054dee4e..1b0b005805 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -169,6 +169,7 @@ "user-already-flagged": "You have already flagged this user", "post-flagged-too-many-times": "This post has been flagged by others already", "user-flagged-too-many-times": "This user has been flagged by others already", + "cant-flag-privileged": "You are not allowed to flag the profiles or content of privileged users (moderators/global moderators/admins)", "self-vote": "You cannot vote on your own post", "too-many-downvotes-today": "You can only downvote %1 times a day", "too-many-downvotes-today-user": "You can only downvote a user %1 times a day", diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index ed07c2a6f9..08a9fd260d 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -70,6 +70,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) { userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator; userData.canEdit = results.canEdit; userData.canBan = results.canBanUser; + userData.canFlag = (await privileges.users.canFlag(callerUID, userData.uid)).flag; userData.canChangePassword = isAdmin || (isSelf && !meta.config['password:disableEdit']); userData.isSelf = isSelf; userData.isFollowing = results.isFollowing; diff --git a/src/flags.js b/src/flags.js index ae954d1607..8bf57257fd 100644 --- a/src/flags.js +++ b/src/flags.js @@ -251,6 +251,15 @@ Flags.validate = async function (payload) { throw new Error('[[error:user-banned]]'); } + // Disallow flagging of profiles/content of privileged users + const [targetPrivileged, reporterPrivileged] = await Promise.all([ + user.isPrivileged(target.uid), + user.isPrivileged(reporter.uid), + ]); + if (targetPrivileged && !reporterPrivileged) { + throw new Error('[[error:cant-flag-privileged]]'); + } + if (payload.type === 'post') { const editable = await privileges.posts.canEdit(payload.id, payload.uid); if (!editable.flag && !meta.config['reputation:disabled'] && reporter.reputation < meta.config['min:rep:flag']) { diff --git a/src/privileges/posts.js b/src/privileges/posts.js index cfbfeedb1c..c7ab882aed 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -176,12 +176,20 @@ module.exports = function (privileges) { }; privileges.posts.canFlag = async function (pid, uid) { - const [userReputation, isAdminOrModerator] = await Promise.all([ + const targetUid = await posts.getPostField(pid, 'uid'); + const [userReputation, isAdminOrModerator, targetPrivileged, reporterPrivileged] = await Promise.all([ user.getUserField(uid, 'reputation'), isAdminOrMod(pid, uid), + user.isPrivileged(targetUid), + user.isPrivileged(uid), ]); const minimumReputation = meta.config['min:rep:flag']; - const canFlag = isAdminOrModerator || (userReputation >= minimumReputation); + let canFlag = isAdminOrModerator || (userReputation >= minimumReputation); + + if (targetPrivileged && !reporterPrivileged) { + canFlag = false; + } + return { flag: canFlag }; }; diff --git a/src/privileges/users.js b/src/privileges/users.js index b23df4d198..4c40f3a3f7 100644 --- a/src/privileges/users.js +++ b/src/privileges/users.js @@ -3,6 +3,8 @@ const _ = require('lodash'); +const user = require('../user'); +const meta = require('../meta'); const groups = require('../groups'); const plugins = require('../plugins'); const helpers = require('./helpers'); @@ -107,6 +109,22 @@ module.exports = function (privileges) { return data.canBan; }; + privileges.users.canFlag = async function (callerUid, uid) { + const [userReputation, targetPrivileged, reporterPrivileged] = await Promise.all([ + user.getUserField(callerUid, 'reputation'), + user.isPrivileged(uid), + user.isPrivileged(callerUid), + ]); + const minimumReputation = meta.config['min:rep:flag']; + let canFlag = reporterPrivileged || (userReputation >= minimumReputation); + + if (targetPrivileged && !reporterPrivileged) { + canFlag = false; + } + + return { flag: canFlag }; + }; + privileges.users.hasBanPrivilege = async uid => await hasGlobalPrivilege('ban', uid); privileges.users.hasInvitePrivilege = async uid => await hasGlobalPrivilege('invite', uid);