Harmonize and make policies and middlwares more consistent

This commit is contained in:
Alexandre Bodin 2021-10-04 18:16:28 +02:00
parent 8160b84881
commit c1aa57f436
42 changed files with 256 additions and 224 deletions

View File

@ -8,7 +8,8 @@ module.exports = [
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::request',
'strapi::query',
'strapi::body',
// 'strapi::compression',
// 'strapi::ip',
{

View File

@ -27,7 +27,7 @@ module.exports = {
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::provider-login.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::provider-login.read'] } },
],
},
},
@ -38,7 +38,7 @@ module.exports = {
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::provider-login.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::provider-login.update'] } },
],
},
},

View File

@ -22,7 +22,7 @@ module.exports = [
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['admin::roles.create'],
},
},
@ -38,7 +38,7 @@ module.exports = [
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['admin::roles.delete'],
},
},
@ -54,7 +54,7 @@ module.exports = [
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['admin::roles.delete'],
},
},

View File

@ -23,14 +23,14 @@ const inputModifiers = [
];
module.exports = createPolicyFactory(
options => {
const { actions } = options;
config => {
const { actions } = config;
const permissions = actions.map(action =>
inputModifiers.find(modifier => modifier.check(action)).transform(action)
);
return ({ ctx, strapi }) => {
return (ctx, { strapi }) => {
const { userAbility: ability, isAuthenticated } = ctx.state;
if (!isAuthenticated || !ability) {

View File

@ -1,5 +1,5 @@
'use strict';
module.exports = ({ ctx }) => {
module.exports = ctx => {
return Boolean(ctx.state.isAuthenticated);
};

View File

@ -28,7 +28,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::marketplace.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::marketplace.read'] } },
],
},
},
@ -41,7 +41,7 @@ module.exports = [
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: { actions: ['admin::marketplace.plugins.install'] },
config: { actions: ['admin::marketplace.plugins.install'] },
},
],
},
@ -55,7 +55,7 @@ module.exports = [
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: { actions: ['admin::marketplace.plugins.uninstall'] },
config: { actions: ['admin::marketplace.plugins.uninstall'] },
},
],
},

View File

@ -8,7 +8,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.create'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.create'] } },
],
},
},
@ -19,7 +19,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.read'] } },
],
},
},
@ -30,7 +30,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.delete'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.delete'] } },
],
},
},
@ -41,7 +41,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.read'] } },
],
},
},
@ -52,7 +52,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::api-tokens.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.update'] } },
],
},
},

View File

@ -6,7 +6,7 @@ module.exports = [
path: '/users/batch-delete',
handler: 'user.deleteMany',
config: {
policies: [{ name: 'admin::hasPermissions', options: { actions: ['admin::users.delete'] } }],
policies: [{ name: 'admin::hasPermissions', config: { actions: ['admin::users.delete'] } }],
},
},
{
@ -16,7 +16,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::roles.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::roles.read'] } },
],
},
},
@ -27,7 +27,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::roles.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::roles.update'] } },
],
},
},
@ -38,7 +38,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::roles.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::roles.read'] } },
],
},
},
@ -49,7 +49,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::roles.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::roles.read'] } },
],
},
},
@ -60,7 +60,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::roles.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::roles.update'] } },
],
},
},

View File

@ -32,7 +32,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::users.create'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::users.create'] } },
],
},
},
@ -43,7 +43,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::users.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::users.read'] } },
],
},
},
@ -54,7 +54,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::users.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::users.read'] } },
],
},
},
@ -65,7 +65,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::users.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::users.update'] } },
],
},
},
@ -74,7 +74,7 @@ module.exports = [
path: '/users/:id',
handler: 'user.deleteOne',
config: {
policies: [{ name: 'admin::hasPermissions', options: { actions: ['admin::users.delete'] } }],
policies: [{ name: 'admin::hasPermissions', config: { actions: ['admin::users.delete'] } }],
},
},
{
@ -82,7 +82,7 @@ module.exports = [
path: '/users/batch-delete',
handler: 'user.deleteMany',
config: {
policies: [{ name: 'admin::hasPermissions', options: { actions: ['admin::users.delete'] } }],
policies: [{ name: 'admin::hasPermissions', config: { actions: ['admin::users.delete'] } }],
},
},
];

View File

@ -8,7 +8,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.read'] } },
],
},
},
@ -19,7 +19,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.create'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.create'] } },
],
},
},
@ -30,7 +30,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.read'] } },
],
},
},
@ -41,7 +41,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.update'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.update'] } },
],
},
},
@ -52,7 +52,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.delete'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.delete'] } },
],
},
},
@ -63,7 +63,7 @@ module.exports = [
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['admin::webhooks.delete'] } },
{ name: 'admin::hasPermissions', config: { actions: ['admin::webhooks.delete'] } },
],
},
},

View File

@ -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' } };
expect(() => hasDraftAndPublish({ ctx, strapi: global.strapi })).toThrowError('forbidden');
expect(() => hasDraftAndPublish(ctx, { strapi: global.strapi })).toThrowError('forbidden');
expect(strapi.errors.forbidden).toHaveBeenCalled();
});
test(`It should fail when the model doesn't exists`, () => {
const ctx = { params: { model: 'foobar' } };
expect(() => hasDraftAndPublish({ ctx, strapi: global.strapi })).toThrowError('forbidden');
expect(() => hasDraftAndPublish(ctx, { strapi: global.strapi })).toThrowError('forbidden');
expect(strapi.errors.forbidden).toHaveBeenCalled();
});
test(`It should fail when params.model isn't provided`, () => {
const ctx = { params: {} };
expect(() => hasDraftAndPublish({ ctx, strapi: global.strapi })).toThrowError('forbidden');
expect(() => hasDraftAndPublish(ctx, { strapi: global.strapi })).toThrowError('forbidden');
expect(strapi.errors.forbidden).toHaveBeenCalled();
});
});

View File

@ -4,12 +4,10 @@ const {
contentTypes: { hasDraftAndPublish },
} = require('@strapi/utils');
module.exports = ({ ctx, strapi }) => {
const {
params: { model: modelUid },
} = ctx;
module.exports = (ctx, { strapi }) => {
const { model: modelUID } = ctx.params;
const model = strapi.contentTypes[modelUid];
const model = strapi.contentTypes[modelUID];
if (!hasDraftAndPublish(model)) {
throw strapi.errors.forbidden();

View File

@ -6,7 +6,7 @@ const {
const { validateHasPermissionsInput } = require('../validation/policies/hasPermissions');
module.exports = createPolicyFactory(
({ actions = [], hasAtLeastOne = false } = {}) => ({ ctx, strapi }) => {
({ actions = [], hasAtLeastOne = false } = {}) => (ctx, { strapi }) => {
const {
state: { userAbility, isAuthenticatedAdmin },
params: { model },

View File

@ -88,7 +88,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: {
config: {
actions: [
'plugin::content-manager.explorer.create',
'plugin::content-manager.explorer.update',
@ -109,7 +109,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.read'] },
config: { actions: ['plugin::content-manager.explorer.read'] },
},
],
},
@ -124,7 +124,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: {
config: {
actions: [
'plugin::content-manager.explorer.create',
'plugin::content-manager.explorer.update',
@ -145,7 +145,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.delete'] },
config: { actions: ['plugin::content-manager.explorer.delete'] },
},
],
},
@ -161,7 +161,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.publish'] },
config: { actions: ['plugin::content-manager.explorer.publish'] },
},
],
},
@ -177,7 +177,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.publish'] },
config: { actions: ['plugin::content-manager.explorer.publish'] },
},
],
},
@ -192,7 +192,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.read'] },
config: { actions: ['plugin::content-manager.explorer.read'] },
},
],
},
@ -207,7 +207,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.read'] },
config: { actions: ['plugin::content-manager.explorer.read'] },
},
],
},
@ -222,7 +222,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.create'] },
config: { actions: ['plugin::content-manager.explorer.create'] },
},
],
},
@ -237,7 +237,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.read'] },
config: { actions: ['plugin::content-manager.explorer.read'] },
},
],
},
@ -252,7 +252,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.update'] },
config: { actions: ['plugin::content-manager.explorer.update'] },
},
],
},
@ -267,7 +267,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.delete'] },
config: { actions: ['plugin::content-manager.explorer.delete'] },
},
],
},
@ -283,7 +283,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.publish'] },
config: { actions: ['plugin::content-manager.explorer.publish'] },
},
],
},
@ -299,7 +299,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.publish'] },
config: { actions: ['plugin::content-manager.explorer.publish'] },
},
],
},
@ -314,7 +314,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::content-manager.explorer.delete'] },
config: { actions: ['plugin::content-manager.explorer.delete'] },
},
],
},

View File

@ -11,7 +11,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -24,7 +24,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -37,7 +37,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -50,7 +50,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -63,7 +63,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -76,7 +76,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -89,7 +89,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -102,7 +102,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -115,7 +115,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -128,7 +128,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -141,7 +141,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -154,7 +154,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},
@ -167,7 +167,7 @@ module.exports = {
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::content-type-builder.read'] },
config: { actions: ['plugin::content-type-builder.read'] },
},
],
},

View File

@ -18,7 +18,7 @@ module.exports = {
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['plugin::email.settings.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::email.settings.read'] } },
],
},
},
@ -29,7 +29,7 @@ module.exports = {
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', options: { actions: ['plugin::email.settings.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::email.settings.read'] } },
],
},
},

View File

@ -0,0 +1,40 @@
'use strict';
const { defaultsDeep } = require('lodash/fp');
const body = require('koa-body');
const defaults = {
multipart: true,
patchKoa: true,
};
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (config, { strapi }) => {
const bodyConfig = defaultsDeep(defaults, config);
return async (ctx, next) => {
// TODO: find a better way later
if (ctx.url === '/graphql') {
return next();
}
try {
return body({ patchKoa: true, ...bodyConfig })(ctx, next);
} catch (e) {
if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
throw strapi.errors.entityTooLarge('FileTooBig', {
errors: [
{
id: 'parser.file.status.sizeLimit',
message: `file is bigger than the limit size!`,
},
],
});
}
throw e;
}
};
};

View File

@ -5,4 +5,4 @@ const compress = require('koa-compress');
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = options => compress(options);
module.exports = config => compress(config);

View File

@ -1,5 +1,6 @@
'use strict';
const { defaultsDeep } = require('lodash/fp');
const cors = require('@koa/cors');
const defaults = {
@ -14,7 +15,7 @@ const defaults = {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = options => {
module.exports = config => {
const {
origin,
expose,
@ -23,7 +24,7 @@ module.exports = options => {
methods,
headers,
keepHeadersOnError,
} = Object.assign({}, defaults, options);
} = defaultsDeep(defaults, config);
return cors({
async origin(ctx) {

View File

@ -1,6 +1,6 @@
'use strict';
const _ = require('lodash');
const { isNil } = require('lodash/fp');
const Boom = require('@hapi/boom');
const delegate = require('delegates');
@ -46,7 +46,7 @@ const formatBoomPayload = boomError => {
const { output } = boomError;
if (output.statusCode < 500 && !_.isNil(boomError.data)) {
if (output.statusCode < 500 && !isNil(boomError.data)) {
output.payload.data = boomError.data;
}
@ -87,7 +87,7 @@ const createResponseUtils = strapi => {
};
strapi.server.app.response.deleted = function(data) {
if (_.isNil(data)) {
if (isNil(data)) {
this.status = 204;
} else {
this.status = 200;
@ -104,7 +104,7 @@ const createResponseUtils = strapi => {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (options, { strapi }) => {
module.exports = (_, { strapi }) => {
createResponseUtils(strapi);
strapi.errors = Boom;
@ -113,7 +113,7 @@ module.exports = (options, { strapi }) => {
// App logic.
await next();
if (_.isNil(ctx.body) && (_.isNil(ctx.status) || ctx.status === 404)) {
if (isNil(ctx.body) && (isNil(ctx.status) || ctx.status === 404)) {
ctx.notFound();
}
} catch (error) {

View File

@ -1,7 +1,7 @@
'use strict';
const { resolve } = require('path');
const { defaultsDeep } = require('lodash');
const { defaultsDeep } = require('lodash/fp');
const favicon = require('koa-favicon');
const defaults = {
@ -12,8 +12,8 @@ const defaults = {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (options, { strapi }) => {
const { maxAge, path: faviconPath } = defaultsDeep(defaults, options);
module.exports = (config, { strapi }) => {
const { maxAge, path: faviconPath } = defaultsDeep(defaults, config);
return favicon(resolve(strapi.dirs.root, faviconPath), { maxAge });
};

View File

@ -1,4 +1,4 @@
import { Strapi } from '../';
import { Middleware } from 'koa';
export type MiddlewareFactory = (options: any, ctx: { strapi: Strapi }) => Middleware;
export type MiddlewareFactory = (options: any, ctx: { strapi: Strapi }) => Middleware | null;

View File

@ -7,7 +7,8 @@ const favicon = require('./favicon');
const ip = require('./ip');
const logger = require('./logger');
const poweredBy = require('./powered-by');
const request = require('./request');
const body = require('./body');
const query = require('./query');
const responseTime = require('./response-time');
const responses = require('./responses');
const security = require('./security');
@ -25,7 +26,8 @@ module.exports = {
logger,
compression,
responses,
request,
body,
query,
favicon,
public: publicStatic,
};

View File

@ -5,4 +5,4 @@ const ip = require('koa-ip');
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = options => ip(options);
module.exports = config => ip(config);

View File

@ -16,7 +16,7 @@ const codeToColor = code => {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (options, { strapi }) => {
module.exports = (_, { strapi }) => {
return async (ctx, next) => {
const start = Date.now();
await next();

View File

@ -1,5 +1,7 @@
'use strict';
const { defaultsDeep } = require('lodash/fp');
const defaults = {
poweredBy: 'Strapi <strapi.io>',
};
@ -7,8 +9,8 @@ const defaults = {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = options => {
const { poweredBy } = Object.assign({}, defaults, options);
module.exports = config => {
const { poweredBy } = defaultsDeep(defaults, config);
return async (ctx, next) => {
await next();

View File

@ -18,8 +18,8 @@ const defaults = {
/**
* @type {import('../').MiddlewareFactory}
*/
module.exports = (options, { strapi }) => {
const { defaultIndex, maxAge, path: publicPath } = defaultsDeep(defaults, options);
module.exports = (config, { strapi }) => {
const { defaultIndex, maxAge, path: publicPath } = defaultsDeep(defaults, config);
const staticDir = path.resolve(strapi.dirs.root, publicPath || strapi.config.paths.static);
@ -122,5 +122,5 @@ module.exports = (options, { strapi }) => {
},
]);
return async (ctx, next) => next();
return null;
};

View File

@ -0,0 +1,46 @@
'use strict';
const { defaultsDeep } = require('lodash/fp');
const qs = require('qs');
const defaults = {
strictNullHandling: true,
arrayLimit: 100,
depth: 20,
};
/**
* Body parser hook
*/
const addQsParser = (app, settings) => {
Object.defineProperty(app.request, 'query', {
configurable: false,
enumerable: true,
/*
* Get parsed query-string.
*/
get() {
const qstr = this.querystring;
const cache = (this._querycache = this._querycache || {});
return cache[qstr] || (cache[qstr] = qs.parse(qstr, settings));
},
/*
* Set query-string as an object.
*/
set(obj) {
this.querystring = qs.stringify(obj);
},
});
return app;
};
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (config, { strapi }) => {
addQsParser(strapi.server.app, defaultsDeep(defaults, config));
return null;
};

View File

@ -1,74 +0,0 @@
'use strict';
const { defaultsDeep } = require('lodash/fp');
const body = require('koa-body');
const qs = require('qs');
const defaults = {
multipart: true,
queryStringParser: {
strictNullHandling: true,
arrayLimit: 100,
depth: 20,
},
};
/**
* Body parser hook
*/
const addQsParser = (app, settings) => {
Object.defineProperty(app.request, 'query', {
configurable: false,
enumerable: true,
/*
* Get parsed query-string.
*/
get() {
const qstr = this.querystring;
const cache = (this._querycache = this._querycache || {});
return cache[qstr] || (cache[qstr] = qs.parse(qstr, settings));
},
/*
* Set query-string as an object.
*/
set(obj) {
this.querystring = qs.stringify(obj);
},
});
return app;
};
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (options, { strapi }) => {
const { queryStringParser, ...bodyOptions } = defaultsDeep(defaults, options);
addQsParser(strapi.server.app, queryStringParser);
return async (ctx, next) => {
// TODO: find a better way later
if (ctx.url === '/graphql') {
return next();
}
try {
return body({ patchKoa: true, ...bodyOptions })(ctx, next);
} catch (e) {
if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
throw strapi.errors.entityTooLarge('FileTooBig', {
errors: [
{
id: 'parser.file.status.sizeLimit',
message: `file is bigger than the limit size!`,
},
],
});
}
throw e;
}
};
};

View File

@ -5,12 +5,12 @@ const { prop, isFunction } = require('lodash/fp');
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = (options = {}) => {
module.exports = (config = {}) => {
return async (ctx, next) => {
await next();
const status = ctx.status;
const handler = prop(`handlers.${status}`, options);
const handler = prop(`handlers.${status}`, config);
if (isFunction(handler)) {
await handler(ctx);

View File

@ -22,4 +22,4 @@ const defaults = {
/**
* @type {import('./').MiddlewareFactory}
*/
module.exports = options => helmet(defaultsDeep(defaults, options));
module.exports = config => helmet(defaultsDeep(defaults, config));

View File

@ -1,7 +1,7 @@
'use strict';
const path = require('path');
const { propOr, isArray } = require('lodash/fp');
const { propOr, isArray, isFunction } = require('lodash/fp');
const getMiddlewareConfig = propOr([], 'config.middlewares');
@ -14,7 +14,9 @@ const resolveRouteMiddlewares = (route, strapi) => {
const middlewares = resolveMiddlewares(middlewaresConfig, strapi);
return middlewares.map(({ handler }) => handler);
return middlewares
.filter(middleware => isFunction(middleware.handler))
.map(({ handler }) => handler);
};
/**

View File

@ -11,14 +11,18 @@ const resolvePolicies = route => {
const { pluginName, apiName } = route.info || {};
const policiesConfig = getPoliciesConfig(route);
const resolvedPolicies = policiesConfig.map(policyConfig =>
policy.get(policyConfig, { pluginName, apiName })
);
const policiesMiddleware = async (ctx, next) => {
const context = policy.createPolicyContext('koa', ctx);
for (const policyName of policiesConfig) {
const resolvedPolicy = await policy.get(policyName, { pluginName, apiName });
const result = await resolvedPolicy({ ctx: context, strapi });
for (const resolvedPolicy of resolvedPolicies) {
const result = await resolvedPolicy(context, { strapi });
if (![true, undefined].includes(result)) {
// TODO: make error clearer
throw new Error('Policies failed.');
}
}

View File

@ -1,6 +1,8 @@
'use strict';
const { isFunction } = require('lodash/fp');
const { yup } = require('@strapi/utils');
const { resolveMiddlewares } = require('./middleware');
/**
@ -15,7 +17,8 @@ const defaultConfig = [
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::request',
'strapi::query',
'strapi::body',
'strapi::favicon',
'strapi::public',
];
@ -24,7 +27,8 @@ const requiredMiddlewares = [
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::request',
'strapi::query',
'strapi::body',
'strapi::public',
'strapi::favicon',
];
@ -63,9 +67,13 @@ const registerApplicationMiddlewares = async strapi => {
checkRequiredMiddlewares(middlewares);
for (const middleware of middlewares) {
strapi.server.use(middleware.handler);
}
// NOTE: exclude middlewares that return nothing.
// this is used for middlewares that only extend the app only need to be added in certain conditions
middlewares
.filter(middleware => isFunction(middleware.handler))
.forEach(middleware => {
strapi.server.use(middleware.handler);
});
};
/**

View File

@ -12,7 +12,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.settings.read'],
},
},
@ -28,7 +28,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.settings.read'],
},
},
@ -52,7 +52,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.read'],
},
},
@ -68,7 +68,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.read'],
},
},
@ -84,7 +84,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.read'],
},
},
@ -100,7 +100,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::upload.assets.update'],
},
},

View File

@ -9,7 +9,7 @@ const { eq } = require('lodash/fp');
const PLUGIN_PREFIX = 'plugin::';
const API_PREFIX = 'api::';
const createPolicy = (policyName, args) => ({ policyName, args });
const createPolicy = (policyName, config) => ({ policyName, config });
const resolveHandler = policy => {
return _.has('handler', policy) ? policy.handler : policy;
@ -20,8 +20,8 @@ const parsePolicy = policy => {
return createPolicy(policy);
}
const { name, options = {} } = policy;
return createPolicy(name, options);
const { name, config = {} } = policy;
return createPolicy(name, config);
};
const resolvePolicy = policyName => {
@ -69,12 +69,12 @@ const get = (policy, { pluginName, apiName } = {}) => {
return policy;
}
const { policyName, args } = parsePolicy(policy);
const { policyName, config } = parsePolicy(policy);
const resolvedPolicy = resolvePolicy(policyName);
if (resolvedPolicy !== undefined) {
return _.isPlainObject(policy) ? resolvedPolicy(args) : resolvedPolicy;
return _.isPlainObject(policy) ? resolvedPolicy(config) : resolvedPolicy;
}
const localPolicy = searchLocalPolicy(policy, { pluginName, apiName });
@ -97,12 +97,12 @@ const createPolicyFactory = (factoryCallback, options) => {
}
};
return options => {
return config => {
if (validator) {
validate(options);
validate(config);
}
return factoryCallback(options);
return factoryCallback(config);
};
};

View File

@ -4,7 +4,8 @@ module.exports = [
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::request',
'strapi::query',
'strapi::body',
'strapi::favicon',
'strapi::public',
];

View File

@ -8,7 +8,7 @@ module.exports = [
config: {
policies: [
'plugin::documentation.index',
{ name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
],
},
},
@ -19,7 +19,7 @@ module.exports = [
config: {
policies: [
'plugin::documentation.index',
{ name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
],
},
},
@ -29,7 +29,7 @@ module.exports = [
handler: 'documentation.loginView',
config: {
policies: [
{ name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
],
},
},
@ -39,7 +39,7 @@ module.exports = [
handler: 'documentation.login',
config: {
policies: [
{ name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
],
},
},
@ -49,7 +49,7 @@ module.exports = [
handler: 'documentation.getInfos',
config: {
policies: [
{ name: 'admin::hasPermissions', options: { actions: ['plugin::documentation.read'] } },
{ name: 'admin::hasPermissions', config: { actions: ['plugin::documentation.read'] } },
],
},
},
@ -61,7 +61,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::documentation.settings.regenerate'] },
config: { actions: ['plugin::documentation.settings.regenerate'] },
},
],
},
@ -74,7 +74,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: { actions: ['plugin::documentation.settings.update'] },
config: { actions: ['plugin::documentation.settings.update'] },
},
],
},

View File

@ -15,10 +15,11 @@ const createPoliciesMiddleware = (resolverConfig, { strapi }) => {
// Run policies & throw an error if one of them fails
for (const policy of policies) {
const result = await policy({ context, strapi });
const result = await policy(context, { strapi });
if (!result) {
throw new Error('Policies failed');
if (![true, undefined].includes(result)) {
// TODO: make error clearer
throw new Error('Policies failed.');
}
}

View File

@ -12,7 +12,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::i18n.locale.read'] },
config: { actions: ['plugin::i18n.locale.read'] },
},
],
},
@ -34,7 +34,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::i18n.locale.create'] },
config: { actions: ['plugin::i18n.locale.create'] },
},
],
},
@ -48,7 +48,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::i18n.locale.update'] },
config: { actions: ['plugin::i18n.locale.update'] },
},
],
},
@ -62,7 +62,7 @@ module.exports = {
'admin::isAuthenticatedAdmin',
{
name: 'plugin::content-manager.hasPermissions',
options: { actions: ['plugin::i18n.locale.delete'] },
config: { actions: ['plugin::i18n.locale.delete'] },
},
],
},

View File

@ -9,7 +9,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.roles.read'],
},
},
@ -24,7 +24,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.roles.read'],
},
},
@ -39,7 +39,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.roles.create'],
},
},
@ -54,7 +54,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.roles.update'],
},
},
@ -69,7 +69,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.roles.delete'],
},
},

View File

@ -9,7 +9,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.email-templates.read'],
},
},
@ -24,7 +24,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.email-templates.update'],
},
},
@ -39,7 +39,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.advanced-settings.read'],
},
},
@ -54,7 +54,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.advanced-settings.update'],
},
},
@ -69,7 +69,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.providers.read'],
},
},
@ -85,7 +85,7 @@ module.exports = [
policies: [
{
name: 'admin::hasPermissions',
options: {
config: {
actions: ['plugin::users-permissions.providers.update'],
},
},