feat: manage:categories privilege WIP

This commit is contained in:
Julian Lam
2020-06-02 15:20:12 -04:00
parent 5219a01ae8
commit 5f20eaba01
6 changed files with 75 additions and 11 deletions

View File

@@ -145,7 +145,7 @@ define('admin/manage/privileges', [
autocomplete.user(inputEl, function (ev, ui) {
var defaultPrivileges;
if (ajaxify.url === '/admin/manage/privileges/admin') {
if (ajaxify.data.url === '/admin/manage/privileges/admin') {
defaultPrivileges = ['manage:categories'];
} else {
defaultPrivileges = cid ? ['find', 'read', 'topics:read'] : ['chat'];
@@ -179,7 +179,7 @@ define('admin/manage/privileges', [
autocomplete.group(inputEl, function (ev, ui) {
var defaultPrivileges;
if (ajaxify.url === '/admin/manage/privileges/admin') {
if (ajaxify.data.url === '/admin/manage/privileges/admin') {
defaultPrivileges = ['groups:manage:categories'];
} else {
defaultPrivileges = cid ? ['groups:find', 'groups:read', 'groups:topics:read'] : ['groups:chat'];

View File

@@ -9,6 +9,7 @@ var semver = require('semver');
var user = require('../user');
var meta = require('../meta');
var plugins = require('../plugins');
var privileges = require('../privileges');
var versions = require('../admin/versions');
var controllers = {
@@ -126,4 +127,26 @@ module.exports = function (middleware) {
middleware.admin.renderFooter = function (req, res, data, next) {
req.app.render('admin/footer', data, next);
};
middleware.admin.checkPrivileges = async (req, res, next) => {
// Kick out guests, obviously
if (!req.uid) {
return controllers.helpers.notAllowed(req, res);
}
// Users in "administrators" group are considered super admins
const isAdmin = await user.isAdministrator(req.uid);
if (isAdmin) {
return next();
}
// Otherwise, check for privilege based on page (if not in mapping, deny access)
const path = req.path.replace(/^(\/api)?\/admin\//g, '');
const privilege = privileges.admin.resolve(path);
if (!privilege || !await privileges.admin.can(privilege, req.uid)) {
return controllers.helpers.notAllowed(req, res);
}
return next();
};
};

View File

@@ -22,6 +22,41 @@ module.exports = function (privileges) {
privileges.admin.groupPrivilegeList = privileges.admin.userPrivilegeList.map(privilege => 'groups:' + privilege);
// Mapping for a page route (via direct match or regexp) to a privilege
privileges.admin.routeMap = {
'manage/categories': 'manage:categories',
};
privileges.admin.routeRegexpMap = {
'^manage/categories/\\d+': 'manage:categories',
};
// Mapping for socket call methods to a privilege
privileges.admin.socketMap = {
'admin.categories.getAll': 'manage:categories',
'admin.categories.create': 'manage:categories',
'admin.categories.update': 'manage:categories',
'admin.categories.purge': 'manage:categories',
'admin.categories.copySettingsFrom': 'manage:categories',
};
privileges.admin.resolve = (path) => {
if (privileges.admin.routeMap[path]) {
return privileges.admin.routeMap[path];
}
let privilege;
Object.keys(privileges.admin.routeRegexpMap).forEach((regexp) => {
if (!privilege) {
console.log('here', new RegExp(regexp), path);
if (new RegExp(regexp).test(path)) {
privilege = privileges.admin.routeRegexpMap[regexp];
}
}
});
return privilege;
};
privileges.admin.list = async function () {
async function getLabels() {
return await utils.promiseParallel({
@@ -61,13 +96,10 @@ module.exports = function (privileges) {
// });
// };
// privileges.admin.can = async function (privilege, uid) {
// const [isAdministrator, isUserAllowedTo] = await Promise.all([
// user.isAdministrator(uid),
// helpers.isUserAllowedTo(privilege, uid, [0]),
// ]);
// return isAdministrator || isUserAllowedTo[0];
// };
privileges.admin.can = async function (privilege, uid) {
const isUserAllowedTo = await helpers.isUserAllowedTo(privilege, uid, [0]);
return isUserAllowedTo[0];
};
// privileges.admin.canGroup = async function (privilege, groupName) {
// return await groups.isMember(groupName, 'cid:0:privileges:groups:' + privilege);

View File

@@ -98,8 +98,8 @@ module.exports = async function (app, middleware) {
var ensureLoggedIn = require('connect-ensure-login');
router.all('(/+api|/+api/*?)', middleware.prepareAPI);
router.all('(/+api/admin|/+api/admin/*?)', middleware.isAdmin);
router.all('(/+admin|/+admin/*?)', ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login?local=1'), middleware.applyCSRF, middleware.isAdmin);
router.all('(/+api/admin|/+api/admin/*?)', middleware.admin.checkPrivileges);
router.all('(/+admin|/+admin/*?)', ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login?local=1'), middleware.applyCSRF, middleware.admin.checkPrivileges);
app.use(middleware.stripLeadingSlashes);

View File

@@ -6,6 +6,7 @@ const meta = require('../meta');
const user = require('../user');
const events = require('../events');
const db = require('../database');
const privileges = require('../privileges');
const websockets = require('./index');
const index = require('./index');
const getAdminSearchDict = require('../admin/search').getDictionary;
@@ -37,6 +38,13 @@ SocketAdmin.before = async function (socket, method) {
if (isAdmin) {
return;
}
// Check admin privileges mapping (if not in mapping, deny access)
const privilege = privileges.admin.socketMap[method];
if (privilege && await privileges.admin.can(privilege, socket.uid)) {
return;
}
winston.warn('[socket.io] Call to admin method ( ' + method + ' ) blocked (accessed by uid ' + socket.uid + ')');
throw new Error('[[error:no-privileges]]');
};

View File

@@ -61,6 +61,7 @@ Categories.setPrivilege = async function (socket, data) {
throw new Error('[[error:no-user-or-group]]');
}
console.log('setting', data);
await privileges.categories[data.set ? 'give' : 'rescind'](
Array.isArray(data.privilege) ? data.privilege : [data.privilege], data.cid, data.member
);