3 new global privileges
view:users
view:tags
view:groups
v1.18.x
Barış Soner Uşaklı 6 years ago
parent ae779ea4f9
commit c72da5595a

@ -10,6 +10,9 @@
"search-content": "Search Content",
"search-users": "Search Users",
"search-tags": "Search Tags",
"view-users": "View Users",
"view-tags": "View Tags",
"view-groups": "View Groups",
"allow-local-login": "Local Login",
"allow-group-creation": "Group Create",

@ -5,8 +5,6 @@
"min-length": "Minimum Tag Length",
"max-length": "Maximum Tag Length",
"goto-manage": "Click here to visit the tag management page.",
"privacy": "Privacy",
"list-private": "Make the tags list private",
"related-topics": "Related Topics",
"max-related-topics": "Maximum related topics to display (if supported by theme)"
}

@ -14,7 +14,6 @@
"disable-email-changes": "Disable email changes",
"disable-password-changes": "Disable password changes",
"allow-account-deletion": "Allow account deletion",
"user-info-private": "Hide user list and data from guests",
"hide-fullname": "Hide fullname from users",
"hide-email": "Hide email from users",
"themes": "Themes",

@ -40,13 +40,15 @@
return false;
}
var loggedIn = data.config ? data.config.loggedIn : false;
if (item.route.match('/users') && data.user && !data.user.privileges['view:users']) {
return false;
}
if (item.route.match('/users') && data.privateUserInfo && !loggedIn) {
if (item.route.match('/tags') && data.user && !data.user.privileges['view:tags']) {
return false;
}
if (item.route.match('/tags') && data.privateTagListing && !loggedIn) {
if (item.route.match('/groups') && data.user && !data.user.privileges['view:groups']) {
return false;
}
@ -179,7 +181,7 @@
}
return states.map(function (priv) {
var guestDisabled = ['groups:moderate', 'groups:posts:upvote', 'groups:posts:downvote', 'groups:local:login', 'groups:group:create'];
var spidersEnabled = ['groups:find', 'groups:read', 'groups:topics:read'];
var spidersEnabled = ['groups:find', 'groups:read', 'groups:topics:read', 'groups:view:users', 'groups:view:tags', 'groups:view:groups'];
var disabled =
(member === 'guests' && guestDisabled.includes(priv.name)) ||
(member === 'spiders' && !spidersEnabled.includes(priv.name));

@ -39,7 +39,7 @@ exports.handleURIErrors = function handleURIErrors(err, req, res, next) {
exports.handleErrors = function handleErrors(err, req, res, next) { // eslint-disable-line no-unused-vars
var cases = {
EBADCSRFTOKEN: function () {
winston.error(req.path + '\n', err.message);
winston.error(req.path + '\n' + err.message);
res.sendStatus(403);
},
'blacklisted-ip': function () {

@ -13,6 +13,7 @@ var meta = require('../meta');
var posts = require('../posts');
var batch = require('../batch');
var events = require('../events');
var privileges = require('../privileges');
var accountHelpers = require('./accounts/helpers');
var userController = module.exports;
@ -84,27 +85,33 @@ userController.getUserDataByField = function (callerUid, field, fieldValue, call
};
userController.getUserDataByUID = function (callerUid, uid, callback) {
if (parseInt(callerUid, 10) <= 0 && meta.config.privateUserInfo) {
return callback(new Error('[[error:no-privileges]]'));
}
if (!parseInt(uid, 10)) {
return callback(new Error('[[error:no-user]]'));
}
async.waterfall([
function (next) {
privileges.global.can('view:users', callerUid, next);
},
function (canView, next) {
if (!canView) {
return next(new Error('[[error:no-privileges]]'));
}
async.parallel({
userData: async.apply(user.getUserData, uid),
settings: async.apply(user.getSettings, uid),
}, next);
},
function (results, next) {
if (!results.userData) {
return next(new Error('[[error:no-user]]'));
}
async.parallel({
userData: async.apply(user.getUserData, uid),
settings: async.apply(user.getSettings, uid),
}, function (err, results) {
if (err || !results.userData) {
return callback(err || new Error('[[error:no-user]]'));
}
results.userData.email = results.settings.showemail && !meta.config.hideEmail ? results.userData.email : undefined;
results.userData.fullname = results.settings.showfullname && !meta.config.hideFullname ? results.userData.fullname : undefined;
results.userData.email = results.settings.showemail && !meta.config.hideEmail ? results.userData.email : undefined;
results.userData.fullname = results.settings.showfullname && !meta.config.hideFullname ? results.userData.fullname : undefined;
callback(null, results.userData);
});
next(null, results.userData);
},
], callback);
};
userController.exportPosts = function (req, res, next) {

@ -385,7 +385,8 @@ function giveGlobalPrivileges(next) {
var privileges = require('./privileges');
var defaultPrivileges = [
'chat', 'upload:post:image', 'signature', 'search:content',
'search:users', 'search:tags', 'local:login',
'search:users', 'search:tags', 'view:users', 'view:tags', 'view:groups',
'local:login',
];
privileges.global.give(defaultPrivileges, 'registered-users', next);
}

@ -196,8 +196,6 @@ module.exports = function (middleware) {
templateValues.defaultLang = meta.config.defaultLang || 'en-GB';
templateValues.userLang = res.locals.config.userLang;
templateValues.languageDirection = results.languageDirection;
templateValues.privateUserInfo = meta.config.privateUserInfo;
templateValues.privateTagListing = meta.config.privateTagListing;
templateValues.template = { name: res.locals.template };
templateValues.template[res.locals.template] = true;

@ -13,8 +13,8 @@ var plugins = require('../plugins');
var meta = require('../meta');
var user = require('../user');
var groups = require('../groups');
var analytics = require('../analytics');
var privileges = require('../privileges');
var controllers = {
api: require('./../controllers/api'),
@ -112,11 +112,12 @@ middleware.routeTouchIcon = function routeTouchIcon(req, res) {
};
middleware.privateTagListing = function privateTagListing(req, res, next) {
if (!req.loggedIn && meta.config.privateTagListing) {
privileges.global.can('view:tags', req.uid, function (err, canView) {
if (err || canView) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
} else {
next();
}
});
};
middleware.exposeGroupName = function exposeGroupName(req, res, next) {

@ -2,6 +2,7 @@
var async = require('async');
var nconf = require('nconf');
var winston = require('winston');
var meta = require('../meta');
var user = require('../user');
@ -87,11 +88,26 @@ module.exports = function (middleware) {
}
middleware.checkGlobalPrivacySettings = function checkGlobalPrivacySettings(req, res, next) {
if (!req.loggedIn && meta.config.privateUserInfo) {
return middleware.authenticate(req, res, next);
}
winston.warn('[middleware], checkGlobalPrivacySettings deprecated, use canViewUsers or canViewGroups');
middleware.canViewUsers(req, res, next);
};
middleware.canViewUsers = function canViewUsers(req, res, next) {
privileges.global.can('view:users', req.uid, function (err, canView) {
if (err || canView) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
});
};
next();
middleware.canViewGroups = function canViewGroups(req, res, next) {
privileges.global.can('view:groups', req.uid, function (err, canView) {
if (err || canView) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
});
};
middleware.checkAccountPermissions = function checkAccountPermissions(req, res, next) {

@ -21,6 +21,9 @@ module.exports = function (privileges) {
{ name: '[[admin/manage/privileges:search-content]]' },
{ name: '[[admin/manage/privileges:search-users]]' },
{ name: '[[admin/manage/privileges:search-tags]]' },
{ name: '[[admin/manage/privileges:view-users]]' },
{ name: '[[admin/manage/privileges:view-tags]]' },
{ name: '[[admin/manage/privileges:view-groups]]' },
{ name: '[[admin/manage/privileges:allow-local-login]]' },
{ name: '[[admin/manage/privileges:allow-group-creation]]' },
];
@ -34,6 +37,9 @@ module.exports = function (privileges) {
'search:content',
'search:users',
'search:tags',
'view:users',
'view:tags',
'view:groups',
'local:login',
'group:create',
];
@ -94,6 +100,9 @@ module.exports = function (privileges) {
'search:content': privData['search:content'] || isAdminOrMod,
'search:users': privData['search:users'] || isAdminOrMod,
'search:tags': privData['search:tags'] || isAdminOrMod,
'view:users': privData['view:users'] || isAdminOrMod,
'view:tags': privData['view:tags'] || isAdminOrMod,
'view:groups': privData['view:groups'] || isAdminOrMod,
}, next);
},
], callback);

@ -4,8 +4,8 @@ var helpers = require('./helpers');
var setupPageRoute = helpers.setupPageRoute;
module.exports = function (app, middleware, controllers) {
var middlewares = [middleware.checkGlobalPrivacySettings, middleware.exposeUid];
var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions, middleware.exposeUid];
var middlewares = [middleware.canViewUsers, middleware.exposeUid];
var accountMiddlewares = [middleware.canViewUsers, middleware.checkAccountPermissions, middleware.exposeUid];
setupPageRoute(app, '/me/*', middleware, [], middleware.redirectMeToUserslug);
setupPageRoute(app, '/uid/:uid*', middleware, [], middleware.redirectUidToUserslug);

@ -16,10 +16,10 @@ module.exports = function (app, middleware, controllers) {
}
}, controllers.api.getConfig);
router.get('/me', middleware.checkGlobalPrivacySettings, controllers.user.getCurrentUser);
router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUID);
router.get('/user/username/:username', middleware.checkGlobalPrivacySettings, controllers.user.getUserByUsername);
router.get('/user/email/:email', middleware.checkGlobalPrivacySettings, controllers.user.getUserByEmail);
router.get('/me', middleware.canViewUsers, controllers.user.getCurrentUser);
router.get('/user/uid/:uid', middleware.canViewUsers, controllers.user.getUserByUID);
router.get('/user/username/:username', middleware.canViewUsers, controllers.user.getUserByUsername);
router.get('/user/email/:email', middleware.canViewUsers, controllers.user.getUserByEmail);
router.get('/user/uid/:userslug/export/posts', middleware.checkAccountPermissions, middleware.exposeUid, controllers.user.exportPosts);
router.get('/user/uid/:userslug/export/uploads', middleware.checkAccountPermissions, middleware.exposeUid, controllers.user.exportUploads);
@ -40,8 +40,8 @@ module.exports = function (app, middleware, controllers) {
var middlewares = [middleware.maintenanceMode, multipartMiddleware, middleware.validateFiles, middleware.applyCSRF];
router.post('/post/upload', middlewares, uploadsController.uploadPost);
router.post('/topic/thumb/upload', middlewares, uploadsController.uploadThumb);
router.post('/user/:userslug/uploadpicture', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadPicture);
router.post('/user/:userslug/uploadpicture', middlewares.concat([middleware.authenticate, middleware.canViewUsers, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadPicture);
router.post('/user/:userslug/uploadcover', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadCoverPicture);
router.post('/user/:userslug/uploadcover', middlewares.concat([middleware.authenticate, middleware.canViewUsers, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadCoverPicture);
router.post('/groups/uploadpicture', middlewares.concat([middleware.authenticate]), controllers.groups.uploadCover);
};

@ -77,13 +77,13 @@ function categoryRoutes(app, middleware, controllers) {
}
function userRoutes(app, middleware, controllers) {
var middlewares = [middleware.checkGlobalPrivacySettings];
var middlewares = [middleware.canViewUsers];
setupPageRoute(app, '/users', middleware, middlewares, controllers.users.index);
}
function groupRoutes(app, middleware, controllers) {
var middlewares = [middleware.checkGlobalPrivacySettings];
var middlewares = [middleware.canViewGroups];
setupPageRoute(app, '/groups', middleware, middlewares, controllers.groups.list);
setupPageRoute(app, '/groups/:slug', middleware, middlewares, controllers.groups.details);

@ -0,0 +1,28 @@
'use strict';
var async = require('async');
var privileges = require('../../privileges');
module.exports = {
name: 'Global view privileges',
timestamp: Date.UTC(2019, 0, 5),
method: function (callback) {
var meta = require('../../meta');
var tasks = [
async.apply(privileges.global.give, ['view:users', 'view:tags', 'view:groups'], 'registered-users'),
];
if (parseInt(meta.config.privateUserInfo, 10) !== 1) {
tasks.push(async.apply(privileges.global.give, ['view:users', 'view:groups'], 'guests'));
tasks.push(async.apply(privileges.global.give, ['view:users', 'view:groups'], 'spiders'));
}
if (parseInt(meta.config.privateTagListing, 10) !== 1) {
tasks.push(async.apply(privileges.global.give, ['view:tags'], 'guests'));
tasks.push(async.apply(privileges.global.give, ['view:tags'], 'spiders'));
}
async.series(tasks, callback);
},
};

@ -3,7 +3,7 @@
var privileges = require('../../privileges');
module.exports = {
name: 'Update category watch data',
name: 'Group create global privilege',
timestamp: Date.UTC(2019, 0, 4),
method: function (callback) {
var meta = require('../../meta');

@ -25,21 +25,6 @@
</div>
</div>
<div class="row">
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/tags:privacy]]</div>
<div class="col-sm-10 col-xs-12">
<form>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input class="mdl-switch__input" type="checkbox" data-field="privateTagListing">
<span class="mdl-switch__label">[[admin/settings/tags:list-private]]</span>
</label>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/tags:related-topics]]</div>
<div class="col-sm-10 col-xs-12">

@ -65,12 +65,6 @@
<span class="mdl-switch__label"><strong>[[admin/settings/user:allow-account-deletion]]</strong></span>
</label>
</div>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input class="mdl-switch__input" type="checkbox" data-field="privateUserInfo">
<span class="mdl-switch__label"><strong>[[admin/settings/user:user-info-private]]</strong></span>
</label>
</div>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input class="mdl-switch__input" type="checkbox" data-field="hideFullname">

@ -744,6 +744,9 @@ describe('Categories', function () {
signature: false,
'local:login': false,
'group:create': false,
'view:users': false,
'view:tags': false,
'view:groups': false,
});
done();
@ -784,6 +787,9 @@ describe('Categories', function () {
'groups:search:content': true,
'groups:search:users': true,
'groups:search:tags': true,
'groups:view:users': true,
'groups:view:tags': true,
'groups:view:groups': true,
'groups:upload:post:image': true,
'groups:upload:post:file': false,
'groups:signature': true,

@ -1336,14 +1336,15 @@ describe('Controllers', function () {
});
});
it('should return 401 if privateUserInfo is turned on', function (done) {
meta.config.privateUserInfo = 1;
request(nconf.get('url') + '/api/user/foo', { json: true }, function (err, res, body) {
meta.config.privateUserInfo = 0;
it('should return 401 if user does not have view:users privilege', function (done) {
privileges.global.rescind(['view:users'], 'guests', function (err) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.equal(body, 'not-authorized');
done();
request(nconf.get('url') + '/api/user/foo', { json: true }, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 401);
assert.equal(body, 'not-authorized');
privileges.global.give(['view:users'], 'guests', done);
});
});
});

@ -236,10 +236,19 @@ function setupDefaultConfigs(meta, next) {
function giveDefaultGlobalPrivileges(next) {
var privileges = require('../../src/privileges');
privileges.global.give([
'chat', 'upload:post:image', 'signature', 'search:content',
'search:users', 'search:tags', 'local:login',
], 'registered-users', next);
async.waterfall([
function (next) {
privileges.global.give([
'chat', 'upload:post:image', 'signature', 'search:content',
'search:users', 'search:tags', 'local:login', 'view:users', 'view:tags', 'view:groups',
], 'registered-users', next);
},
function (next) {
privileges.global.give([
'view:users', 'view:tags', 'view:groups',
], 'guests', next);
},
], next);
}
function enableDefaultPlugins(callback) {

@ -13,24 +13,39 @@ describe('helpers', function () {
done();
});
it('should return false if route is /users and privateUserInfo is on and user is not logged in', function (done) {
it('should return false if route is /users and user does not have view:users privilege', function (done) {
var flag = helpers.displayMenuItem({
navigation: [{ route: '/users' }],
privateUserInfo: true,
config: {
loggedIn: false,
user: {
privileges: {
'view:users': false,
},
},
}, 0);
assert(!flag);
done();
});
it('should return false if route is /tags and privateTagListing is on and user is not logged in', function (done) {
it('should return false if route is /tags and user does not have view:tags privilege', function (done) {
var flag = helpers.displayMenuItem({
navigation: [{ route: '/tags' }],
privateTagListing: true,
config: {
loggedIn: false,
user: {
privileges: {
'view:tags': false,
},
},
}, 0);
assert(!flag);
done();
});
it('should return false if route is /groups and user does not have view:groups privilege', function (done) {
var flag = helpers.displayMenuItem({
navigation: [{ route: '/groups' }],
user: {
privileges: {
'view:groups': false,
},
},
}, 0);
assert(!flag);

Loading…
Cancel
Save