@strapi/strapi 4.0.0-beta.2 → 4.0.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +12 -12
  2. package/bin/strapi.js +6 -1
  3. package/lib/Strapi.js +33 -21
  4. package/lib/commands/build.js +1 -1
  5. package/lib/commands/content-types/list.js +3 -5
  6. package/lib/commands/develop.js +8 -10
  7. package/lib/commands/generate-template.js +4 -5
  8. package/lib/commands/hooks/list.js +3 -5
  9. package/lib/commands/middlewares/list.js +3 -5
  10. package/lib/commands/new.js +3 -1
  11. package/lib/commands/policies/list.js +3 -5
  12. package/lib/commands/services/list.js +22 -0
  13. package/lib/commands/watchAdmin.js +4 -4
  14. package/lib/core/app-configuration/index.js +5 -10
  15. package/lib/core/bootstrap.js +2 -2
  16. package/lib/core/domain/module/index.js +3 -1
  17. package/lib/core/domain/module/validation.js +1 -4
  18. package/lib/core/loaders/admin.js +2 -2
  19. package/lib/core/loaders/apis.js +3 -1
  20. package/lib/core/loaders/plugins/get-enabled-plugins.js +25 -9
  21. package/lib/core/loaders/plugins/index.js +21 -7
  22. package/lib/core/loaders/src-index.js +1 -0
  23. package/lib/core/registries/apis.js +2 -16
  24. package/lib/core/registries/content-types.js +50 -6
  25. package/lib/core/registries/controllers.d.ts +7 -0
  26. package/lib/core/registries/controllers.js +74 -3
  27. package/lib/core/registries/hooks.d.ts +20 -0
  28. package/lib/core/registries/hooks.js +57 -7
  29. package/lib/core/registries/middlewares.d.ts +5 -0
  30. package/lib/core/registries/middlewares.js +61 -2
  31. package/lib/core/registries/policies.d.ts +9 -0
  32. package/lib/core/registries/policies.js +57 -6
  33. package/lib/core/registries/services.d.ts +7 -0
  34. package/lib/core/registries/services.js +67 -11
  35. package/lib/core-api/controller/collection-type.js +38 -11
  36. package/lib/core-api/controller/index.d.ts +25 -0
  37. package/lib/core-api/controller/index.js +30 -11
  38. package/lib/core-api/controller/single-type.js +26 -7
  39. package/lib/core-api/routes/index.js +71 -0
  40. package/lib/core-api/service/collection-type.js +8 -12
  41. package/lib/core-api/service/index.d.ts +21 -0
  42. package/lib/core-api/service/index.js +9 -19
  43. package/lib/core-api/service/pagination.js +7 -2
  44. package/lib/core-api/service/single-type.js +12 -11
  45. package/lib/factories.d.ts +48 -0
  46. package/lib/factories.js +84 -0
  47. package/lib/index.d.ts +1 -0
  48. package/lib/index.js +5 -1
  49. package/lib/middlewares/body.js +33 -0
  50. package/lib/middlewares/compression.js +1 -1
  51. package/lib/middlewares/cors.js +3 -2
  52. package/lib/middlewares/errors.js +24 -119
  53. package/lib/middlewares/favicon.js +3 -3
  54. package/lib/middlewares/index.d.ts +2 -1
  55. package/lib/middlewares/index.js +4 -2
  56. package/lib/middlewares/ip.js +1 -1
  57. package/lib/middlewares/logger.js +1 -1
  58. package/lib/middlewares/powered-by.js +4 -2
  59. package/lib/middlewares/public/index.js +4 -7
  60. package/lib/middlewares/query.js +46 -0
  61. package/lib/middlewares/responses.js +2 -2
  62. package/lib/middlewares/security.js +29 -3
  63. package/lib/middlewares/session/index.js +1 -1
  64. package/lib/services/auth/index.js +1 -6
  65. package/lib/services/entity-service/attributes/index.js +31 -0
  66. package/lib/services/entity-service/attributes/transforms.js +20 -0
  67. package/lib/services/entity-service/components.js +2 -3
  68. package/lib/services/entity-service/index.d.ts +1 -1
  69. package/lib/services/entity-service/index.js +83 -27
  70. package/lib/services/entity-service/params.js +37 -87
  71. package/lib/services/entity-validator/index.js +76 -43
  72. package/lib/services/entity-validator/validators.js +129 -43
  73. package/lib/services/errors.js +77 -0
  74. package/lib/services/metrics/index.js +37 -35
  75. package/lib/services/server/compose-endpoint.js +39 -11
  76. package/lib/services/server/content-api.js +1 -1
  77. package/lib/services/server/index.js +4 -9
  78. package/lib/services/server/koa.js +64 -0
  79. package/lib/services/server/middleware.js +8 -1
  80. package/lib/services/server/policy.js +8 -10
  81. package/lib/services/server/register-middlewares.js +7 -2
  82. package/lib/services/server/register-routes.js +1 -3
  83. package/lib/services/server/routing.js +13 -0
  84. package/lib/utils/get-dirs.js +1 -0
  85. package/lib/utils/signals.js +24 -0
  86. package/package.json +22 -17
  87. package/lib/core/app-configuration/load-functions.js +0 -28
  88. package/lib/core-api/index.js +0 -39
  89. package/lib/middlewares/request.js +0 -74
@@ -0,0 +1,48 @@
1
+ import { Service } from './core-api/service';
2
+ import { Controller } from './core-api/controller';
3
+ import { Middleware } from './middlewares';
4
+ import { Policy } from './core/registries/policies';
5
+
6
+ type ControllerConfig = Controller;
7
+
8
+ type ServiceConfig = Service;
9
+
10
+ type HandlerConfig = {
11
+ auth: false | { scope: string[] };
12
+ policies: Array<string | Policy>;
13
+ middlewares: Array<string | Middleware>;
14
+ };
15
+
16
+ type SingleTypeRouterConfig = {
17
+ find: HandlerConfig;
18
+ update: HandlerConfig;
19
+ delete: HandlerConfig;
20
+ };
21
+
22
+ type CollectionTypeRouterConfig = {
23
+ find: HandlerConfig;
24
+ findOne: HandlerConfig;
25
+ create: HandlerConfig;
26
+ update: HandlerConfig;
27
+ delete: HandlerConfig;
28
+ };
29
+
30
+ type RouterConfig = {
31
+ prefix: string;
32
+ only: string[];
33
+ except: string[];
34
+ config: SingleTypeRouterConfig | CollectionTypeRouterConfig;
35
+ };
36
+
37
+ interface Route {
38
+ method: string;
39
+ path: string;
40
+ }
41
+ interface Router {
42
+ prefix: string;
43
+ routes: Route[];
44
+ }
45
+
46
+ export function createCoreRouter(uid: string, cfg: RouterConfig): () => Router;
47
+ export function createCoreController(uid: string, cfg: ControllerConfig): () => Controller;
48
+ export function createCoreService(uid: string, cfg: ServiceConfig): () => Service;
@@ -0,0 +1,84 @@
1
+ 'use strict';
2
+
3
+ const { pipe, omit, pick } = require('lodash/fp');
4
+
5
+ const { createController } = require('./core-api/controller');
6
+ const { createService } = require('./core-api/service');
7
+ const { createRoutes } = require('./core-api/routes');
8
+
9
+ const createCoreController = (uid, cfg = {}) => {
10
+ return ({ strapi }) => {
11
+ const baseController = createController({
12
+ contentType: strapi.contentType(uid),
13
+ });
14
+
15
+ let userCtrl = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
16
+
17
+ for (const methodName of Object.keys(baseController)) {
18
+ if (userCtrl[methodName] === undefined) {
19
+ userCtrl[methodName] = baseController[methodName];
20
+ }
21
+ }
22
+
23
+ Object.setPrototypeOf(userCtrl, baseController);
24
+ return userCtrl;
25
+ };
26
+ };
27
+
28
+ const createCoreService = (uid, cfg = {}) => {
29
+ return ({ strapi }) => {
30
+ const baseService = createService({
31
+ contentType: strapi.contentType(uid),
32
+ });
33
+
34
+ let userService = typeof cfg === 'function' ? cfg({ strapi }) : cfg;
35
+
36
+ for (const methodName of Object.keys(baseService)) {
37
+ if (userService[methodName] === undefined) {
38
+ userService[methodName] = baseService[methodName];
39
+ }
40
+ }
41
+
42
+ Object.setPrototypeOf(userService, baseService);
43
+ return userService;
44
+ };
45
+ };
46
+
47
+ const createCoreRouter = (uid, cfg = {}) => {
48
+ const { prefix, config = {}, only, except } = cfg;
49
+ let routes;
50
+
51
+ return {
52
+ get prefix() {
53
+ return prefix;
54
+ },
55
+ get routes() {
56
+ if (!routes) {
57
+ const contentType = strapi.contentType(uid);
58
+
59
+ const defaultRoutes = createRoutes({ contentType });
60
+
61
+ Object.keys(defaultRoutes).forEach(routeName => {
62
+ const defaultRoute = defaultRoutes[routeName];
63
+
64
+ Object.assign(defaultRoute.config, config[routeName] || {});
65
+ });
66
+
67
+ const selectedRoutes = pipe(
68
+ routes => (except ? omit(except, routes) : routes),
69
+ routes => (only ? pick(only, routes) : routes)
70
+ )(defaultRoutes);
71
+
72
+ routes = Object.values(selectedRoutes);
73
+ }
74
+
75
+ return routes;
76
+ },
77
+ };
78
+ };
79
+
80
+ module.exports = {
81
+ createCoreController,
82
+ createCoreService,
83
+ createCoreRouter,
84
+ };
package/lib/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { Database } from '@strapi/database';
2
2
  import { EntityService } from './services/entity-service';
3
3
  import { Strapi as StrapiClass } from './Strapi';
4
4
 
5
+ export * as factories from './factories';
5
6
  interface StrapiInterface extends StrapiClass {
6
7
  query: Database['query'];
7
8
  entityService: EntityService;
package/lib/index.js CHANGED
@@ -1,3 +1,7 @@
1
1
  'use strict';
2
2
 
3
- module.exports = require('./Strapi');
3
+ const Strapi = require('./Strapi');
4
+
5
+ Strapi.factories = require('./factories');
6
+
7
+ module.exports = Strapi;
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const body = require('koa-body');
5
+
6
+ const defaults = {
7
+ multipart: true,
8
+ patchKoa: true,
9
+ };
10
+
11
+ /**
12
+ * @type {import('./').MiddlewareFactory}
13
+ */
14
+ module.exports = config => {
15
+ const bodyConfig = defaultsDeep(defaults, config);
16
+
17
+ return async (ctx, next) => {
18
+ // TODO: find a better way later
19
+ if (ctx.url === '/graphql') {
20
+ return next();
21
+ }
22
+
23
+ try {
24
+ await body({ patchKoa: true, ...bodyConfig })(ctx, next);
25
+ } catch (e) {
26
+ if ((e || {}).message && e.message.includes('maxFileSize exceeded')) {
27
+ return ctx.payloadTooLarge('FileTooBig');
28
+ }
29
+
30
+ throw e;
31
+ }
32
+ };
33
+ };
@@ -5,4 +5,4 @@ const compress = require('koa-compress');
5
5
  /**
6
6
  * @type {import('./').MiddlewareFactory}
7
7
  */
8
- module.exports = options => compress(options);
8
+ module.exports = config => compress(config);
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const { defaultsDeep } = require('lodash/fp');
3
4
  const cors = require('@koa/cors');
4
5
 
5
6
  const defaults = {
@@ -14,7 +15,7 @@ const defaults = {
14
15
  /**
15
16
  * @type {import('./').MiddlewareFactory}
16
17
  */
17
- module.exports = options => {
18
+ module.exports = config => {
18
19
  const {
19
20
  origin,
20
21
  expose,
@@ -23,7 +24,7 @@ module.exports = options => {
23
24
  methods,
24
25
  headers,
25
26
  keepHeadersOnError,
26
- } = Object.assign({}, defaults, options);
27
+ } = defaultsDeep(defaults, config);
27
28
 
28
29
  return cors({
29
30
  async origin(ctx) {
@@ -1,135 +1,40 @@
1
1
  'use strict';
2
2
 
3
- const _ = require('lodash');
4
- const Boom = require('@hapi/boom');
5
- const delegate = require('delegates');
6
-
7
- const boomMethods = [
8
- 'badRequest',
9
- 'unauthorized',
10
- 'paymentRequired',
11
- 'forbidden',
12
- 'notFound',
13
- 'methodNotAllowed',
14
- 'notAcceptable',
15
- 'proxyAuthRequired',
16
- 'clientTimeout',
17
- 'conflict',
18
- 'resourceGone',
19
- 'lengthRequired',
20
- 'preconditionFailed',
21
- 'entityTooLarge',
22
- 'uriTooLong',
23
- 'unsupportedMediaType',
24
- 'rangeNotSatisfiable',
25
- 'expectationFailed',
26
- 'teapot',
27
- 'badData',
28
- 'locked',
29
- 'failedDependency',
30
- 'preconditionRequired',
31
- 'tooManyRequests',
32
- 'illegal',
33
- 'badImplementation',
34
- 'notImplemented',
35
- 'badGateway',
36
- 'serverUnavailable',
37
- 'gatewayTimeout',
38
- ];
39
-
40
- const formatBoomPayload = boomError => {
41
- if (!Boom.isBoom(boomError)) {
42
- boomError = Boom.boomify(boomError, {
43
- statusCode: boomError.status || 500,
44
- });
45
- }
46
-
47
- const { output } = boomError;
48
-
49
- if (output.statusCode < 500 && !_.isNil(boomError.data)) {
50
- output.payload.data = boomError.data;
51
- }
52
-
53
- return { status: output.statusCode, body: output.payload };
54
- };
55
-
56
- /**
57
- * Create short responses ctx.(send|created|deleted)
58
- * @param {Strapi} strapi
59
- */
60
- const createResponseUtils = strapi => {
61
- const delegator = delegate(strapi.server.app.context, 'response');
62
-
63
- boomMethods.forEach(method => {
64
- strapi.server.app.response[method] = function(msg, ...rest) {
65
- const boomError = Boom[method](msg, ...rest) || {};
66
-
67
- const { status, body } = formatBoomPayload(boomError);
68
-
69
- // keep retro-compatibility for old error formats
70
- body.message = msg || body.data || body.message;
71
-
72
- this.body = body;
73
- this.status = status;
74
- };
75
-
76
- delegator.method(method);
77
- });
78
-
79
- strapi.server.app.response.send = function(data, status = 200) {
80
- this.status = status;
81
- this.body = data;
82
- };
83
-
84
- strapi.server.app.response.created = function(data) {
85
- this.status = 201;
86
- this.body = data;
87
- };
88
-
89
- strapi.server.app.response.deleted = function(data) {
90
- if (_.isNil(data)) {
91
- this.status = 204;
92
- } else {
93
- this.status = 200;
94
- this.body = data;
95
- }
96
- };
97
-
98
- delegator
99
- .method('send')
100
- .method('created')
101
- .method('deleted');
102
- };
103
-
104
- /**
105
- * @type {import('./').MiddlewareFactory}
106
- */
107
- module.exports = (options, { strapi }) => {
108
- createResponseUtils(strapi);
109
- strapi.errors = Boom;
110
-
3
+ const { HttpError, ApplicationError } = require('@strapi/utils').errors;
4
+ const {
5
+ formatApplicationError,
6
+ formatHttpError,
7
+ formatInternalError,
8
+ } = require('../services/errors');
9
+
10
+ module.exports = (/* _, { strapi } */) => {
111
11
  return async (ctx, next) => {
112
12
  try {
113
- // App logic.
114
13
  await next();
115
14
 
116
- if (_.isNil(ctx.body) && (_.isNil(ctx.status) || ctx.status === 404)) {
117
- ctx.notFound();
15
+ if (!ctx.response._explicitStatus) {
16
+ return ctx.notFound();
118
17
  }
119
18
  } catch (error) {
120
- // emit error if configured
121
- if (strapi.config.get('server.emitErrors', false)) {
122
- strapi.server.app.emit('error', error, ctx);
19
+ if (error instanceof ApplicationError) {
20
+ const { status, body } = formatApplicationError(error);
21
+ ctx.status = status;
22
+ ctx.body = body;
23
+ return;
123
24
  }
124
25
 
125
- const { status, body } = formatBoomPayload(error);
126
-
127
- if (status >= 500) {
128
- strapi.log.error(error);
26
+ if (error instanceof HttpError) {
27
+ const { status, body } = formatHttpError(error);
28
+ ctx.status = status;
29
+ ctx.body = body;
30
+ return;
129
31
  }
130
32
 
131
- ctx.body = body;
33
+ strapi.log.error(error);
34
+
35
+ const { status, body } = formatInternalError(error);
132
36
  ctx.status = status;
37
+ ctx.body = body;
133
38
  }
134
39
  };
135
40
  };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { resolve } = require('path');
4
- const { defaultsDeep } = require('lodash');
4
+ const { defaultsDeep } = require('lodash/fp');
5
5
  const favicon = require('koa-favicon');
6
6
 
7
7
  const defaults = {
@@ -12,8 +12,8 @@ const defaults = {
12
12
  /**
13
13
  * @type {import('./').MiddlewareFactory}
14
14
  */
15
- module.exports = (options, { strapi }) => {
16
- const { maxAge, path: faviconPath } = defaultsDeep(defaults, options);
15
+ module.exports = (config, { strapi }) => {
16
+ const { maxAge, path: faviconPath } = defaultsDeep(defaults, config);
17
17
 
18
18
  return favicon(resolve(strapi.dirs.root, faviconPath), { maxAge });
19
19
  };
@@ -1,4 +1,5 @@
1
1
  import { Strapi } from '../';
2
2
  import { Middleware } from 'koa';
3
3
 
4
- export type MiddlewareFactory = (options: any, ctx: { strapi: Strapi }) => Middleware;
4
+ export type MiddlewareFactory = (config: any, ctx: { strapi: Strapi }) => Middleware | null;
5
+ export type Middleware = Middleware;
@@ -7,7 +7,8 @@ const favicon = require('./favicon');
7
7
  const ip = require('./ip');
8
8
  const logger = require('./logger');
9
9
  const poweredBy = require('./powered-by');
10
- const request = require('./request');
10
+ const body = require('./body');
11
+ const query = require('./query');
11
12
  const responseTime = require('./response-time');
12
13
  const responses = require('./responses');
13
14
  const security = require('./security');
@@ -25,7 +26,8 @@ module.exports = {
25
26
  logger,
26
27
  compression,
27
28
  responses,
28
- request,
29
+ body,
30
+ query,
29
31
  favicon,
30
32
  public: publicStatic,
31
33
  };
@@ -5,4 +5,4 @@ const ip = require('koa-ip');
5
5
  /**
6
6
  * @type {import('./').MiddlewareFactory}
7
7
  */
8
- module.exports = options => ip(options);
8
+ module.exports = config => ip(config);
@@ -16,7 +16,7 @@ const codeToColor = code => {
16
16
  /**
17
17
  * @type {import('./').MiddlewareFactory}
18
18
  */
19
- module.exports = (options, { strapi }) => {
19
+ module.exports = (_, { strapi }) => {
20
20
  return async (ctx, next) => {
21
21
  const start = Date.now();
22
22
  await next();
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { defaultsDeep } = require('lodash/fp');
4
+
3
5
  const defaults = {
4
6
  poweredBy: 'Strapi <strapi.io>',
5
7
  };
@@ -7,8 +9,8 @@ const defaults = {
7
9
  /**
8
10
  * @type {import('./').MiddlewareFactory}
9
11
  */
10
- module.exports = options => {
11
- const { poweredBy } = Object.assign({}, defaults, options);
12
+ module.exports = config => {
13
+ const { poweredBy } = defaultsDeep(defaults, config);
12
14
 
13
15
  return async (ctx, next) => {
14
16
  await next();
@@ -11,17 +11,14 @@ const serveStatic = require('./serve-static');
11
11
 
12
12
  const defaults = {
13
13
  maxAge: 60000,
14
- path: './public',
15
14
  defaultIndex: true,
16
15
  };
17
16
 
18
17
  /**
19
18
  * @type {import('../').MiddlewareFactory}
20
19
  */
21
- module.exports = (options, { strapi }) => {
22
- const { defaultIndex, maxAge, path: publicPath } = defaultsDeep(defaults, options);
23
-
24
- const staticDir = path.resolve(strapi.dirs.root, publicPath || strapi.config.paths.static);
20
+ module.exports = (config, { strapi }) => {
21
+ const { defaultIndex, maxAge } = defaultsDeep(defaults, config);
25
22
 
26
23
  if (defaultIndex === true) {
27
24
  const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
@@ -83,7 +80,7 @@ module.exports = (options, { strapi }) => {
83
80
  {
84
81
  method: 'GET',
85
82
  path: '/(.*)',
86
- handler: koaStatic(staticDir, {
83
+ handler: koaStatic(strapi.dirs.public, {
87
84
  maxage: maxAge,
88
85
  defer: true,
89
86
  }),
@@ -122,5 +119,5 @@ module.exports = (options, { strapi }) => {
122
119
  },
123
120
  ]);
124
121
 
125
- return async (ctx, next) => next();
122
+ return null;
126
123
  };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ const { defaultsDeep } = require('lodash/fp');
4
+ const qs = require('qs');
5
+
6
+ const defaults = {
7
+ strictNullHandling: true,
8
+ arrayLimit: 100,
9
+ depth: 20,
10
+ };
11
+
12
+ /**
13
+ * Body parser hook
14
+ */
15
+ const addQsParser = (app, settings) => {
16
+ Object.defineProperty(app.request, 'query', {
17
+ configurable: false,
18
+ enumerable: true,
19
+ /*
20
+ * Get parsed query-string.
21
+ */
22
+ get() {
23
+ const qstr = this.querystring;
24
+ const cache = (this._querycache = this._querycache || {});
25
+ return cache[qstr] || (cache[qstr] = qs.parse(qstr, settings));
26
+ },
27
+
28
+ /*
29
+ * Set query-string as an object.
30
+ */
31
+ set(obj) {
32
+ this.querystring = qs.stringify(obj);
33
+ },
34
+ });
35
+
36
+ return app;
37
+ };
38
+
39
+ /**
40
+ * @type {import('./').MiddlewareFactory}
41
+ */
42
+ module.exports = (config, { strapi }) => {
43
+ addQsParser(strapi.server.app, defaultsDeep(defaults, config));
44
+
45
+ return null;
46
+ };
@@ -5,12 +5,12 @@ const { prop, isFunction } = require('lodash/fp');
5
5
  /**
6
6
  * @type {import('./').MiddlewareFactory}
7
7
  */
8
- module.exports = (options = {}) => {
8
+ module.exports = (config = {}) => {
9
9
  return async (ctx, next) => {
10
10
  await next();
11
11
 
12
12
  const status = ctx.status;
13
- const handler = prop(`handlers.${status}`, options);
13
+ const handler = prop(`handlers.${status}`, config);
14
14
 
15
15
  if (isFunction(handler)) {
16
16
  await handler(ctx);
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { defaultsDeep } = require('lodash/fp');
3
+ const { defaultsDeep, merge } = require('lodash/fp');
4
4
  const helmet = require('koa-helmet');
5
5
 
6
6
  const defaults = {
@@ -8,7 +8,15 @@ const defaults = {
8
8
  crossOriginOpenerPolicy: false,
9
9
  crossOriginResourcePolicy: false,
10
10
  originAgentCluster: false,
11
- contentSecurityPolicy: false,
11
+ contentSecurityPolicy: {
12
+ useDefaults: true,
13
+ directives: {
14
+ 'connect-src': ["'self'", 'https:'],
15
+ 'img-src': ["'self'", 'data:', 'blob:'],
16
+ 'media-src': ["'self'", 'data:', 'blob:'],
17
+ upgradeInsecureRequests: null,
18
+ },
19
+ },
12
20
  xssFilter: false,
13
21
  hsts: {
14
22
  maxAge: 31536000,
@@ -22,4 +30,22 @@ const defaults = {
22
30
  /**
23
31
  * @type {import('./').MiddlewareFactory}
24
32
  */
25
- module.exports = options => helmet(defaultsDeep(defaults, options));
33
+ module.exports = config => (ctx, next) => {
34
+ let helmetConfig = defaultsDeep(defaults, config);
35
+
36
+ if (
37
+ ctx.method === 'GET' &&
38
+ ['/graphql', '/documentation'].some(str => ctx.path.startsWith(str))
39
+ ) {
40
+ helmetConfig = merge(helmetConfig, {
41
+ contentSecurityPolicy: {
42
+ directives: {
43
+ 'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'],
44
+ 'img-src': ["'self'", 'data:', 'cdn.jsdelivr.net', 'strapi.io'],
45
+ },
46
+ },
47
+ });
48
+ }
49
+
50
+ return helmet(helmetConfig)(ctx, next);
51
+ };
@@ -9,7 +9,7 @@ const session = require('koa-session');
9
9
  */
10
10
  module.exports = strapi => {
11
11
  const requireStore = store => {
12
- return require(path.resolve(strapi.config.appPath, 'node_modules', 'koa-' + store));
12
+ return require(path.resolve(strapi.dirs.root, 'node_modules', 'koa-' + store));
13
13
  };
14
14
 
15
15
  const defineStore = session => {
@@ -3,8 +3,7 @@
3
3
  const { strict: assert } = require('assert');
4
4
  const { has, prop } = require('lodash/fp');
5
5
 
6
- class UnauthorizedError extends Error {}
7
- class ForbiddenError extends Error {}
6
+ const { UnauthorizedError } = require('@strapi/utils').errors;
8
7
 
9
8
  const INVALID_STRATEGY_MSG =
10
9
  'Invalid auth strategy. Expecting an object with properties {name: string, authenticate: function, verify: function}';
@@ -22,10 +21,6 @@ const createAuthentication = () => {
22
21
  const strategies = {};
23
22
 
24
23
  return {
25
- errors: {
26
- UnauthorizedError,
27
- ForbiddenError,
28
- },
29
24
  register(type, strategy) {
30
25
  validStrategy(strategy);
31
26
 
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ const transforms = require('./transforms');
4
+
5
+ const applyTransforms = (data, context) => {
6
+ const { contentType } = context;
7
+
8
+ const entries = Object.entries(data);
9
+
10
+ for (const [attributeName, value] of entries) {
11
+ const attribute = contentType.attributes[attributeName];
12
+
13
+ if (!attribute) {
14
+ continue;
15
+ }
16
+
17
+ const transform = transforms[attribute.type];
18
+
19
+ if (transform) {
20
+ const attributeContext = { ...context, attributeName, attribute };
21
+
22
+ data[attributeName] = transform(value, attributeContext);
23
+ }
24
+ }
25
+
26
+ return data;
27
+ };
28
+
29
+ module.exports = {
30
+ applyTransforms,
31
+ };