mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +00:00
Merge branch 'releases/v4' of https://github.com/strapi/strapi into fix-filter-popover-date
This commit is contained in:
commit
5ec0e78a5d
@ -1,3 +1,3 @@
|
||||
module.exports = ctx => {
|
||||
module.exports = (policyCtx, config, { strapi }) => {
|
||||
return true;
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ module.exports = {
|
||||
handler: 'address.find',
|
||||
config: {
|
||||
middlewares: ['api::address.address-middleware'],
|
||||
policies: ['address'],
|
||||
policies: ['global::test-policy', 'api::address.address'],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
module.exports = (config, { strapi }) => {
|
||||
// Add your own logic here.
|
||||
return async (ctx, next) => {
|
||||
strapi.log.info('In test-middleware middleware.');
|
||||
strapi.log.info('In application test-middleware middleware.');
|
||||
|
||||
await next();
|
||||
};
|
||||
|
@ -1,3 +1,18 @@
|
||||
module.exports = ctx => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* `test-policy` policy.
|
||||
*/
|
||||
|
||||
module.exports = (policyCtx, config, { strapi }) => {
|
||||
// Add your own logic here.
|
||||
strapi.log.info('In test-policy policy.');
|
||||
|
||||
const canDoSomething = true;
|
||||
|
||||
if (canDoSomething) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
@ -1,9 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const {
|
||||
policy: { createPolicyFactory },
|
||||
} = require('@strapi/utils');
|
||||
const { createPolicy } = require('@strapi/utils').policy;
|
||||
const { validateHasPermissionsInput } = require('../validation/policies/hasPermissions');
|
||||
|
||||
const inputModifiers = [
|
||||
@ -22,15 +20,16 @@ const inputModifiers = [
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = createPolicyFactory(
|
||||
config => {
|
||||
module.exports = createPolicy({
|
||||
name: 'admin::hasPermissions',
|
||||
validator: validateHasPermissionsInput,
|
||||
handler(ctx, config) {
|
||||
const { actions } = config;
|
||||
|
||||
const permissions = actions.map(action =>
|
||||
inputModifiers.find(modifier => modifier.check(action)).transform(action)
|
||||
);
|
||||
|
||||
return ctx => {
|
||||
const { userAbility: ability, isAuthenticated } = ctx.state;
|
||||
|
||||
if (!isAuthenticated || !ability) {
|
||||
@ -40,10 +39,5 @@ module.exports = createPolicyFactory(
|
||||
const isAuthorized = permissions.every(({ action, subject }) => ability.can(action, subject));
|
||||
|
||||
return isAuthorized;
|
||||
};
|
||||
},
|
||||
{
|
||||
validator: validateHasPermissionsInput,
|
||||
name: 'admin::hasPermissions',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = ctx => {
|
||||
return Boolean(ctx.state.isAuthenticated);
|
||||
module.exports = policyCtx => {
|
||||
return Boolean(policyCtx.state.isAuthenticated);
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ describe('hasDraftAndPublish policy', () => {
|
||||
|
||||
test('It should succeed when the model has draft & publish enabled', () => {
|
||||
const ctx = { params: { model: 'foo' } };
|
||||
const res = hasDraftAndPublish(ctx, { strapi: global.strapi });
|
||||
const res = hasDraftAndPublish(ctx, {}, { strapi: global.strapi });
|
||||
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
@ -37,21 +37,21 @@ describe('hasDraftAndPublish policy', () => {
|
||||
test(`It should fail when the model has draft & publish disabled`, () => {
|
||||
const ctx = { params: { model: 'bar' } };
|
||||
|
||||
const res = hasDraftAndPublish(ctx, { strapi: global.strapi });
|
||||
const res = hasDraftAndPublish(ctx, {}, { strapi: global.strapi });
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
test(`It should fail when the model doesn't exists`, () => {
|
||||
const ctx = { params: { model: 'foobar' } };
|
||||
|
||||
const res = hasDraftAndPublish(ctx, { strapi: global.strapi });
|
||||
const res = hasDraftAndPublish(ctx, {}, { strapi: global.strapi });
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
test(`It should fail when params.model isn't provided`, () => {
|
||||
const ctx = { params: {} };
|
||||
|
||||
const res = hasDraftAndPublish(ctx, { strapi: global.strapi });
|
||||
const res = hasDraftAndPublish(ctx, {}, { strapi: global.strapi });
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -4,7 +4,7 @@ const {
|
||||
contentTypes: { hasDraftAndPublish },
|
||||
} = require('@strapi/utils');
|
||||
|
||||
module.exports = (ctx, { strapi }) => {
|
||||
module.exports = (ctx, config, { strapi }) => {
|
||||
const { model: modelUID } = ctx.params;
|
||||
|
||||
const model = strapi.contentTypes[modelUID];
|
||||
|
@ -1,12 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
policy: { createPolicyFactory },
|
||||
policy: { createPolicy },
|
||||
} = require('@strapi/utils');
|
||||
const { validateHasPermissionsInput } = require('../validation/policies/hasPermissions');
|
||||
|
||||
module.exports = createPolicyFactory(
|
||||
({ actions = [], hasAtLeastOne = false } = {}) => ctx => {
|
||||
module.exports = createPolicy({
|
||||
name: 'plugin::content-manager.hasPermissions',
|
||||
validator: validateHasPermissionsInput,
|
||||
handler(ctx, config = {}) {
|
||||
const { actions = [], hasAtLeastOne = false } = config;
|
||||
|
||||
const {
|
||||
state: { userAbility, isAuthenticatedAdmin },
|
||||
params: { model },
|
||||
@ -22,8 +26,4 @@ module.exports = createPolicyFactory(
|
||||
|
||||
return isAuthorized;
|
||||
},
|
||||
{
|
||||
validator: validateHasPermissionsInput,
|
||||
name: 'plugin::content-manager.hasPermissions',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -82,7 +82,8 @@ module.exports = strapi => {
|
||||
|
||||
router[method](path, routeHandler);
|
||||
} catch (error) {
|
||||
throw new Error(`Error creating endpoint ${route.method} ${route.path}: ${error.message}`);
|
||||
error.message = `Error creating endpoint ${route.method} ${route.path}: ${error.message}`;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -1,24 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const { propOr } = require('lodash/fp');
|
||||
const policy = require('@strapi/utils/lib/policy');
|
||||
const { ForbiddenError } = require('@strapi/utils').errors;
|
||||
const { policy: policyUtils } = require('@strapi/utils');
|
||||
|
||||
const getPoliciesConfig = propOr([], 'config.policies');
|
||||
|
||||
const resolvePolicies = route => {
|
||||
const { pluginName, apiName } = route.info || {};
|
||||
const policiesConfig = getPoliciesConfig(route);
|
||||
|
||||
const resolvedPolicies = policiesConfig.map(policyConfig =>
|
||||
policy.get(policyConfig, { pluginName, apiName })
|
||||
);
|
||||
const resolvedPolicies = policyUtils.resolve(policiesConfig, route.info);
|
||||
|
||||
const policiesMiddleware = async (ctx, next) => {
|
||||
const context = policy.createPolicyContext('koa', ctx);
|
||||
const context = policyUtils.createPolicyContext('koa', ctx);
|
||||
|
||||
for (const resolvedPolicy of resolvedPolicies) {
|
||||
const result = await resolvedPolicy(context, { strapi });
|
||||
for (const { handler, config } of resolvedPolicies) {
|
||||
const result = await handler(context, config, { strapi });
|
||||
|
||||
if (![true, undefined].includes(result)) {
|
||||
throw new ForbiddenError('Policies failed.');
|
||||
|
@ -9,36 +9,22 @@ const { eq } = require('lodash/fp');
|
||||
const PLUGIN_PREFIX = 'plugin::';
|
||||
const API_PREFIX = 'api::';
|
||||
|
||||
const createPolicy = (policyName, config) => ({ policyName, config });
|
||||
|
||||
const resolveHandler = policy => {
|
||||
return _.has('handler', policy) ? policy.handler : policy;
|
||||
};
|
||||
|
||||
const parsePolicy = policy => {
|
||||
if (typeof policy === 'string') {
|
||||
return createPolicy(policy);
|
||||
return { policyName: policy, config: {} };
|
||||
}
|
||||
|
||||
const { name, config = {} } = policy;
|
||||
return createPolicy(name, config);
|
||||
};
|
||||
|
||||
const resolvePolicy = policyName => {
|
||||
const policy = strapi.policy(policyName);
|
||||
|
||||
return resolveHandler(policy);
|
||||
const { name, config } = policy;
|
||||
return { policyName: name, config };
|
||||
};
|
||||
|
||||
const searchLocalPolicy = (policyName, { pluginName, apiName }) => {
|
||||
if (pluginName) {
|
||||
const policy = strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
|
||||
return resolveHandler(policy);
|
||||
return strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
|
||||
}
|
||||
|
||||
if (apiName) {
|
||||
const policy = strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
|
||||
return resolveHandler(policy);
|
||||
return strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
|
||||
}
|
||||
};
|
||||
|
||||
@ -56,45 +42,68 @@ const globalPolicy = ({ method, endpoint, controller, action, plugin }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const get = (policy, { pluginName, apiName } = {}) => {
|
||||
if (typeof policy === 'function') {
|
||||
return policy;
|
||||
}
|
||||
const resolvePolicies = (config, { pluginName, apiName } = {}) => {
|
||||
return config.map(policyConfig => {
|
||||
return {
|
||||
handler: getPolicy(policyConfig, { pluginName, apiName }),
|
||||
config: policyConfig.config || {},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const { policyName, config } = parsePolicy(policy);
|
||||
|
||||
const resolvedPolicy = resolvePolicy(policyName);
|
||||
const findPolicy = (name, { pluginName, apiName } = {}) => {
|
||||
const resolvedPolicy = strapi.policy(name);
|
||||
|
||||
if (resolvedPolicy !== undefined) {
|
||||
return _.isPlainObject(policy) ? resolvedPolicy(config) : resolvedPolicy;
|
||||
return resolvedPolicy;
|
||||
}
|
||||
|
||||
const localPolicy = searchLocalPolicy(policy, { pluginName, apiName });
|
||||
const localPolicy = searchLocalPolicy(name, { pluginName, apiName });
|
||||
|
||||
if (localPolicy !== undefined) {
|
||||
return localPolicy;
|
||||
}
|
||||
|
||||
throw new Error(`Could not find policy "${policy}"`);
|
||||
throw new Error(`Could not find policy "${name}"`);
|
||||
};
|
||||
|
||||
const createPolicyFactory = (factoryCallback, options) => {
|
||||
const { validator, name = 'unnamed' } = options;
|
||||
const getPolicy = (policyConfig, { pluginName, apiName } = {}) => {
|
||||
if (typeof policyConfig === 'function') {
|
||||
return policyConfig;
|
||||
}
|
||||
|
||||
const validate = (...args) => {
|
||||
const { policyName, config } = parsePolicy(policyConfig);
|
||||
|
||||
const policy = findPolicy(policyName, { pluginName, apiName });
|
||||
|
||||
if (typeof policy === 'function') {
|
||||
return policy;
|
||||
}
|
||||
|
||||
if (policy.validator) {
|
||||
policy.validator(config);
|
||||
}
|
||||
|
||||
return policy.handler;
|
||||
};
|
||||
|
||||
const createPolicy = options => {
|
||||
const { name = 'unnamed', validator, handler } = options;
|
||||
|
||||
const wrappedValidator = config => {
|
||||
if (validator) {
|
||||
try {
|
||||
validator(...args);
|
||||
validator(config);
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid objects submitted to "${name}" policy.`);
|
||||
throw new Error(`Invalid config passed to "${name}" policy.`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return config => {
|
||||
if (validator) {
|
||||
validate(config);
|
||||
}
|
||||
|
||||
return factoryCallback(config);
|
||||
return {
|
||||
name,
|
||||
validator: wrappedValidator,
|
||||
handler,
|
||||
};
|
||||
};
|
||||
|
||||
@ -102,7 +111,6 @@ const createPolicyContext = (type, ctx) => {
|
||||
return Object.assign(
|
||||
{
|
||||
is: eq(type),
|
||||
|
||||
get type() {
|
||||
return type;
|
||||
},
|
||||
@ -112,8 +120,9 @@ const createPolicyContext = (type, ctx) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
get,
|
||||
get: getPolicy,
|
||||
resolve: resolvePolicies,
|
||||
globalPolicy,
|
||||
createPolicyFactory,
|
||||
createPolicy,
|
||||
createPolicyContext,
|
||||
};
|
||||
|
@ -4,9 +4,10 @@
|
||||
* `{{id}}` policy.
|
||||
*/
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
module.exports = (config, { strapi }) => {
|
||||
return policyCtx => {
|
||||
// Add your own logic here.
|
||||
console.log('In {{id}} policy.');
|
||||
strapi.log.info('In {{id}} policy.');
|
||||
|
||||
const canDoSomething = true;
|
||||
|
||||
@ -15,4 +16,5 @@ module.exports = async (ctx) => {
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
@ -1,25 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const { getOr } = require('lodash/fp');
|
||||
const { propOr } = require('lodash/fp');
|
||||
const { policy: policyUtils } = require('@strapi/utils');
|
||||
const { ForbiddenError } = require('@strapi/utils').errors;
|
||||
|
||||
const getPoliciesConfig = propOr([], 'policies');
|
||||
|
||||
const createPoliciesMiddleware = (resolverConfig, { strapi }) => {
|
||||
const resolverPolicies = getPoliciesConfig(resolverConfig);
|
||||
const policies = policyUtils.resolve(resolverPolicies);
|
||||
|
||||
return async (resolve, ...rest) => {
|
||||
const resolverPolicies = getOr([], 'policies', resolverConfig);
|
||||
|
||||
// Transform every policy into a unique format
|
||||
const policies = resolverPolicies.map(policy => policyUtils.get(policy));
|
||||
|
||||
// Create a graphql policy context
|
||||
const context = createGraphQLPolicyContext(...rest);
|
||||
|
||||
// Run policies & throw an error if one of them fails
|
||||
for (const policy of policies) {
|
||||
const result = await policy(context, { strapi });
|
||||
for (const { handler, config } of policies) {
|
||||
const result = await handler(context, config, { strapi });
|
||||
|
||||
if (![true, undefined].includes(result)) {
|
||||
throw new ForbiddenError();
|
||||
throw new ForbiddenError('Policies failed.');
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user