From d29361f4c9fcdcf74469f476ced8739b90fcb4fb Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 11 Jan 2017 15:06:28 -0500 Subject: [PATCH] added additional visibility masks for profile menu hook, also added isPrivileged user method, closes #5306 --- src/controllers/accounts/helpers.js | 35 +++++++++++++++++++++++++---- src/middleware/index.js | 24 ++++++++++++++++++++ src/user.js | 10 +++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 2ef476a4ef..e2bc008de8 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -119,7 +119,13 @@ helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { userData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; userData['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; userData['email:confirmed'] = !!parseInt(userData['email:confirmed'], 10); - userData.profile_links = filterLinks(results.profile_links.concat(results.profile_menu.links), isSelf); + userData.profile_links = filterLinks(results.profile_links.concat(results.profile_menu.links), { + self: isSelf, + other: !isSelf, + moderator: isModerator, + globalMod: isGlobalModerator, + admin: isAdmin + }); userData.sso = results.sso.associations; userData.status = user.getStatus(userData); @@ -154,9 +160,30 @@ helpers.getBaseUser = function (userslug, callerUID, callback) { helpers.getUserDataByUserSlug(userslug, callerUID, callback); }; -function filterLinks(links, self) { - return links.filter(function (link) { - return link && (link.public || self); +function filterLinks(links, states) { + return links.filter(function (link, index) { + // "public" is the old property, if visibility is defined, discard `public` + if (link.hasOwnProperty('public') && !link.hasOwnProperty('visibility')) { + winston.warn('[account/profileMenu (' + link.id + ')] Use of the `.public` property is deprecated, use `visibility` now'); + return link && (link.public || states.self); + } + + // Default visibility + link.visibility = Object.assign({ + self: true, + other: true, + moderator: true, + globalMod: true, + admin: true + }, link.visibility); + + // Iterate through states and permit if every test passes (or is not defined) + var permit = Object.keys(states).some(function (state) { + return states[state] === link.visibility[state]; + }); + + links[index].public = permit; + return permit; }); } diff --git a/src/middleware/index.js b/src/middleware/index.js index f48aaef748..85e29a879a 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -73,6 +73,30 @@ middleware.ensureSelfOrGlobalPrivilege = function (req, res, next) { } }; +middleware.ensureSelfOrPrivileged = function (req, res, next) { + /* + The "self" part of this middleware hinges on you having used + middleware.exposeUid prior to invoking this middleware. + */ + if (req.user) { + if (req.user.uid === res.locals.uid) { + return next(); + } + + user.isPrivileged(req.uid, function (err, ok) { + if (err) { + return next(err); + } else if (ok) { + return next(); + } else { + controllers.helpers.notAllowed(req, res); + } + }); + } else { + controllers.helpers.notAllowed(req, res); + } +}; + middleware.pageView = function (req, res, next) { analytics.pageView({ ip: req.ip, diff --git a/src/user.js b/src/user.js index 00e5824690..2ae5a4baf5 100644 --- a/src/user.js +++ b/src/user.js @@ -256,6 +256,16 @@ var meta = require('./meta'); privileges.users.isGlobalModerator(uid, callback); }; + User.isPrivileged = function (uid, callback) { + async.parallel([ + async.apply(User.isAdministrator, uid), + async.apply(User.isGlobalModerator, uid), + async.apply(User.isModeratorOfAnyCategory, uid) + ], function (err, results) { + callback(err, results ? results.some(Boolean) : false); + }); + }; + User.isAdminOrGlobalMod = function (uid, callback) { async.parallel({ isAdmin: async.apply(User.isAdministrator, uid),