2020-05-29 17:23:42 +02:00
|
|
|
'use strict';
|
|
|
|
|
2020-06-11 10:54:26 +02:00
|
|
|
const _ = require('lodash');
|
2020-10-05 16:26:55 +02:00
|
|
|
const { flatMap, filter } = require('lodash/fp');
|
2020-07-01 19:11:04 +02:00
|
|
|
const pmap = require('p-map');
|
2020-10-27 11:27:17 +01:00
|
|
|
const { getBoundActionsBySubject, BOUND_ACTIONS_FOR_FIELDS } = require('../domain/role');
|
|
|
|
const { createPermission } = require('../domain/permission');
|
2020-06-29 16:32:14 +02:00
|
|
|
const createPermissionsManager = require('./permission/permissions-manager');
|
2020-06-09 19:00:57 +02:00
|
|
|
const createConditionProvider = require('./permission/condition-provider');
|
|
|
|
const createPermissionEngine = require('./permission/engine');
|
2020-06-29 16:32:14 +02:00
|
|
|
const actionProvider = require('./permission/action-provider');
|
2020-10-05 16:26:55 +02:00
|
|
|
const { EDITOR_CODE } = require('./constants');
|
2020-06-09 19:00:57 +02:00
|
|
|
|
2020-06-16 11:13:01 +02:00
|
|
|
const conditionProvider = createConditionProvider();
|
2020-06-09 19:00:57 +02:00
|
|
|
const engine = createPermissionEngine(conditionProvider);
|
2020-05-28 13:02:06 +02:00
|
|
|
|
2020-07-20 17:40:01 +02:00
|
|
|
/**
|
|
|
|
* Removes unwanted fields from a permission
|
2020-08-11 16:39:05 +02:00
|
|
|
* @param perm
|
2020-07-20 17:40:01 +02:00
|
|
|
* @returns {*}
|
|
|
|
*/
|
|
|
|
const sanitizePermission = perm => ({
|
|
|
|
..._.pick(perm, ['id', 'action', 'subject', 'fields']),
|
|
|
|
conditions: strapi.admin.services.condition.removeUnkownConditionIds(perm.conditions),
|
|
|
|
});
|
|
|
|
|
2020-05-29 17:23:42 +02:00
|
|
|
/**
|
|
|
|
* Delete permissions of roles in database
|
2020-06-08 15:13:26 +02:00
|
|
|
* @param rolesIds ids of roles
|
2020-05-29 17:23:42 +02:00
|
|
|
* @returns {Promise<array>}
|
|
|
|
*/
|
2020-05-29 11:09:17 +02:00
|
|
|
const deleteByRolesIds = rolesIds => {
|
|
|
|
return strapi.query('permission', 'admin').delete({ role_in: rolesIds });
|
|
|
|
};
|
|
|
|
|
2020-06-08 15:13:26 +02:00
|
|
|
/**
|
|
|
|
* Delete permissions
|
|
|
|
* @param ids ids of permissions
|
|
|
|
* @returns {Promise<array>}
|
|
|
|
*/
|
|
|
|
const deleteByIds = ids => {
|
|
|
|
return strapi.query('permission', 'admin').delete({ id_in: ids });
|
|
|
|
};
|
|
|
|
|
2020-10-05 16:26:55 +02:00
|
|
|
/**
|
|
|
|
* Create many permissions
|
|
|
|
* @param permissions
|
|
|
|
* @returns {Promise<*[]|*>}
|
|
|
|
*/
|
2020-10-19 16:34:02 +02:00
|
|
|
const createMany = async permissions => {
|
2020-10-05 16:26:55 +02:00
|
|
|
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);
|
|
|
|
};
|
|
|
|
|
2020-05-28 11:29:59 +02:00
|
|
|
/**
|
|
|
|
* Find assigned permissions in the database
|
|
|
|
* @param params query params to find the permissions
|
|
|
|
* @returns {Promise<array<Object>>}
|
|
|
|
*/
|
|
|
|
const find = (params = {}) => {
|
|
|
|
return strapi.query('permission', 'admin').find(params, []);
|
|
|
|
};
|
|
|
|
|
2020-06-12 10:28:14 +02:00
|
|
|
/**
|
|
|
|
* Find all permissions for a user
|
|
|
|
* @param roles
|
|
|
|
* @returns {Promise<*[]|*>}
|
|
|
|
*/
|
2020-06-11 10:54:26 +02:00
|
|
|
const findUserPermissions = async ({ roles }) => {
|
|
|
|
if (!_.isArray(roles)) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2020-06-22 13:00:21 +02:00
|
|
|
return strapi
|
|
|
|
.query('permission', 'admin')
|
|
|
|
.find({ role_in: roles.map(_.property('id')), _limit: -1 });
|
2020-06-11 10:54:26 +02:00
|
|
|
};
|
|
|
|
|
2020-06-23 16:31:16 +02:00
|
|
|
/**
|
|
|
|
* Removes permissions in database that don't exist anymore
|
2020-06-24 14:09:43 +02:00
|
|
|
* @returns {Promise<>}
|
2020-06-23 16:31:16 +02:00
|
|
|
*/
|
|
|
|
const cleanPermissionInDatabase = async () => {
|
2020-07-01 19:11:04 +02:00
|
|
|
const pageSize = 200;
|
|
|
|
let page = 0;
|
|
|
|
let total = 1;
|
|
|
|
|
|
|
|
while (page * pageSize < total) {
|
|
|
|
// First, delete permission that don't exist anymore
|
|
|
|
page += 1;
|
|
|
|
const res = await strapi.query('permission', 'admin').findPage({ page, pageSize }, []);
|
|
|
|
total = res.pagination.total;
|
|
|
|
|
|
|
|
const dbPermissions = res.results;
|
|
|
|
const allActionsMap = actionProvider.getAllByMap();
|
|
|
|
const permissionsToRemoveIds = dbPermissions.reduce((idsToDelete, perm) => {
|
|
|
|
if (
|
|
|
|
!allActionsMap.has(perm.action) ||
|
|
|
|
(Array.isArray(allActionsMap.get(perm.action).subjects) &&
|
|
|
|
!allActionsMap.get(perm.action).subjects.includes(perm.subject))
|
|
|
|
) {
|
|
|
|
idsToDelete.push(perm.id);
|
|
|
|
}
|
|
|
|
return idsToDelete;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const deletePromise = deleteByIds(permissionsToRemoveIds);
|
|
|
|
|
|
|
|
// Second, clean fields of permissions (add required ones, remove the non-existing anymore ones)
|
|
|
|
const permissionsInDb = dbPermissions.filter(perm => !permissionsToRemoveIds.includes(perm.id));
|
|
|
|
const permissionsWithCleanFields = strapi.admin.services['content-type'].cleanPermissionFields(
|
2020-08-11 16:39:05 +02:00
|
|
|
permissionsInDb
|
2020-07-01 19:11:04 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
// Update only the ones that need to be updated
|
|
|
|
const permissionsNeedingToBeUpdated = _.differenceWith(
|
|
|
|
permissionsWithCleanFields,
|
|
|
|
permissionsInDb,
|
|
|
|
(a, b) => a.id === b.id && _.xor(a.fields, b.fields).length === 0
|
|
|
|
);
|
2020-10-05 16:26:55 +02:00
|
|
|
const promiseProvider = perm => update({ id: perm.id }, perm);
|
2020-07-01 19:11:04 +02:00
|
|
|
|
|
|
|
//Update the database
|
|
|
|
await Promise.all([
|
|
|
|
deletePromise,
|
|
|
|
pmap(permissionsNeedingToBeUpdated, promiseProvider, {
|
|
|
|
concurrency: 100,
|
|
|
|
stopOnError: true,
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
}
|
2020-06-23 16:31:16 +02:00
|
|
|
};
|
|
|
|
|
2020-10-05 16:26:55 +02:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
);
|
2020-10-19 16:34:02 +02:00
|
|
|
await createMany(permissions);
|
2020-10-05 16:26:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-29 11:09:17 +02:00
|
|
|
module.exports = {
|
2020-10-19 12:34:20 +02:00
|
|
|
createMany,
|
2020-05-28 11:29:59 +02:00
|
|
|
find,
|
2020-05-29 11:09:17 +02:00
|
|
|
deleteByRolesIds,
|
2020-06-08 15:13:26 +02:00
|
|
|
deleteByIds,
|
2020-06-11 10:54:26 +02:00
|
|
|
sanitizePermission,
|
|
|
|
findUserPermissions,
|
2020-06-09 19:00:57 +02:00
|
|
|
actionProvider,
|
2020-06-29 16:32:14 +02:00
|
|
|
createPermissionsManager,
|
2020-06-09 19:00:57 +02:00
|
|
|
engine,
|
|
|
|
conditionProvider,
|
2020-06-23 16:31:16 +02:00
|
|
|
cleanPermissionInDatabase,
|
2020-10-05 16:26:55 +02:00
|
|
|
ensureBoundPermissionsInDatabase,
|
2020-05-29 11:09:17 +02:00
|
|
|
};
|