188 lines
4.5 KiB
JavaScript
Raw Normal View History

/**
* Policies util
*/
'use strict';
const _ = require('lodash');
const GLOBAL_PREFIX = 'global::';
2021-08-06 18:09:49 +02:00
const PLUGIN_PREFIX = 'plugin::';
const ADMIN_PREFIX = 'admin::';
2021-08-06 18:09:49 +02:00
const APPLICATION_PREFIX = 'api::';
2021-08-02 17:54:49 +02:00
const getPolicyIn = (container, policy) => {
return (
_.get(container, ['config', 'policies', policy]) ||
_.get(container, ['config', 'policies', _.toLower(policy)])
);
};
const policyExistsIn = (container, policy) => !_.isUndefined(getPolicyIn(container, policy));
const createPolicy = (policyName, args) => ({ policyName, args });
const resolveHandler = policy => (_.isFunction(policy) ? policy : policy.handler);
const parsePolicy = policy => {
if (typeof policy === 'string') {
return createPolicy(policy);
}
const { name, options = {} } = policy;
return createPolicy(name, options);
};
const resolvePolicy = policyName => {
const resolver = policyResolvers.find(resolver => resolver.exists(policyName));
return resolver ? resolveHandler(resolver.get)(policyName) : undefined;
};
2021-08-26 18:44:11 +02:00
const searchLocalPolicy = (policy, { pluginName, apiName }) => {
let [absoluteApiName, policyName] = policy.split('.');
let absoluteApi = _.get(strapi.api, absoluteApiName);
const resolver = policyResolvers.find(({ name }) => name === 'plugin');
if (policyExistsIn(absoluteApi, policyName)) {
return resolveHandler(getPolicyIn(absoluteApi, policyName));
}
2021-08-26 18:44:11 +02:00
const pluginPolicy = `${PLUGIN_PREFIX}${pluginName}.${policy}`;
2021-08-26 18:44:11 +02:00
if (pluginName && resolver.exists(pluginPolicy)) {
return resolveHandler(resolver.get(pluginPolicy));
}
const api = _.get(strapi.api, apiName);
if (api && policyExistsIn(api, policy)) {
return resolveHandler(getPolicyIn(api, policy));
}
return undefined;
};
const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
return async (ctx, next) => {
ctx.request.route = {
endpoint: `${method} ${endpoint}`,
controller: _.toLower(controller),
action: _.toLower(action),
verb: _.toLower(method),
plugin,
};
await next();
};
};
2021-08-24 17:56:49 +02:00
const bodyPolicy = async (ctx, next) => {
const values = await next();
if (_.isNil(ctx.body) && !_.isNil(values)) {
ctx.body = values;
}
};
const policyResolvers = [
{
name: 'api',
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('.');
2021-08-24 17:56:49 +02:00
// TODO: load policies into the registry & user strapi.policy(policy)
return getPolicyIn(_.get(strapi, ['api', api]), policyName);
},
},
{
name: 'admin',
is(policy) {
return _.startsWith(policy, ADMIN_PREFIX);
},
exists(policy) {
return this.is(policy) && !_.isUndefined(this.get(policy));
},
get(policy) {
2021-08-25 15:16:17 +02:00
return strapi.policy(policy);
},
},
{
name: 'plugin',
is(policy) {
return _.startsWith(policy, PLUGIN_PREFIX);
},
exists(policy) {
return this.is(policy) && !_.isUndefined(this.get(policy));
},
get(policy) {
2021-08-24 17:56:49 +02:00
return strapi.policy(policy);
},
},
{
name: 'global',
is(policy) {
return _.startsWith(policy, GLOBAL_PREFIX);
},
exists(policy) {
return this.is(policy) && !_.isUndefined(this.get(policy));
},
get(policy) {
2021-08-24 17:56:49 +02:00
return strapi.policy(policy);
},
},
];
2021-08-26 18:44:11 +02:00
const get = (policy, { pluginName, apiName }) => {
if (typeof policy === 'function') {
return policy;
}
const { policyName, args } = parsePolicy(policy);
const resolvedPolicy = resolvePolicy(policyName);
if (resolvedPolicy !== undefined) {
return _.isPlainObject(policy) ? resolvedPolicy(args) : resolvedPolicy;
}
2021-08-26 18:44:11 +02:00
const localPolicy = searchLocalPolicy(policy, { pluginName, apiName });
if (localPolicy !== undefined) {
return localPolicy;
}
throw new Error(`Could not find policy "${policy}"`);
};
const createPolicyFactory = (factoryCallback, options) => {
const { validator, name = 'unnamed' } = options;
const validate = (...args) => {
try {
validator(...args);
} catch (e) {
throw new Error(`Invalid objects submitted to "${name}" policy.`);
}
};
return options => {
if (validator) {
validate(options);
}
return factoryCallback(options);
};
};
module.exports = {
get,
globalPolicy,
2021-08-24 17:56:49 +02:00
bodyPolicy,
createPolicyFactory,
};