Add privilege for accessing user information (#7859)

* Add view users info global privilege

* Show user ip only to global mods and admins

* fix missing comma

* Hide link for users without correct privilege

* move getting privilege information to getAllData

* Hide the link from Global Moderators as well

* Give Global Moderator view:users:info privilege

* Restrict ip in post menu to view:users:info

* add some trailing commas....

* Add privilege to categories test

* Add group privilege to categories test

* add upgrade script

* fix style for TravisCI

* more styling - change spaces to tabs

* some more styling fixes (hopefully final one)

* fix style for Travis CI

* hide ip in chat messages

* Don't show even hidden ips on user profile page
v1.18.x
Opliko 5 years ago committed by Barış Soner Uşaklı
parent 781b3f1a9a
commit b9583ed838

@ -16,7 +16,7 @@
"view-groups": "View Groups",
"allow-local-login": "Local Login",
"allow-group-creation": "Group Create",
"view-users-info": "View Users Info",
"find-category": "Find Category",
"access-category": "Access Category",
"access-topics": "Access Topics",

@ -46,6 +46,9 @@ chatsController.get = async function (req, res, next) {
room.title = room.roomName || room.usernames || '[[pages:chats]]';
room.uid = uid;
room.userslug = req.params.userslug;
room.canViewInfo = await privileges.global.can('view:users:info', uid);
res.render('chats', room);
};

@ -31,6 +31,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) {
const isAdmin = results.isAdmin;
const isGlobalModerator = results.isGlobalModerator;
const isModerator = results.isModerator;
const canViewInfo = results.canViewInfo;
const isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10);
userData.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0);
@ -47,7 +48,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) {
userData.fullname = '';
}
if (isAdmin || isSelf || ((isGlobalModerator || isModerator) && !results.isTargetAdmin)) {
if (isAdmin || isSelf || (canViewInfo && !results.isTargetAdmin)) {
userData.ips = results.ips;
}
@ -86,6 +87,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID) {
moderator: isModerator,
globalMod: isGlobalModerator,
admin: isAdmin,
canViewInfo: canViewInfo,
});
userData.sso = results.sso.associations;
@ -129,6 +131,7 @@ async function getAllData(uid, callerUID) {
canEdit: privileges.users.canEdit(callerUID, uid),
canBanUser: privileges.users.canBanUser(callerUID, uid),
isBlocked: user.blocks.is(uid, callerUID),
canViewInfo: privileges.global.can('view:users:info', callerUID),
});
}
@ -140,9 +143,10 @@ async function getProfileMenu(uid, callerUID) {
visibility: {
self: false,
other: false,
moderator: true,
globalMod: true,
moderator: false,
globalMod: false,
admin: true,
canViewInfo: true,
},
}, {
id: 'sessions',
@ -154,6 +158,7 @@ async function getProfileMenu(uid, callerUID) {
moderator: false,
globalMod: false,
admin: false,
canViewInfo: false,
},
}];
@ -168,6 +173,7 @@ async function getProfileMenu(uid, callerUID) {
moderator: false,
globalMod: false,
admin: false,
canViewInfo: false,
},
});
}
@ -202,6 +208,7 @@ function filterLinks(links, states) {
moderator: true,
globalMod: true,
admin: true,
canViewInfo: true,
...link.visibility };
var permit = Object.keys(states).some(function (state) {

@ -411,7 +411,7 @@ function giveGlobalPrivileges(next) {
privileges.global.give(defaultPrivileges, 'registered-users', next);
},
function (next) {
privileges.global.give(defaultPrivileges.concat(['ban', 'upload:post:file']), 'Global Moderators', next);
privileges.global.give(defaultPrivileges.concat(['ban', 'upload:post:file', 'view:users:info']), 'Global Moderators', next);
},
function (next) {
privileges.global.give(['view:users', 'view:tags', 'view:groups'], 'guests', next);

@ -132,7 +132,7 @@ module.exports = function (middleware) {
// For the account/info page only, allow plain moderators through
if (/user\/.+\/info$/.test(req.path)) {
user.isModeratorOfAnyCategory(req.uid, next);
privileges.global.can('view:users:info', req.uid, next);
} else {
next(null, false);
}

@ -26,6 +26,7 @@ module.exports = function (privileges) {
{ name: '[[admin/manage/privileges:view-groups]]' },
{ name: '[[admin/manage/privileges:allow-local-login]]' },
{ name: '[[admin/manage/privileges:allow-group-creation]]' },
{ name: '[[admin/manage/privileges:view-users-info]]' },
];
privileges.global.userPrivilegeList = [
@ -42,6 +43,7 @@ module.exports = function (privileges) {
'view:groups',
'local:login',
'group:create',
'view:users:info',
];
privileges.global.groupPrivilegeList = privileges.global.userPrivilegeList.map(privilege => 'groups:' + privilege);
@ -81,6 +83,7 @@ module.exports = function (privileges) {
'view:users': privData['view:users'] || isAdministrator,
'view:tags': privData['view:tags'] || isAdministrator,
'view:groups': privData['view:groups'] || isAdministrator,
'view:users:info': privData['view:users:info'] || isAdministrator,
});
};

@ -280,7 +280,7 @@ SocketModules.chats.getMessages = async function (socket, data) {
};
SocketModules.chats.getIP = async function (socket, mid) {
const allowed = await user.isAdminOrGlobalMod(socket.uid);
const allowed = await privileges.global.can('view:users:info', socket.uid);
if (!allowed) {
throw new Error('[[error:no-privilege]]');
}

@ -31,6 +31,7 @@ module.exports = function (SocketPosts) {
tools: plugins.fireHook('filter:post.tools', { pid: data.pid, uid: socket.uid, tools: [] }),
postSharing: social.getActivePostSharing(),
history: posts.diffs.exists(data.pid),
canViewInfo: privileges.global.can('view:users:info', socket.uid),
});
const postData = results.posts;
@ -48,7 +49,7 @@ module.exports = function (SocketPosts) {
postData.display_history = results.history;
postData.toolsVisible = postData.tools.length || postData.display_moderator_tools;
if (!results.isAdmin && !results.isGlobalMod && !results.isModerator) {
if (!results.isAdmin && !results.canViewInfo) {
postData.ip = undefined;
}
return results;

@ -0,0 +1,45 @@
'use strict';
var async = require('async');
var db = require('../../database');
var privileges = require('../../privileges');
var groups = require('../../groups');
module.exports = {
name: 'give mod info privilege',
timestamp: Date.UTC(2019, 9, 8),
method: function (callback) {
async.waterfall([
function (next) {
db.getSortedSetRevRange('categories:cid', 0, -1, next);
},
function (cids, next) {
async.eachSeries(cids, function (cid, next) {
async.waterfall([
function (next) {
givePrivsToModerators(cid, '', next);
},
function (next) {
givePrivsToModerators(cid, 'groups:', next);
},
], next);
}, next);
},
function (next) {
privileges.global.give(['view:users:info'], 'Global Moderators', next);
},
], callback);
function givePrivsToModerators(cid, groupPrefix, callback) {
async.waterfall([
function (next) {
db.getSortedSetRevRange('group:cid:' + cid + ':privileges:' + groupPrefix + 'moderate:members', 0, -1, next);
},
function (members, next) {
async.eachSeries(members, function (member, next) {
groups.join(['cid:0:privileges:view:users:info'], member, next);
}, next);
},
], callback);
}
},
};

@ -767,6 +767,7 @@ describe('Categories', function () {
'search:content': false,
'search:users': false,
'search:tags': false,
'view:users:info': false,
'upload:post:image': false,
'upload:post:file': false,
signature: false,
@ -816,6 +817,7 @@ describe('Categories', function () {
'groups:search:users': true,
'groups:search:tags': true,
'groups:view:users': true,
'groups:view:users:info': false,
'groups:view:tags': true,
'groups:view:groups': true,
'groups:upload:post:image': true,

Loading…
Cancel
Save