mirror of
https://github.com/strapi/strapi.git
synced 2025-12-27 15:13:21 +00:00
Ensure bound permissions in database (#8180)
* Ensure bound permissions in database Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Refactor, handle missing fields & fix e2e tests Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu>
This commit is contained in:
parent
ded8bc37bb
commit
eb5a94501e
@ -17,6 +17,7 @@ module.exports = async () => {
|
||||
registerAdminConditions();
|
||||
registerPermissionActions();
|
||||
await strapi.admin.services.permission.cleanPermissionInDatabase();
|
||||
await strapi.admin.services.permission.ensureBoundPermissionsInDatabase();
|
||||
await strapi.admin.services.user.migrateUsers();
|
||||
await strapi.admin.services.role.createRolesIfNoneExist();
|
||||
await strapi.admin.services.permission.resetSuperAdminPermissions();
|
||||
|
||||
29
packages/strapi-admin/domain/role.js
Normal file
29
packages/strapi-admin/domain/role.js
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
contentTypes: { hasDraftAndPublish },
|
||||
} = require('strapi-utils');
|
||||
const {
|
||||
AUTHOR_CODE,
|
||||
PUBLISH_ACTION,
|
||||
DELETE_ACTION,
|
||||
UPDATE_ACTION,
|
||||
CREATE_ACTION,
|
||||
READ_ACTION,
|
||||
} = require('../services/constants');
|
||||
|
||||
const BOUND_ACTIONS = [READ_ACTION, CREATE_ACTION, UPDATE_ACTION, DELETE_ACTION, PUBLISH_ACTION];
|
||||
|
||||
const BOUND_ACTIONS_FOR_FIELDS = [READ_ACTION, CREATE_ACTION, UPDATE_ACTION];
|
||||
|
||||
const getBoundActionsBySubject = (role, subject) => {
|
||||
const model = strapi.getModel(subject);
|
||||
|
||||
if (role.code === AUTHOR_CODE || !hasDraftAndPublish(model)) {
|
||||
return [READ_ACTION, UPDATE_ACTION, CREATE_ACTION, DELETE_ACTION];
|
||||
}
|
||||
|
||||
return BOUND_ACTIONS;
|
||||
};
|
||||
|
||||
module.exports = { getBoundActionsBySubject, BOUND_ACTIONS, BOUND_ACTIONS_FOR_FIELDS };
|
||||
@ -2,4 +2,9 @@ module.exports = {
|
||||
SUPER_ADMIN_CODE: 'strapi-super-admin',
|
||||
EDITOR_CODE: 'strapi-editor',
|
||||
AUTHOR_CODE: 'strapi-author',
|
||||
READ_ACTION: 'plugins::content-manager.explorer.read',
|
||||
CREATE_ACTION: 'plugins::content-manager.explorer.create',
|
||||
UPDATE_ACTION: 'plugins::content-manager.explorer.update',
|
||||
DELETE_ACTION: 'plugins::content-manager.explorer.delete',
|
||||
PUBLISH_ACTION: 'plugins::content-manager.explorer.publish',
|
||||
};
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const { flatMap, filter } = require('lodash/fp');
|
||||
const pmap = require('p-map');
|
||||
const { createPermission } = require('../domain/permission');
|
||||
const { validatePermissionsExist } = require('../validation/permission');
|
||||
const createPermissionsManager = require('./permission/permissions-manager');
|
||||
const createConditionProvider = require('./permission/condition-provider');
|
||||
const createPermissionEngine = require('./permission/engine');
|
||||
const actionProvider = require('./permission/action-provider');
|
||||
const { EDITOR_CODE } = require('./constants');
|
||||
const { getBoundActionsBySubject, BOUND_ACTIONS_FOR_FIELDS } = require('../domain/role');
|
||||
const { createPermission } = require('../domain/permission');
|
||||
|
||||
const conditionProvider = createConditionProvider();
|
||||
const engine = createPermissionEngine(conditionProvider);
|
||||
@ -54,6 +57,25 @@ const deleteByIds = ids => {
|
||||
return strapi.query('permission', 'admin').delete({ id_in: ids });
|
||||
};
|
||||
|
||||
/**
|
||||
* Create many permissions
|
||||
* @param permissions
|
||||
* @returns {Promise<*[]|*>}
|
||||
*/
|
||||
const createMany = async permissions => {
|
||||
return strapi.query('permission', 'admin').createMany(permissions);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a permission
|
||||
* @returns {Promise<*[]|*>}
|
||||
* @param params
|
||||
* @param attributes
|
||||
*/
|
||||
const update = async (params, attributes) => {
|
||||
return strapi.query('permission', 'admin').update(params, attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find assigned permissions in the database
|
||||
* @param params query params to find the permissions
|
||||
@ -100,9 +122,7 @@ const assign = async (roleId, permissions = []) => {
|
||||
await deleteByIds(permissionsToDelete.map(p => p.id));
|
||||
}
|
||||
if (permissionsToAdd.length > 0) {
|
||||
const createdPermissions = await strapi
|
||||
.query('permission', 'admin')
|
||||
.createMany(permissionsToAdd);
|
||||
const createdPermissions = await createMany(permissionsToAdd);
|
||||
permissionsToReturn.push(...createdPermissions.map(p => ({ ...p, role: p.role.id })));
|
||||
}
|
||||
|
||||
@ -166,8 +186,7 @@ const cleanPermissionInDatabase = async () => {
|
||||
permissionsInDb,
|
||||
(a, b) => a.id === b.id && _.xor(a.fields, b.fields).length === 0
|
||||
);
|
||||
const promiseProvider = perm =>
|
||||
strapi.query('permission', 'admin').update({ id: perm.id }, perm);
|
||||
const promiseProvider = perm => update({ id: perm.id }, perm);
|
||||
|
||||
//Update the database
|
||||
await Promise.all([
|
||||
@ -180,6 +199,53 @@ const cleanPermissionInDatabase = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const ensureBoundPermissionsInDatabase = async () => {
|
||||
if (strapi.EE) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentTypes = Object.values(strapi.contentTypes);
|
||||
const editorRole = await strapi.query('role', 'admin').findOne({ code: EDITOR_CODE }, []);
|
||||
|
||||
if (_.isNil(editorRole)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const contentType of contentTypes) {
|
||||
const boundActions = getBoundActionsBySubject(editorRole, contentType.uid);
|
||||
const permissions = await strapi.query('permission', 'admin').find(
|
||||
{
|
||||
subject: contentType.uid,
|
||||
action_in: boundActions,
|
||||
role: editorRole.id,
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
if (permissions.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fields = _.flow(flatMap('fields'), filter(_.negate(_.isNil)), _.uniq)(permissions);
|
||||
|
||||
// Handle the scenario where permissions are missing
|
||||
|
||||
const missingActions = _.difference(boundActions, _.map(permissions, 'action'));
|
||||
|
||||
if (missingActions.length > 0) {
|
||||
const permissions = missingActions.map(action =>
|
||||
createPermission({
|
||||
action,
|
||||
subject: contentType.uid,
|
||||
role: editorRole.id,
|
||||
fields: BOUND_ACTIONS_FOR_FIELDS.includes(action) ? fields : null,
|
||||
})
|
||||
);
|
||||
await createMany(permissions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset super admin permissions (giving it all permissions)
|
||||
* @returns {Promise<>}
|
||||
@ -225,4 +291,5 @@ module.exports = {
|
||||
conditionProvider,
|
||||
cleanPermissionInDatabase,
|
||||
resetSuperAdminPermissions,
|
||||
ensureBoundPermissionsInDatabase,
|
||||
};
|
||||
|
||||
@ -1,38 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const {
|
||||
yup,
|
||||
formatYupErrors,
|
||||
contentTypes: { hasDraftAndPublish },
|
||||
} = require('strapi-utils');
|
||||
const { yup, formatYupErrors } = require('strapi-utils');
|
||||
const validators = require('./common-validators');
|
||||
const { AUTHOR_CODE } = require('../services/constants');
|
||||
const { AUTHOR_CODE, PUBLISH_ACTION } = require('../services/constants');
|
||||
const {
|
||||
BOUND_ACTIONS_FOR_FIELDS,
|
||||
BOUND_ACTIONS,
|
||||
getBoundActionsBySubject,
|
||||
} = require('../domain/role');
|
||||
|
||||
const handleReject = error => Promise.reject(formatYupErrors(error));
|
||||
|
||||
// validatedUpdatePermissionsInput
|
||||
|
||||
const READ_ACTION = 'plugins::content-manager.explorer.read';
|
||||
const CREATE_ACTION = 'plugins::content-manager.explorer.create';
|
||||
const UPDATE_ACTION = 'plugins::content-manager.explorer.update';
|
||||
const DELETE_ACTION = 'plugins::content-manager.explorer.delete';
|
||||
const PUBLISH_ACTION = 'plugins::content-manager.explorer.publish';
|
||||
|
||||
const BOUND_ACTIONS = [READ_ACTION, CREATE_ACTION, UPDATE_ACTION, DELETE_ACTION, PUBLISH_ACTION];
|
||||
|
||||
const BOUND_ACTIONS_FOR_FIELDS = [READ_ACTION, CREATE_ACTION, UPDATE_ACTION];
|
||||
|
||||
const getBoundActionsBySubject = (role, subject) => {
|
||||
const model = strapi.getModel(subject);
|
||||
|
||||
if (role.code === AUTHOR_CODE || !hasDraftAndPublish(model)) {
|
||||
return [READ_ACTION, UPDATE_ACTION, CREATE_ACTION, DELETE_ACTION];
|
||||
}
|
||||
|
||||
return BOUND_ACTIONS;
|
||||
};
|
||||
|
||||
const actionFieldsAreEqual = (a, b) => {
|
||||
const aFields = a.fields || [];
|
||||
const bFields = b.fields || [];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user