@strapi/strapi 4.0.0-next.8 → 4.0.2
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.
- package/README.md +14 -14
- package/bin/strapi.js +46 -60
- package/lib/Strapi.js +152 -74
- package/lib/commands/build.js +19 -8
- package/lib/commands/console.js +1 -1
- package/lib/commands/content-types/list.js +22 -0
- package/lib/commands/controllers/list.js +22 -0
- package/lib/commands/develop.js +22 -27
- package/lib/commands/generate-template.js +4 -5
- package/lib/commands/hooks/list.js +22 -0
- package/lib/commands/middlewares/list.js +22 -0
- package/lib/commands/new.js +3 -1
- package/lib/commands/policies/list.js +22 -0
- package/lib/commands/routes/list.js +28 -0
- package/lib/commands/services/list.js +22 -0
- package/lib/commands/watchAdmin.js +18 -9
- package/lib/core/app-configuration/index.js +3 -19
- package/lib/core/bootstrap.js +3 -95
- package/lib/core/domain/content-type/index.js +5 -11
- package/lib/core/domain/module/index.js +42 -11
- package/lib/core/domain/module/validation.js +16 -19
- package/lib/core/loaders/admin.js +2 -2
- package/lib/core/loaders/apis.js +148 -9
- package/lib/core/loaders/components.js +4 -6
- package/lib/core/loaders/index.js +1 -0
- package/lib/core/loaders/middlewares.js +23 -123
- package/lib/core/loaders/plugins/get-enabled-plugins.js +55 -19
- package/lib/core/loaders/plugins/get-user-plugins-config.js +37 -0
- package/lib/core/loaders/plugins/index.js +30 -16
- package/lib/core/loaders/policies.js +1 -1
- package/lib/core/loaders/src-index.js +39 -0
- package/lib/core/registries/apis.js +29 -0
- package/lib/core/registries/content-types.js +61 -12
- package/lib/core/registries/controllers.d.ts +7 -0
- package/lib/core/registries/controllers.js +91 -7
- package/lib/core/registries/hooks.d.ts +20 -0
- package/lib/core/registries/hooks.js +87 -0
- package/lib/core/registries/middlewares.d.ts +5 -0
- package/lib/core/registries/middlewares.js +64 -5
- package/lib/core/registries/modules.js +3 -3
- package/lib/core/registries/plugins.js +2 -2
- package/lib/core/registries/policies.d.ts +9 -0
- package/lib/core/registries/policies.js +64 -5
- package/lib/core/registries/services.d.ts +7 -0
- package/lib/core/registries/services.js +86 -17
- package/lib/core/utils.js +22 -0
- package/lib/core-api/controller/collection-type.js +45 -26
- package/lib/core-api/controller/index.d.ts +25 -0
- package/lib/core-api/controller/index.js +33 -11
- package/lib/core-api/controller/single-type.js +29 -15
- package/lib/core-api/controller/transform.js +62 -6
- package/lib/core-api/routes/index.js +71 -0
- package/lib/core-api/service/collection-type.js +43 -21
- package/lib/core-api/service/index.d.ts +21 -0
- package/lib/core-api/service/index.js +8 -67
- package/lib/core-api/service/pagination.js +125 -0
- package/lib/core-api/service/single-type.js +17 -19
- package/lib/factories.d.ts +48 -0
- package/lib/factories.js +84 -0
- package/lib/index.d.ts +10 -31
- package/lib/index.js +5 -1
- package/lib/middlewares/body.js +33 -0
- package/lib/middlewares/compression.js +8 -0
- package/lib/middlewares/cors.js +58 -0
- package/lib/middlewares/errors.js +40 -0
- package/lib/middlewares/favicon.js +19 -0
- package/lib/middlewares/index.d.ts +5 -0
- package/lib/middlewares/index.js +30 -116
- package/lib/middlewares/ip.js +8 -0
- package/lib/middlewares/logger.js +27 -0
- package/lib/middlewares/powered-by.js +20 -0
- package/lib/middlewares/public/index.js +72 -77
- package/lib/middlewares/query.js +46 -0
- package/lib/middlewares/response-time.js +15 -0
- package/lib/middlewares/responses.js +19 -0
- package/lib/middlewares/security.js +51 -0
- package/lib/middlewares/session/index.js +6 -6
- package/lib/migrations/draft-publish.js +57 -0
- package/lib/services/auth/index.js +87 -0
- package/lib/services/core-store.js +64 -49
- package/lib/services/cron.js +54 -0
- package/lib/services/entity-service/attributes/index.js +31 -0
- package/lib/services/entity-service/attributes/transforms.js +20 -0
- package/lib/services/entity-service/components.js +39 -15
- package/lib/services/entity-service/index.d.ts +91 -0
- package/lib/services/entity-service/index.js +118 -60
- package/lib/services/entity-service/params.js +52 -94
- package/lib/services/entity-validator/index.js +76 -43
- package/lib/services/entity-validator/validators.js +131 -43
- package/lib/services/errors.js +77 -0
- package/lib/services/fs.js +1 -1
- package/lib/services/metrics/index.js +38 -36
- package/lib/services/server/admin-api.js +14 -0
- package/lib/services/server/api.js +36 -0
- package/lib/services/server/compose-endpoint.js +141 -0
- package/lib/services/server/content-api.js +16 -0
- package/lib/{server.js → services/server/http-server.js} +0 -0
- package/lib/services/server/index.js +127 -0
- package/lib/services/server/koa.js +64 -0
- package/lib/services/server/middleware.js +122 -0
- package/lib/services/server/policy.js +32 -0
- package/lib/services/server/register-middlewares.js +110 -0
- package/lib/services/server/register-routes.js +106 -0
- package/lib/services/server/routing.js +120 -0
- package/lib/services/webhook-runner.js +1 -1
- package/lib/utils/ee.js +3 -3
- package/lib/utils/get-dirs.js +17 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/signals.js +24 -0
- package/lib/utils/update-notifier/index.js +2 -1
- package/package.json +94 -97
- package/lib/commands/generate.js +0 -76
- package/lib/core/app-configuration/load-functions.js +0 -28
- package/lib/core-api/index.js +0 -39
- package/lib/load/check-reserved-filename.js +0 -10
- package/lib/load/load-config-files.js +0 -22
- package/lib/load/require-file-parse.js +0 -15
- package/lib/middlewares/boom/defaults.json +0 -5
- package/lib/middlewares/boom/index.js +0 -147
- package/lib/middlewares/cors/index.js +0 -66
- package/lib/middlewares/cron/defaults.json +0 -5
- package/lib/middlewares/cron/index.js +0 -43
- package/lib/middlewares/favicon/defaults.json +0 -7
- package/lib/middlewares/favicon/index.js +0 -32
- package/lib/middlewares/gzip/defaults.json +0 -6
- package/lib/middlewares/gzip/index.js +0 -19
- package/lib/middlewares/helmet/defaults.json +0 -18
- package/lib/middlewares/helmet/index.js +0 -9
- package/lib/middlewares/ip/defaults.json +0 -7
- package/lib/middlewares/ip/index.js +0 -25
- package/lib/middlewares/language/defaults.json +0 -9
- package/lib/middlewares/language/index.js +0 -40
- package/lib/middlewares/logger/defaults.json +0 -5
- package/lib/middlewares/logger/index.js +0 -37
- package/lib/middlewares/parser/defaults.json +0 -11
- package/lib/middlewares/parser/index.js +0 -71
- package/lib/middlewares/poweredBy/defaults.json +0 -5
- package/lib/middlewares/poweredBy/index.js +0 -16
- package/lib/middlewares/public/defaults.json +0 -8
- package/lib/middlewares/responseTime/defaults.json +0 -5
- package/lib/middlewares/responseTime/index.js +0 -25
- package/lib/middlewares/responses/defaults.json +0 -5
- package/lib/middlewares/responses/index.js +0 -18
- package/lib/middlewares/router/defaults.json +0 -7
- package/lib/middlewares/router/index.js +0 -58
- package/lib/middlewares/router/utils/composeEndpoint.js +0 -177
- package/lib/utils/get-prefixed-dependencies.js +0 -7
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { defaultsDeep } = require('lodash/fp');
|
|
4
|
+
const cors = require('@koa/cors');
|
|
5
|
+
|
|
6
|
+
const defaults = {
|
|
7
|
+
origin: '*',
|
|
8
|
+
maxAge: 31536000,
|
|
9
|
+
credentials: true,
|
|
10
|
+
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
|
|
11
|
+
headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
|
|
12
|
+
keepHeadersOnError: false,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @type {import('./').MiddlewareFactory}
|
|
17
|
+
*/
|
|
18
|
+
module.exports = config => {
|
|
19
|
+
const {
|
|
20
|
+
origin,
|
|
21
|
+
expose,
|
|
22
|
+
maxAge,
|
|
23
|
+
credentials,
|
|
24
|
+
methods,
|
|
25
|
+
headers,
|
|
26
|
+
keepHeadersOnError,
|
|
27
|
+
} = defaultsDeep(defaults, config);
|
|
28
|
+
|
|
29
|
+
return cors({
|
|
30
|
+
async origin(ctx) {
|
|
31
|
+
let originList;
|
|
32
|
+
|
|
33
|
+
if (typeof origin === 'function') {
|
|
34
|
+
originList = await origin(ctx);
|
|
35
|
+
} else {
|
|
36
|
+
originList = origin;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const whitelist = Array.isArray(originList) ? originList : originList.split(/\s*,\s*/);
|
|
40
|
+
|
|
41
|
+
const requestOrigin = ctx.accept.headers.origin;
|
|
42
|
+
if (whitelist.includes('*')) {
|
|
43
|
+
return '*';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!whitelist.includes(requestOrigin)) {
|
|
47
|
+
return ctx.throw(`${requestOrigin} is not a valid origin`);
|
|
48
|
+
}
|
|
49
|
+
return requestOrigin;
|
|
50
|
+
},
|
|
51
|
+
exposeHeaders: expose,
|
|
52
|
+
maxAge,
|
|
53
|
+
credentials,
|
|
54
|
+
allowMethods: methods,
|
|
55
|
+
allowHeaders: headers,
|
|
56
|
+
keepHeadersOnError,
|
|
57
|
+
});
|
|
58
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
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 } */) => {
|
|
11
|
+
return async (ctx, next) => {
|
|
12
|
+
try {
|
|
13
|
+
await next();
|
|
14
|
+
|
|
15
|
+
if (!ctx.response._explicitStatus) {
|
|
16
|
+
return ctx.notFound();
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error instanceof ApplicationError) {
|
|
20
|
+
const { status, body } = formatApplicationError(error);
|
|
21
|
+
ctx.status = status;
|
|
22
|
+
ctx.body = body;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (error instanceof HttpError) {
|
|
27
|
+
const { status, body } = formatHttpError(error);
|
|
28
|
+
ctx.status = status;
|
|
29
|
+
ctx.body = body;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
strapi.log.error(error);
|
|
34
|
+
|
|
35
|
+
const { status, body } = formatInternalError(error);
|
|
36
|
+
ctx.status = status;
|
|
37
|
+
ctx.body = body;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { resolve } = require('path');
|
|
4
|
+
const { defaultsDeep } = require('lodash/fp');
|
|
5
|
+
const favicon = require('koa-favicon');
|
|
6
|
+
|
|
7
|
+
const defaults = {
|
|
8
|
+
path: 'favicon.ico',
|
|
9
|
+
maxAge: 86400000,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @type {import('./').MiddlewareFactory}
|
|
14
|
+
*/
|
|
15
|
+
module.exports = (config, { strapi }) => {
|
|
16
|
+
const { maxAge, path: faviconPath } = defaultsDeep(defaults, config);
|
|
17
|
+
|
|
18
|
+
return favicon(resolve(strapi.dirs.root, faviconPath), { maxAge });
|
|
19
|
+
};
|
package/lib/middlewares/index.js
CHANGED
|
@@ -1,119 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// list of enabled middlewares
|
|
36
|
-
const enabledMiddlewares = Object.keys(this.middleware).filter(middlewareEnabled);
|
|
37
|
-
|
|
38
|
-
// Method to initialize middlewares and emit an event.
|
|
39
|
-
const initialize = middlewareKey => {
|
|
40
|
-
if (this.middleware[middlewareKey].loaded === true) return;
|
|
41
|
-
|
|
42
|
-
const module = this.middleware[middlewareKey].load;
|
|
43
|
-
|
|
44
|
-
return new Promise((resolve, reject) => {
|
|
45
|
-
const timeout = setTimeout(
|
|
46
|
-
() => reject(`(middleware: ${middlewareKey}) is taking too long to load.`),
|
|
47
|
-
middlewareConfig.timeout || 1000
|
|
48
|
-
);
|
|
49
|
-
this.middleware[middlewareKey] = merge(this.middleware[middlewareKey], module);
|
|
50
|
-
|
|
51
|
-
Promise.resolve()
|
|
52
|
-
.then(() => module.initialize())
|
|
53
|
-
.then(() => {
|
|
54
|
-
clearTimeout(timeout);
|
|
55
|
-
this.middleware[middlewareKey].loaded = true;
|
|
56
|
-
resolve();
|
|
57
|
-
})
|
|
58
|
-
.catch(err => {
|
|
59
|
-
clearTimeout(timeout);
|
|
60
|
-
|
|
61
|
-
if (err) {
|
|
62
|
-
return reject(err);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Run init functions
|
|
70
|
-
*/
|
|
71
|
-
|
|
72
|
-
// Run beforeInitialize of every middleware
|
|
73
|
-
await Promise.all(
|
|
74
|
-
enabledMiddlewares.map(key => {
|
|
75
|
-
const { beforeInitialize } = this.middleware[key].load;
|
|
76
|
-
if (typeof beforeInitialize === 'function') {
|
|
77
|
-
return beforeInitialize();
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
// run the initialization of an array of middlewares sequentially
|
|
83
|
-
const initMiddlewaresSeq = async middlewareArr => {
|
|
84
|
-
for (let key of uniq(middlewareArr)) {
|
|
85
|
-
await initialize(key);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const middlewaresBefore = get(middlewareConfig, 'load.before', [])
|
|
90
|
-
.filter(middlewareExists)
|
|
91
|
-
.filter(middlewareEnabled);
|
|
92
|
-
|
|
93
|
-
const middlewaresAfter = get(middlewareConfig, 'load.after', [])
|
|
94
|
-
.filter(middlewareExists)
|
|
95
|
-
.filter(middlewareEnabled);
|
|
96
|
-
|
|
97
|
-
const middlewaresOrder = get(middlewareConfig, 'load.order', [])
|
|
98
|
-
.filter(middlewareExists)
|
|
99
|
-
.filter(middlewareEnabled);
|
|
100
|
-
|
|
101
|
-
const unspecifiedMiddlewares = difference(
|
|
102
|
-
enabledMiddlewares,
|
|
103
|
-
middlewaresBefore,
|
|
104
|
-
middlewaresOrder,
|
|
105
|
-
middlewaresAfter
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
// before
|
|
109
|
-
await initMiddlewaresSeq(middlewaresBefore);
|
|
110
|
-
|
|
111
|
-
// ordered // rest of middlewares
|
|
112
|
-
await Promise.all([
|
|
113
|
-
initMiddlewaresSeq(middlewaresOrder),
|
|
114
|
-
Promise.all(unspecifiedMiddlewares.map(initialize)),
|
|
115
|
-
]);
|
|
116
|
-
|
|
117
|
-
// after
|
|
118
|
-
await initMiddlewaresSeq(middlewaresAfter);
|
|
3
|
+
const compression = require('./compression');
|
|
4
|
+
const cors = require('./cors');
|
|
5
|
+
const errors = require('./errors');
|
|
6
|
+
const favicon = require('./favicon');
|
|
7
|
+
const ip = require('./ip');
|
|
8
|
+
const logger = require('./logger');
|
|
9
|
+
const poweredBy = require('./powered-by');
|
|
10
|
+
const body = require('./body');
|
|
11
|
+
const query = require('./query');
|
|
12
|
+
const responseTime = require('./response-time');
|
|
13
|
+
const responses = require('./responses');
|
|
14
|
+
const security = require('./security');
|
|
15
|
+
// TODO: add back ?
|
|
16
|
+
// session: require('./session'),
|
|
17
|
+
const publicStatic = require('./public');
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
errors,
|
|
21
|
+
ip,
|
|
22
|
+
security,
|
|
23
|
+
cors,
|
|
24
|
+
responseTime,
|
|
25
|
+
poweredBy,
|
|
26
|
+
logger,
|
|
27
|
+
compression,
|
|
28
|
+
responses,
|
|
29
|
+
body,
|
|
30
|
+
query,
|
|
31
|
+
favicon,
|
|
32
|
+
public: publicStatic,
|
|
119
33
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
const codeToColor = code => {
|
|
5
|
+
return code >= 500
|
|
6
|
+
? chalk.red(code)
|
|
7
|
+
: code >= 400
|
|
8
|
+
? chalk.yellow(code)
|
|
9
|
+
: code >= 300
|
|
10
|
+
? chalk.cyan(code)
|
|
11
|
+
: code >= 200
|
|
12
|
+
? chalk.green(code)
|
|
13
|
+
: code;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @type {import('./').MiddlewareFactory}
|
|
18
|
+
*/
|
|
19
|
+
module.exports = (_, { strapi }) => {
|
|
20
|
+
return async (ctx, next) => {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
await next();
|
|
23
|
+
const delta = Math.ceil(Date.now() - start);
|
|
24
|
+
|
|
25
|
+
strapi.log.http(`${ctx.method} ${ctx.url} (${delta} ms) ${codeToColor(ctx.status)}`);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { defaultsDeep } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const defaults = {
|
|
6
|
+
poweredBy: 'Strapi <strapi.io>',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @type {import('./').MiddlewareFactory}
|
|
11
|
+
*/
|
|
12
|
+
module.exports = config => {
|
|
13
|
+
const { poweredBy } = defaultsDeep(defaults, config);
|
|
14
|
+
|
|
15
|
+
return async (ctx, next) => {
|
|
16
|
+
await next();
|
|
17
|
+
|
|
18
|
+
ctx.set('X-Powered-By', poweredBy);
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -1,98 +1,93 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Module dependencies
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Node.js core.
|
|
8
3
|
const fs = require('fs');
|
|
9
4
|
const path = require('path');
|
|
10
5
|
const stream = require('stream');
|
|
11
6
|
const _ = require('lodash');
|
|
7
|
+
const { defaultsDeep } = require('lodash/fp');
|
|
12
8
|
const koaStatic = require('koa-static');
|
|
13
9
|
const utils = require('../../utils');
|
|
14
10
|
const serveStatic = require('./serve-static');
|
|
15
11
|
|
|
12
|
+
const defaults = {
|
|
13
|
+
maxAge: 60000,
|
|
14
|
+
defaultIndex: true,
|
|
15
|
+
};
|
|
16
|
+
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* @type {import('../').MiddlewareFactory}
|
|
18
19
|
*/
|
|
20
|
+
module.exports = (config, { strapi }) => {
|
|
21
|
+
const { defaultIndex, maxAge } = defaultsDeep(defaults, config);
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Initialize the hook
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
async initialize() {
|
|
27
|
-
const { defaultIndex, maxAge, path: publicPath } = strapi.config.middleware.settings.public;
|
|
28
|
-
const staticDir = path.resolve(strapi.dir, publicPath || strapi.config.paths.static);
|
|
29
|
-
|
|
30
|
-
if (defaultIndex === true) {
|
|
31
|
-
const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
|
|
23
|
+
if (defaultIndex === true) {
|
|
24
|
+
const index = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (ctx.body != null || ctx.status !== 404) return;
|
|
26
|
+
const serveIndexPage = async (ctx, next) => {
|
|
27
|
+
// defer rendering of strapi index page
|
|
28
|
+
await next();
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
const isInitialized = await utils.isInitialized(strapi);
|
|
40
|
-
const data = {
|
|
41
|
-
serverTime: new Date().toUTCString(),
|
|
42
|
-
isInitialized,
|
|
43
|
-
..._.pick(strapi, [
|
|
44
|
-
'config.info.version',
|
|
45
|
-
'config.info.name',
|
|
46
|
-
'config.admin.url',
|
|
47
|
-
'config.server.url',
|
|
48
|
-
'config.environment',
|
|
49
|
-
'config.serveAdminPanel',
|
|
50
|
-
]),
|
|
51
|
-
};
|
|
52
|
-
const content = _.template(index)(data);
|
|
53
|
-
const body = stream.Readable({
|
|
54
|
-
read() {
|
|
55
|
-
this.push(Buffer.from(content));
|
|
56
|
-
this.push(null);
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
// Serve static.
|
|
60
|
-
ctx.type = 'html';
|
|
61
|
-
ctx.body = body;
|
|
62
|
-
};
|
|
30
|
+
if (ctx.body != null || ctx.status !== 404) return;
|
|
63
31
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
32
|
+
ctx.url = 'index.html';
|
|
33
|
+
const isInitialized = await utils.isInitialized(strapi);
|
|
34
|
+
const data = {
|
|
35
|
+
serverTime: new Date().toUTCString(),
|
|
36
|
+
isInitialized,
|
|
37
|
+
..._.pick(strapi, [
|
|
38
|
+
'config.info.version',
|
|
39
|
+
'config.info.name',
|
|
40
|
+
'config.admin.url',
|
|
41
|
+
'config.server.url',
|
|
42
|
+
'config.environment',
|
|
43
|
+
'config.serveAdminPanel',
|
|
44
|
+
]),
|
|
45
|
+
};
|
|
46
|
+
const content = _.template(index)(data);
|
|
47
|
+
const body = stream.Readable({
|
|
48
|
+
read() {
|
|
49
|
+
this.push(Buffer.from(content));
|
|
50
|
+
this.push(null);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
// Serve static.
|
|
54
|
+
ctx.type = 'html';
|
|
55
|
+
ctx.body = body;
|
|
56
|
+
};
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
|
|
58
|
+
strapi.server.routes([
|
|
59
|
+
{
|
|
60
|
+
method: 'GET',
|
|
61
|
+
path: '/',
|
|
62
|
+
handler: serveIndexPage,
|
|
63
|
+
config: { auth: false },
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
method: 'GET',
|
|
67
|
+
path: '/index.html',
|
|
68
|
+
handler: serveIndexPage,
|
|
69
|
+
config: { auth: false },
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
method: 'GET',
|
|
73
|
+
path: '/assets/images/(.*)',
|
|
74
|
+
handler: serveStatic(path.resolve(__dirname, 'assets/images'), {
|
|
76
75
|
maxage: maxAge,
|
|
77
76
|
defer: true,
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
);
|
|
77
|
+
}),
|
|
78
|
+
config: { auth: false },
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
method: 'GET',
|
|
82
|
+
path: '/(.*)',
|
|
83
|
+
handler: koaStatic(strapi.dirs.public, {
|
|
84
|
+
maxage: maxAge,
|
|
85
|
+
defer: true,
|
|
86
|
+
}),
|
|
87
|
+
config: { auth: false },
|
|
88
|
+
},
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
strapi.router.get(`${strapi.config.admin.path}/*`, serveAdmin);
|
|
96
|
-
},
|
|
97
|
-
};
|
|
92
|
+
return null;
|
|
98
93
|
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @type {import('./').MiddlewareFactory}
|
|
5
|
+
*/
|
|
6
|
+
module.exports = () => {
|
|
7
|
+
return async (ctx, next) => {
|
|
8
|
+
const start = Date.now();
|
|
9
|
+
|
|
10
|
+
await next();
|
|
11
|
+
|
|
12
|
+
const delta = Math.ceil(Date.now() - start);
|
|
13
|
+
ctx.set('X-Response-Time', delta + 'ms');
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { prop, isFunction } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @type {import('./').MiddlewareFactory}
|
|
7
|
+
*/
|
|
8
|
+
module.exports = (config = {}) => {
|
|
9
|
+
return async (ctx, next) => {
|
|
10
|
+
await next();
|
|
11
|
+
|
|
12
|
+
const status = ctx.status;
|
|
13
|
+
const handler = prop(`handlers.${status}`, config);
|
|
14
|
+
|
|
15
|
+
if (isFunction(handler)) {
|
|
16
|
+
await handler(ctx);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { defaultsDeep, merge } = require('lodash/fp');
|
|
4
|
+
const helmet = require('koa-helmet');
|
|
5
|
+
|
|
6
|
+
const defaults = {
|
|
7
|
+
crossOriginEmbedderPolicy: false,
|
|
8
|
+
crossOriginOpenerPolicy: false,
|
|
9
|
+
crossOriginResourcePolicy: false,
|
|
10
|
+
originAgentCluster: 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
|
+
},
|
|
20
|
+
xssFilter: false,
|
|
21
|
+
hsts: {
|
|
22
|
+
maxAge: 31536000,
|
|
23
|
+
includeSubDomains: true,
|
|
24
|
+
},
|
|
25
|
+
frameguard: {
|
|
26
|
+
action: 'sameorigin',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @type {import('./').MiddlewareFactory}
|
|
32
|
+
*/
|
|
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
|
+
};
|