162 lines
3.4 KiB
TypeScript
Raw Normal View History

/**
* Policies util
*/
2022-08-08 15:50:34 +02:00
2023-04-27 23:18:48 +02:00
import _ from 'lodash';
import { eq } from 'lodash/fp';
import type { Context } from './types';
2021-08-06 18:09:49 +02:00
const PLUGIN_PREFIX = 'plugin::';
2021-08-28 14:16:39 +02:00
const API_PREFIX = 'api::';
2023-04-27 23:18:48 +02:00
interface PolicyInfo {
name: string;
config: unknown;
}
type PolicyConfig = string | PolicyInfo | (() => PolicyInfo);
interface PolicyContext {
pluginName?: string;
apiName?: string;
}
interface RouteInfo {
method: string;
endpoint: string;
controller: string;
action: string;
plugin: string;
}
const parsePolicy = (policy: string | PolicyInfo) => {
if (typeof policy === 'string') {
return { policyName: policy, config: {} };
}
const { name, config } = policy;
return { policyName: name, config };
};
2023-04-27 23:18:48 +02:00
const searchLocalPolicy = (policyName: string, policyContext: PolicyContext) => {
const { pluginName, apiName } = policyContext ?? {};
2021-08-28 14:16:39 +02:00
if (pluginName) {
return strapi.policy(`${PLUGIN_PREFIX}${pluginName}.${policyName}`);
}
2021-08-28 14:16:39 +02:00
if (apiName) {
return strapi.policy(`${API_PREFIX}${apiName}.${policyName}`);
}
};
2023-04-27 23:18:48 +02:00
const globalPolicy = ({ method, endpoint, controller, action, plugin }: RouteInfo) => {
return async (ctx: Context, next: () => void) => {
ctx.request.route = {
endpoint: `${method} ${endpoint}`,
controller: _.toLower(controller),
action: _.toLower(action),
verb: _.toLower(method),
plugin,
};
await next();
};
};
2023-04-27 23:18:48 +02:00
const resolvePolicies = (config: PolicyInfo[], policyContext: PolicyContext) => {
const { pluginName, apiName } = policyContext ?? {};
2022-08-08 23:33:39 +02:00
return config.map((policyConfig) => {
return {
handler: getPolicy(policyConfig, { pluginName, apiName }),
config: policyConfig.config || {},
};
});
};
2023-04-27 23:18:48 +02:00
const findPolicy = (name: string, policyContext: PolicyContext) => {
const { pluginName, apiName } = policyContext ?? {};
const resolvedPolicy = strapi.policy(name);
if (resolvedPolicy !== undefined) {
return resolvedPolicy;
}
const localPolicy = searchLocalPolicy(name, { pluginName, apiName });
if (localPolicy !== undefined) {
return localPolicy;
}
throw new Error(`Could not find policy "${name}"`);
};
2023-06-06 10:58:36 +02:00
const getPolicy = (policyConfig: PolicyConfig, policyContext?: PolicyContext) => {
2023-04-27 23:18:48 +02:00
const { pluginName, apiName } = policyContext ?? {};
if (typeof policyConfig === 'function') {
return policyConfig;
}
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;
};
2023-04-27 23:18:48 +02:00
interface Options {
name: string;
validator?(config: unknown): void;
handler(...args: any[]): any;
}
const createPolicy = (options: Options) => {
const { name = 'unnamed', validator, handler } = options;
2023-04-27 23:18:48 +02:00
const wrappedValidator = (config: unknown) => {
if (validator) {
try {
validator(config);
} catch (e) {
throw new Error(`Invalid config passed to "${name}" policy.`);
}
}
};
return {
name,
validator: wrappedValidator,
handler,
};
};
2023-04-27 23:18:48 +02:00
const createPolicyContext = (type: string, ctx: object) => {
2021-09-24 09:35:25 +02:00
return Object.assign(
{
is: eq(type),
get type() {
return type;
},
},
ctx
);
};
2023-04-27 23:18:48 +02:00
export {
getPolicy as get,
resolvePolicies as resolve,
globalPolicy,
createPolicy,
2021-09-24 09:35:25 +02:00
createPolicyContext,
};