mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +00:00
Rework policies resolving (allow policy generators) / Add hasPermissions policy
Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu>
This commit is contained in:
parent
85ea0abdc8
commit
b3f602d207
23
packages/strapi-admin/config/policies/hasPermissions.js
Normal file
23
packages/strapi-admin/config/policies/hasPermissions.js
Normal file
@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
const { validateHasPermissionsInput } = require('../../validation/policies/hasPermissions');
|
||||
|
||||
module.exports = permissions => {
|
||||
try {
|
||||
validateHasPermissionsInput(permissions);
|
||||
} catch {
|
||||
throw new Error('Invalid objects submitted to admin::hasPermissions policy.');
|
||||
}
|
||||
|
||||
return async (ctx, next) => {
|
||||
const { userAbility: ability } = ctx.state;
|
||||
|
||||
const isAuthorized = permissions.every(({ action, subject }) => ability.can(action, subject));
|
||||
|
||||
if (!isAuthorized) {
|
||||
throw strapi.errors.forbidden();
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
};
|
22
packages/strapi-admin/validation/policies/hasPermissions.js
Normal file
22
packages/strapi-admin/validation/policies/hasPermissions.js
Normal file
@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
const { yup, formatYupErrors } = require('strapi-utils');
|
||||
|
||||
const hasPermissionsSchema = yup.array().of(
|
||||
yup.object().shape({
|
||||
action: yup.string().required(),
|
||||
subject: yup.string(),
|
||||
})
|
||||
);
|
||||
|
||||
const validateHasPermissionsInput = data => {
|
||||
try {
|
||||
return hasPermissionsSchema.validateSync(data, { strict: true, abortEarly: true });
|
||||
} catch (e) {
|
||||
throw new Error(formatYupErrors(e));
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
validateHasPermissionsInput,
|
||||
};
|
@ -5,41 +5,57 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
const get = (policy, plugin, apiName) => {
|
||||
if (globalPolicyExists(policy)) {
|
||||
return parsePolicy(getGlobalPolicy(policy));
|
||||
const GLOBAL_PREFIX = 'global::';
|
||||
const PLUGIN_PREFIX = 'plugins::';
|
||||
const ADMIN_PREFIX = 'admin::';
|
||||
const APPLICATION_PREFIX = 'application::';
|
||||
|
||||
const isPolicyGenerator = _.isArray;
|
||||
|
||||
const getPolicyIn = (container, policy) =>
|
||||
_.get(container, ['config', 'policies', _.toLower(policy)]);
|
||||
|
||||
const policyExistsIn = (container, policy) => !_.isUndefined(getPolicyIn(container, policy));
|
||||
|
||||
const stripPolicy = (policy, prefix) => policy.replace(prefix, '');
|
||||
|
||||
const createPolicy = (policyName, args) => ({ policyName, args });
|
||||
|
||||
const resolveHandler = policy => (_.isFunction(policy) ? policy : policy.handler);
|
||||
|
||||
const parsePolicy = policy =>
|
||||
isPolicyGenerator(policy) ? createPolicy(...policy) : createPolicy(policy);
|
||||
|
||||
const resolvePolicy = policyName => {
|
||||
for (const policyModel of Object.values(policyModelsProvider)) {
|
||||
if (policyModel.exists(policyName)) {
|
||||
return resolveHandler(policyModel.get)(policyName);
|
||||
}
|
||||
}
|
||||
|
||||
if (pluginPolicyExists(policy)) {
|
||||
return parsePolicy(getPluginPolicy(policy));
|
||||
}
|
||||
|
||||
if (adminPolicyExists(policy)) {
|
||||
return parsePolicy(getAdminPolicy(policy));
|
||||
}
|
||||
|
||||
if (APIPolicyExists(policy)) {
|
||||
return parsePolicy(getAPIPolicy(policy));
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const getLegacyPolicy = (policy, plugin, apiName) => {
|
||||
let [absoluteApiName, policyName] = policy.split('.');
|
||||
let absoluteApi = _.get(strapi.api, absoluteApiName);
|
||||
|
||||
if (policyExistsIn(absoluteApi, policyName)) {
|
||||
return parsePolicy(getPolicyIn(absoluteApi, policyName));
|
||||
return resolveHandler(getPolicyIn(absoluteApi, policyName));
|
||||
}
|
||||
|
||||
const pluginPolicy = `${PLUGIN_PREFIX}${plugin}.${policy}`;
|
||||
|
||||
if (plugin && pluginPolicyExists(pluginPolicy)) {
|
||||
return parsePolicy(getPluginPolicy(pluginPolicy));
|
||||
if (plugin && policyModelsProvider.plugin.exists(pluginPolicy)) {
|
||||
return resolveHandler(policyModelsProvider.plugin.get(pluginPolicy));
|
||||
}
|
||||
|
||||
const api = _.get(strapi.api, apiName);
|
||||
if (api && policyExistsIn(api, policy)) {
|
||||
return parsePolicy(getPolicyIn(api, policy));
|
||||
return resolveHandler(getPolicyIn(api, policy));
|
||||
}
|
||||
|
||||
throw new Error(`Could not find policy "${policy}"`);
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
|
||||
@ -48,7 +64,7 @@ const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
|
||||
endpoint: `${method} ${endpoint}`,
|
||||
controller: _.toLower(controller),
|
||||
action: _.toLower(action),
|
||||
splittedEndpoint: endpoint,
|
||||
splitEndpoint: endpoint,
|
||||
verb: _.toLower(method),
|
||||
plugin,
|
||||
};
|
||||
@ -57,70 +73,76 @@ const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const parsePolicy = policy => {
|
||||
if (_.isFunction(policy)) {
|
||||
return policy;
|
||||
const createPolicyModelsProvider = () => ({
|
||||
APIPolicy: {
|
||||
is(policy) {
|
||||
return _.startsWith(policy, APPLICATION_PREFIX);
|
||||
},
|
||||
exists(policy) {
|
||||
return this.is(policy) && !_.isUndefined(this.get(policy));
|
||||
},
|
||||
get: policy => {
|
||||
const [, policyWithoutPrefix] = policy.split('::');
|
||||
const [api = '', policyName = ''] = policyWithoutPrefix.split('.');
|
||||
return getPolicyIn(_.get(strapi, ['api', api]), policyName);
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
is(policy) {
|
||||
return _.startsWith(policy, ADMIN_PREFIX);
|
||||
},
|
||||
exists(policy) {
|
||||
return this.is(policy) && !_.isUndefined(this.get(policy));
|
||||
},
|
||||
get: policy => {
|
||||
return getPolicyIn(_.get(strapi, 'admin'), stripPolicy(policy, ADMIN_PREFIX));
|
||||
},
|
||||
},
|
||||
plugin: {
|
||||
is(policy) {
|
||||
return _.startsWith(policy, PLUGIN_PREFIX);
|
||||
},
|
||||
exists(policy) {
|
||||
return this.is(policy) && !_.isUndefined(this.get(policy));
|
||||
},
|
||||
get(policy) {
|
||||
const [plugin = '', policyName = ''] = stripPolicy(policy, PLUGIN_PREFIX).split('.');
|
||||
return getPolicyIn(_.get(strapi, ['plugins', plugin]), policyName);
|
||||
},
|
||||
},
|
||||
global: {
|
||||
is(policy) {
|
||||
return _.startsWith(policy, GLOBAL_PREFIX);
|
||||
},
|
||||
exists(policy) {
|
||||
return this.is(policy) && !_.isUndefined(this.get(policy));
|
||||
},
|
||||
get(policy) {
|
||||
return getPolicyIn(strapi, stripPolicy(policy, GLOBAL_PREFIX));
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const policyModelsProvider = createPolicyModelsProvider();
|
||||
|
||||
const get = (policy, plugin, apiName) => {
|
||||
const { policyName, args } = parsePolicy(policy);
|
||||
|
||||
const resolvedPolicy = resolvePolicy(policyName);
|
||||
|
||||
if (resolvedPolicy !== undefined) {
|
||||
return isPolicyGenerator(policy) ? resolvedPolicy(args) : resolvedPolicy;
|
||||
}
|
||||
|
||||
return policy.handler;
|
||||
const legacyPolicy = getLegacyPolicy(policy, plugin, apiName);
|
||||
|
||||
if (legacyPolicy !== undefined) {
|
||||
return legacyPolicy;
|
||||
}
|
||||
|
||||
throw new Error(`Could not find policy "${policy}"`);
|
||||
};
|
||||
|
||||
const GLOBAL_PREFIX = 'global::';
|
||||
const PLUGIN_PREFIX = 'plugins::';
|
||||
const ADMIN_PREFIX = 'admin::';
|
||||
const APPLICATION_PREFIX = 'application::';
|
||||
|
||||
const getPolicyIn = (container, policy) => {
|
||||
return _.get(container, ['config', 'policies', _.toLower(policy)]);
|
||||
};
|
||||
|
||||
const policyExistsIn = (container, policy) => {
|
||||
return !_.isUndefined(getPolicyIn(container, policy));
|
||||
};
|
||||
|
||||
const isGlobal = policy => _.startsWith(policy, GLOBAL_PREFIX);
|
||||
|
||||
const getGlobalPolicy = policy => {
|
||||
const strippedPolicy = policy.replace(GLOBAL_PREFIX, '');
|
||||
return getPolicyIn(strapi, strippedPolicy);
|
||||
};
|
||||
|
||||
const globalPolicyExists = policy => {
|
||||
return isGlobal(policy) && !_.isUndefined(getGlobalPolicy(policy));
|
||||
};
|
||||
|
||||
const getPluginPolicy = policy => {
|
||||
const strippedPolicy = policy.replace(PLUGIN_PREFIX, '');
|
||||
const [plugin = '', policyName = ''] = strippedPolicy.split('.');
|
||||
return getPolicyIn(_.get(strapi, ['plugins', plugin]), policyName);
|
||||
};
|
||||
|
||||
const pluginPolicyExists = policy =>
|
||||
isPluginPolicy(policy) && !_.isUndefined(getPluginPolicy(policy));
|
||||
|
||||
const isPluginPolicy = policy => _.startsWith(policy, PLUGIN_PREFIX);
|
||||
|
||||
const getAdminPolicy = policy => {
|
||||
const strippedPolicy = policy.replace(ADMIN_PREFIX, '');
|
||||
return getPolicyIn(_.get(strapi, 'admin'), strippedPolicy);
|
||||
};
|
||||
|
||||
const isAdminPolicy = policy => _.startsWith(policy, ADMIN_PREFIX);
|
||||
|
||||
const adminPolicyExists = policy => isAdminPolicy(policy) && !_.isUndefined(getAdminPolicy(policy));
|
||||
|
||||
const getAPIPolicy = policy => {
|
||||
const [, policyWithoutPrefix] = policy.split('::');
|
||||
const [api = '', policyName = ''] = policyWithoutPrefix.split('.');
|
||||
return getPolicyIn(_.get(strapi, ['api', api]), policyName);
|
||||
};
|
||||
|
||||
const APIPolicyExists = policy => {
|
||||
return isAPIPolicy(policy) && !_.isUndefined(getAPIPolicy(policy));
|
||||
};
|
||||
|
||||
const isAPIPolicy = policy => _.startsWith(policy, APPLICATION_PREFIX);
|
||||
|
||||
module.exports = {
|
||||
get,
|
||||
globalPolicy,
|
||||
|
Loading…
x
Reference in New Issue
Block a user