@strapi/strapi 4.6.0-beta.1 → 4.6.0
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 -10
- package/bin/strapi.js +101 -5
- package/ee/ee-store.js +18 -0
- package/ee/index.js +173 -0
- package/ee/license.js +102 -0
- package/{lib/utils → ee}/resources/key.pub +0 -0
- package/lib/Strapi.js +15 -5
- package/lib/commands/builders/admin.js +1 -1
- package/lib/commands/transfer/export.js +37 -36
- package/lib/commands/transfer/import.js +42 -50
- package/lib/commands/transfer/transfer.js +129 -0
- package/lib/commands/transfer/utils.js +93 -6
- package/lib/commands/utils/commander.js +76 -13
- package/lib/commands/utils/helpers.js +108 -0
- package/lib/core/loaders/plugins/index.js +9 -1
- package/lib/core-api/service/index.d.ts +1 -1
- package/lib/core-api/service/single-type.js +14 -1
- package/lib/services/entity-service/components.js +39 -36
- package/lib/services/entity-service/index.js +13 -2
- package/lib/services/errors.js +5 -1
- package/lib/services/event-hub.js +70 -8
- package/lib/services/metrics/index.js +3 -54
- package/lib/services/metrics/sender.js +1 -3
- package/lib/types/core/strapi/index.d.ts +5 -0
- package/lib/types/factories.d.ts +1 -1
- package/lib/utils/cron.js +56 -0
- package/lib/utils/ee.js +1 -121
- package/lib/utils/startup-logger.js +2 -4
- package/package.json +18 -17
- package/lib/commands/utils/index.js +0 -20
package/README.md
CHANGED
|
@@ -80,25 +80,29 @@ Complete installation requirements can be found in the documentation under <a hr
|
|
|
80
80
|
- CentOS/RHEL 8
|
|
81
81
|
- macOS Mojave
|
|
82
82
|
- Windows 10
|
|
83
|
-
- Docker
|
|
83
|
+
- Docker
|
|
84
84
|
|
|
85
85
|
(Please note that Strapi may work on other operating systems, but these are not tested nor officially supported at this time.)
|
|
86
86
|
|
|
87
87
|
**Node:**
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
Strapi only supports maintenance and LTS versions of Node.js. Please refer to the <a href="https://nodejs.org/en/about/releases/">Node.js release schedule</a> for more information. NPM versions installed by default with Node.js are supported. Generally it's recommended to use yarn over npm where possible.
|
|
90
|
+
|
|
91
|
+
| Strapi Version | Recommended | Minimum |
|
|
92
|
+
| -------------- | ----------- | ------- |
|
|
93
|
+
| 4.3.9 and up | 18.x | 14.x |
|
|
94
|
+
| 4.0.x to 4.3.8 | 16.x | 14.x |
|
|
91
95
|
|
|
92
96
|
**Database:**
|
|
93
97
|
|
|
94
|
-
| Database |
|
|
95
|
-
| ---------- |
|
|
96
|
-
| MySQL | 5.7.8 |
|
|
97
|
-
| MariaDB | 10.
|
|
98
|
-
| PostgreSQL |
|
|
99
|
-
| SQLite | 3
|
|
98
|
+
| Database | Recommended | Minimum |
|
|
99
|
+
| ---------- | ----------- | ------- |
|
|
100
|
+
| MySQL | 8.0 | 5.7.8 |
|
|
101
|
+
| MariaDB | 10.6 | 10.3 |
|
|
102
|
+
| PostgreSQL | 14.0 | 11.0 |
|
|
103
|
+
| SQLite | 3 | 3 |
|
|
100
104
|
|
|
101
|
-
**We recommend always using the latest version of Strapi to start your new projects**.
|
|
105
|
+
**We recommend always using the latest version of Strapi stable to start your new projects**.
|
|
102
106
|
|
|
103
107
|
## Features
|
|
104
108
|
|
package/bin/strapi.js
CHANGED
|
@@ -14,7 +14,21 @@ const inquirer = require('inquirer');
|
|
|
14
14
|
const program = new Command();
|
|
15
15
|
|
|
16
16
|
const packageJSON = require('../package.json');
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
promptEncryptionKey,
|
|
19
|
+
confirmMessage,
|
|
20
|
+
forceOption,
|
|
21
|
+
} = require('../lib/commands/utils/commander');
|
|
22
|
+
const { exitWith } = require('../lib/commands/utils/helpers');
|
|
23
|
+
const {
|
|
24
|
+
excludeOption,
|
|
25
|
+
onlyOption,
|
|
26
|
+
validateExcludeOnly,
|
|
27
|
+
} = require('../lib/commands/transfer/utils');
|
|
28
|
+
|
|
29
|
+
process.on('SIGINT', () => {
|
|
30
|
+
process.exit();
|
|
31
|
+
});
|
|
18
32
|
|
|
19
33
|
const checkCwdIsStrapiApp = (name) => {
|
|
20
34
|
const logErrorAndExit = () => {
|
|
@@ -258,10 +272,65 @@ program
|
|
|
258
272
|
.option('-s, --silent', `Run the generation silently, without any output`, false)
|
|
259
273
|
.action(getLocalScript('ts/generate-types'));
|
|
260
274
|
|
|
275
|
+
// if (process.env.STRAPI_EXPERIMENTAL === 'true') {
|
|
276
|
+
// // `$ strapi transfer`
|
|
277
|
+
// program
|
|
278
|
+
// .command('transfer')
|
|
279
|
+
// .description('Transfer data from one source to another')
|
|
280
|
+
// .allowExcessArguments(false)
|
|
281
|
+
// .addOption(
|
|
282
|
+
// new Option(
|
|
283
|
+
// '--from <sourceURL>',
|
|
284
|
+
// `URL of the remote Strapi instance to get data from`
|
|
285
|
+
// ).argParser(parseURL)
|
|
286
|
+
// )
|
|
287
|
+
// .addOption(
|
|
288
|
+
// new Option(
|
|
289
|
+
// '--to <destinationURL>',
|
|
290
|
+
// `URL of the remote Strapi instance to send data to`
|
|
291
|
+
// ).argParser(parseURL)
|
|
292
|
+
// )
|
|
293
|
+
// .addOption(forceOption)
|
|
294
|
+
// // Validate URLs
|
|
295
|
+
// .hook(
|
|
296
|
+
// 'preAction',
|
|
297
|
+
// ifOptions(
|
|
298
|
+
// (opts) => opts.from,
|
|
299
|
+
// (thisCommand) => assertUrlHasProtocol(thisCommand.opts().from, ['https:', 'http:'])
|
|
300
|
+
// )
|
|
301
|
+
// )
|
|
302
|
+
// .hook(
|
|
303
|
+
// 'preAction',
|
|
304
|
+
// ifOptions(
|
|
305
|
+
// (opts) => opts.to,
|
|
306
|
+
// (thisCommand) => assertUrlHasProtocol(thisCommand.opts().to, ['https:', 'http:'])
|
|
307
|
+
// )
|
|
308
|
+
// )
|
|
309
|
+
// .hook(
|
|
310
|
+
// 'preAction',
|
|
311
|
+
// ifOptions(
|
|
312
|
+
// (opts) => !opts.from && !opts.to,
|
|
313
|
+
// () => exitWith(1, 'At least one source (from) or destination (to) option must be provided')
|
|
314
|
+
// )
|
|
315
|
+
// )
|
|
316
|
+
// .addOption(forceOption)
|
|
317
|
+
// .addOption(excludeOption)
|
|
318
|
+
// .addOption(onlyOption)
|
|
319
|
+
// .hook('preAction', validateExcludeOnly)
|
|
320
|
+
// .hook(
|
|
321
|
+
// 'preAction',
|
|
322
|
+
// confirmMessage(
|
|
323
|
+
// 'The import will delete all data in the remote database. Are you sure you want to proceed?'
|
|
324
|
+
// )
|
|
325
|
+
// )
|
|
326
|
+
// .action(getLocalScript('transfer/transfer'));
|
|
327
|
+
// }
|
|
328
|
+
|
|
261
329
|
// `$ strapi export`
|
|
262
330
|
program
|
|
263
331
|
.command('export')
|
|
264
332
|
.description('Export data from Strapi to file')
|
|
333
|
+
.allowExcessArguments(false)
|
|
265
334
|
.addOption(
|
|
266
335
|
new Option('--no-encrypt', `Disables 'aes-128-ecb' encryption of the output file`).default(true)
|
|
267
336
|
)
|
|
@@ -273,7 +342,9 @@ program
|
|
|
273
342
|
)
|
|
274
343
|
)
|
|
275
344
|
.addOption(new Option('-f, --file <file>', 'name to use for exported file (without extensions)'))
|
|
276
|
-
.
|
|
345
|
+
.addOption(excludeOption)
|
|
346
|
+
.addOption(onlyOption)
|
|
347
|
+
.hook('preAction', validateExcludeOnly)
|
|
277
348
|
.hook('preAction', promptEncryptionKey)
|
|
278
349
|
.action(getLocalScript('transfer/export'));
|
|
279
350
|
|
|
@@ -281,6 +352,7 @@ program
|
|
|
281
352
|
program
|
|
282
353
|
.command('import')
|
|
283
354
|
.description('Import data from file to Strapi')
|
|
355
|
+
.allowExcessArguments(false)
|
|
284
356
|
.requiredOption(
|
|
285
357
|
'-f, --file <file>',
|
|
286
358
|
'path and filename for the Strapi export file you want to import'
|
|
@@ -291,7 +363,10 @@ program
|
|
|
291
363
|
'Provide encryption key in command instead of using the prompt'
|
|
292
364
|
)
|
|
293
365
|
)
|
|
294
|
-
.
|
|
366
|
+
.addOption(forceOption)
|
|
367
|
+
.addOption(excludeOption)
|
|
368
|
+
.addOption(onlyOption)
|
|
369
|
+
.hook('preAction', validateExcludeOnly)
|
|
295
370
|
.hook('preAction', async (thisCommand) => {
|
|
296
371
|
const opts = thisCommand.opts();
|
|
297
372
|
const ext = path.extname(String(opts.file));
|
|
@@ -307,13 +382,34 @@ program
|
|
|
307
382
|
},
|
|
308
383
|
]);
|
|
309
384
|
if (!answers.key?.length) {
|
|
310
|
-
|
|
311
|
-
process.exit(0);
|
|
385
|
+
exitWith(0, 'No key entered, aborting import.');
|
|
312
386
|
}
|
|
313
387
|
opts.key = answers.key;
|
|
314
388
|
}
|
|
315
389
|
}
|
|
316
390
|
})
|
|
391
|
+
// set decrypt and decompress options based on filename
|
|
392
|
+
.hook('preAction', (thisCommand) => {
|
|
393
|
+
const opts = thisCommand.opts();
|
|
394
|
+
|
|
395
|
+
const { extname, parse } = path;
|
|
396
|
+
|
|
397
|
+
let file = opts.file;
|
|
398
|
+
|
|
399
|
+
if (extname(file) === '.enc') {
|
|
400
|
+
file = parse(file).name; // trim the .enc extension
|
|
401
|
+
thisCommand.opts().decrypt = true;
|
|
402
|
+
} else {
|
|
403
|
+
thisCommand.opts().decrypt = false;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (extname(file) === '.gz') {
|
|
407
|
+
file = parse(file).name; // trim the .gz extension
|
|
408
|
+
thisCommand.opts().decompress = true;
|
|
409
|
+
} else {
|
|
410
|
+
thisCommand.opts().decompress = false;
|
|
411
|
+
}
|
|
412
|
+
})
|
|
317
413
|
.hook(
|
|
318
414
|
'preAction',
|
|
319
415
|
confirmMessage(
|
package/ee/ee-store.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const eeStoreModel = {
|
|
4
|
+
uid: 'strapi::ee-store',
|
|
5
|
+
collectionName: 'strapi_ee_store_settings',
|
|
6
|
+
attributes: {
|
|
7
|
+
key: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
},
|
|
10
|
+
value: {
|
|
11
|
+
type: 'text',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
eeStoreModel,
|
|
18
|
+
};
|
package/ee/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { pick } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const { readLicense, verifyLicense, fetchLicense, LicenseCheckError } = require('./license');
|
|
6
|
+
const { eeStoreModel } = require('./ee-store');
|
|
7
|
+
const { shiftCronExpression } = require('../lib/utils/cron');
|
|
8
|
+
|
|
9
|
+
const ONE_MINUTE = 1000 * 60;
|
|
10
|
+
|
|
11
|
+
const ee = {
|
|
12
|
+
enabled: false,
|
|
13
|
+
licenseInfo: {},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const disable = (message) => {
|
|
17
|
+
ee.logger?.warn(`${message} Switching to CE.`);
|
|
18
|
+
// Only keep the license key for potential re-enabling during a later check
|
|
19
|
+
ee.licenseInfo = pick('licenseKey', ee.licenseInfo);
|
|
20
|
+
ee.enabled = false;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let initialized = false;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Optimistically enable EE if the format of the license is valid, only run once.
|
|
27
|
+
*/
|
|
28
|
+
const init = (licenseDir, logger) => {
|
|
29
|
+
if (initialized) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
initialized = true;
|
|
34
|
+
ee.logger = logger;
|
|
35
|
+
|
|
36
|
+
if (process.env.STRAPI_DISABLE_EE?.toLowerCase() === 'true') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const license = process.env.STRAPI_LICENSE || readLicense(licenseDir);
|
|
42
|
+
|
|
43
|
+
if (license) {
|
|
44
|
+
ee.licenseInfo = verifyLicense(license);
|
|
45
|
+
ee.enabled = true;
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
disable(error.message);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Contact the license registry to update the license to its latest state.
|
|
54
|
+
*
|
|
55
|
+
* Store the result in database to avoid unecessary requests, and will fallback to that in case of a network failure.
|
|
56
|
+
*/
|
|
57
|
+
const onlineUpdate = async ({ strapi }) => {
|
|
58
|
+
const { get, commit, rollback } = await strapi.db.transaction();
|
|
59
|
+
const transaction = get();
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const storedInfo = await strapi.db
|
|
63
|
+
.queryBuilder(eeStoreModel.uid)
|
|
64
|
+
.where({ key: 'ee_information' })
|
|
65
|
+
.select('value')
|
|
66
|
+
.first()
|
|
67
|
+
.transacting(transaction)
|
|
68
|
+
.forUpdate()
|
|
69
|
+
.execute()
|
|
70
|
+
.then((result) => (result ? JSON.parse(result.value) : result));
|
|
71
|
+
|
|
72
|
+
const shouldContactRegistry = (storedInfo?.lastCheckAt ?? 0) < Date.now() - ONE_MINUTE;
|
|
73
|
+
const result = { lastCheckAt: Date.now() };
|
|
74
|
+
|
|
75
|
+
const fallback = (error) => {
|
|
76
|
+
if (error instanceof LicenseCheckError && error.shouldFallback && storedInfo?.license) {
|
|
77
|
+
ee.logger?.warn(
|
|
78
|
+
`${error.message} The last stored one will be used as a potential fallback.`
|
|
79
|
+
);
|
|
80
|
+
return storedInfo.license;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
result.error = error.message;
|
|
84
|
+
disable(error.message);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const license = shouldContactRegistry
|
|
88
|
+
? await fetchLicense(ee.licenseInfo.licenseKey, strapi.config.get('uuid')).catch(fallback)
|
|
89
|
+
: storedInfo.license;
|
|
90
|
+
|
|
91
|
+
if (license) {
|
|
92
|
+
try {
|
|
93
|
+
ee.licenseInfo = verifyLicense(license);
|
|
94
|
+
validateInfo();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
disable(error.message);
|
|
97
|
+
}
|
|
98
|
+
} else if (!shouldContactRegistry) {
|
|
99
|
+
disable(storedInfo.error);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (shouldContactRegistry) {
|
|
103
|
+
result.license = license ?? null;
|
|
104
|
+
const query = strapi.db.queryBuilder(eeStoreModel.uid).transacting(transaction);
|
|
105
|
+
|
|
106
|
+
if (!storedInfo) {
|
|
107
|
+
query.insert({ key: 'ee_information', value: JSON.stringify(result) });
|
|
108
|
+
} else {
|
|
109
|
+
query.update({ value: JSON.stringify(result) }).where({ key: 'ee_information' });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await query.execute();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await commit();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// Example of errors: SQLite does not support FOR UPDATE
|
|
118
|
+
await rollback();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const validateInfo = () => {
|
|
123
|
+
const expirationTime = new Date(ee.licenseInfo.expireAt).getTime();
|
|
124
|
+
|
|
125
|
+
if (expirationTime < new Date().getTime()) {
|
|
126
|
+
return disable('License expired.');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ee.enabled = true;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const checkLicense = async ({ strapi }) => {
|
|
133
|
+
const shouldStayOffline =
|
|
134
|
+
ee.licenseInfo.type === 'gold' &&
|
|
135
|
+
// This env variable support is temporarily used to ease the migration between online vs offline
|
|
136
|
+
process.env.STRAPI_DISABLE_LICENSE_PING?.toLowerCase() === 'true';
|
|
137
|
+
|
|
138
|
+
if (!shouldStayOffline) {
|
|
139
|
+
await onlineUpdate({ strapi });
|
|
140
|
+
strapi.cron.add({ [shiftCronExpression('0 0 */12 * * *')]: onlineUpdate });
|
|
141
|
+
} else {
|
|
142
|
+
if (!ee.licenseInfo.expireAt) {
|
|
143
|
+
return disable('Your license does not have offline support.');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
validateInfo();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const list = () => {
|
|
151
|
+
return (
|
|
152
|
+
ee.licenseInfo.features?.map((feature) =>
|
|
153
|
+
typeof feature === 'object' ? feature : { name: feature }
|
|
154
|
+
) || []
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const get = (featureName) => list().find((feature) => feature.name === featureName);
|
|
159
|
+
|
|
160
|
+
module.exports = Object.freeze({
|
|
161
|
+
init,
|
|
162
|
+
checkLicense,
|
|
163
|
+
|
|
164
|
+
get isEE() {
|
|
165
|
+
return ee.enabled;
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
features: Object.freeze({
|
|
169
|
+
list,
|
|
170
|
+
get,
|
|
171
|
+
isEnabled: (featureName) => get(featureName) !== undefined,
|
|
172
|
+
}),
|
|
173
|
+
});
|
package/ee/license.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { join } = require('path');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const fetch = require('node-fetch');
|
|
7
|
+
|
|
8
|
+
const machineId = require('../lib/utils/machine-id');
|
|
9
|
+
|
|
10
|
+
const DEFAULT_FEATURES = {
|
|
11
|
+
bronze: [],
|
|
12
|
+
silver: [],
|
|
13
|
+
gold: ['sso', { name: 'audit-logs', options: { retentionDays: 90 } }],
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const publicKey = fs.readFileSync(join(__dirname, 'resources/key.pub'));
|
|
17
|
+
|
|
18
|
+
class LicenseCheckError extends Error {
|
|
19
|
+
constructor(message, shouldFallback = false) {
|
|
20
|
+
super(message);
|
|
21
|
+
|
|
22
|
+
this.shouldFallback = shouldFallback;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const readLicense = (directory) => {
|
|
27
|
+
try {
|
|
28
|
+
const path = join(directory, 'license.txt');
|
|
29
|
+
return fs.readFileSync(path).toString();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error.code !== 'ENOENT') {
|
|
32
|
+
throw Error('License file not readable, review its format and access rules.');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const verifyLicense = (license) => {
|
|
38
|
+
const [signature, base64Content] = Buffer.from(license, 'base64').toString().split('\n');
|
|
39
|
+
|
|
40
|
+
if (!signature || !base64Content) {
|
|
41
|
+
throw new Error('Invalid license.');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const stringifiedContent = Buffer.from(base64Content, 'base64').toString();
|
|
45
|
+
|
|
46
|
+
const verify = crypto.createVerify('RSA-SHA256');
|
|
47
|
+
verify.update(stringifiedContent);
|
|
48
|
+
verify.end();
|
|
49
|
+
|
|
50
|
+
const verified = verify.verify(publicKey, signature, 'base64');
|
|
51
|
+
|
|
52
|
+
if (!verified) {
|
|
53
|
+
throw new Error('Invalid license.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const licenseInfo = JSON.parse(stringifiedContent);
|
|
57
|
+
|
|
58
|
+
if (!licenseInfo.features) {
|
|
59
|
+
licenseInfo.features = DEFAULT_FEATURES[licenseInfo.type];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Object.freeze(licenseInfo.features);
|
|
63
|
+
return licenseInfo;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const throwError = () => {
|
|
67
|
+
throw new LicenseCheckError('Could not proceed to the online validation of your license.', true);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const fetchLicense = async (key, projectId) => {
|
|
71
|
+
const response = await fetch(`https://license.strapi.io/api/licenses/validate`, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
headers: { 'Content-Type': 'application/json' },
|
|
74
|
+
body: JSON.stringify({ key, projectId, deviceId: machineId() }),
|
|
75
|
+
}).catch(throwError);
|
|
76
|
+
|
|
77
|
+
const contentType = response.headers.get('Content-Type');
|
|
78
|
+
|
|
79
|
+
if (contentType.includes('application/json')) {
|
|
80
|
+
const { data, error } = await response.json();
|
|
81
|
+
|
|
82
|
+
switch (response.status) {
|
|
83
|
+
case 200:
|
|
84
|
+
return data.license;
|
|
85
|
+
case 400:
|
|
86
|
+
throw new LicenseCheckError(error.message);
|
|
87
|
+
case 404:
|
|
88
|
+
throw new LicenseCheckError('The license used does not exists.');
|
|
89
|
+
default:
|
|
90
|
+
throwError();
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
throwError();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = Object.freeze({
|
|
98
|
+
readLicense,
|
|
99
|
+
verifyLicense,
|
|
100
|
+
fetchLicense,
|
|
101
|
+
LicenseCheckError,
|
|
102
|
+
});
|
|
File without changes
|
package/lib/Strapi.js
CHANGED
|
@@ -17,6 +17,7 @@ const { createServer } = require('./services/server');
|
|
|
17
17
|
const createWebhookRunner = require('./services/webhook-runner');
|
|
18
18
|
const { webhookModel, createWebhookStore } = require('./services/webhook-store');
|
|
19
19
|
const { createCoreStore, coreStoreModel } = require('./services/core-store');
|
|
20
|
+
const { eeStoreModel } = require('../ee/ee-store');
|
|
20
21
|
const createEntityService = require('./services/entity-service');
|
|
21
22
|
const createCronService = require('./services/cron');
|
|
22
23
|
const entityValidator = require('./services/entity-validator');
|
|
@@ -120,16 +121,20 @@ class Strapi {
|
|
|
120
121
|
this.customFields = createCustomFields(this);
|
|
121
122
|
|
|
122
123
|
createUpdateNotifier(this).notify();
|
|
124
|
+
|
|
125
|
+
Object.defineProperty(this, 'EE', {
|
|
126
|
+
get: () => {
|
|
127
|
+
ee.init(this.dirs.app.root, this.log);
|
|
128
|
+
return ee.isEE;
|
|
129
|
+
},
|
|
130
|
+
configurable: false,
|
|
131
|
+
});
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
get config() {
|
|
126
135
|
return this.container.get('config');
|
|
127
136
|
}
|
|
128
137
|
|
|
129
|
-
get EE() {
|
|
130
|
-
return ee({ dir: this.dirs.app.root, logger: this.log });
|
|
131
|
-
}
|
|
132
|
-
|
|
133
138
|
get services() {
|
|
134
139
|
return this.container.get('services').getAll();
|
|
135
140
|
}
|
|
@@ -225,7 +230,7 @@ class Strapi {
|
|
|
225
230
|
|
|
226
231
|
await this.runLifecyclesFunctions(LIFECYCLES.DESTROY);
|
|
227
232
|
|
|
228
|
-
this.eventHub.
|
|
233
|
+
this.eventHub.destroy();
|
|
229
234
|
|
|
230
235
|
if (_.has(this, 'db')) {
|
|
231
236
|
await this.db.destroy();
|
|
@@ -404,6 +409,7 @@ class Strapi {
|
|
|
404
409
|
const contentTypes = [
|
|
405
410
|
coreStoreModel,
|
|
406
411
|
webhookModel,
|
|
412
|
+
eeStoreModel,
|
|
407
413
|
...Object.values(strapi.contentTypes),
|
|
408
414
|
...Object.values(strapi.components),
|
|
409
415
|
];
|
|
@@ -447,6 +453,10 @@ class Strapi {
|
|
|
447
453
|
|
|
448
454
|
await this.db.schema.sync();
|
|
449
455
|
|
|
456
|
+
if (this.EE) {
|
|
457
|
+
await ee.checkLicense({ strapi: this });
|
|
458
|
+
}
|
|
459
|
+
|
|
450
460
|
await this.hook('strapi::content-types.afterSync').call({
|
|
451
461
|
oldContentTypes,
|
|
452
462
|
contentTypes: strapi.contentTypes,
|
|
@@ -30,7 +30,7 @@ module.exports = async ({ buildDestDir, forceBuild = true, optimization, srcDir
|
|
|
30
30
|
// Always remove the .cache and build folders
|
|
31
31
|
await strapiAdmin.clean({ appDir: srcDir, buildDestDir });
|
|
32
32
|
|
|
33
|
-
ee(
|
|
33
|
+
ee.init(srcDir);
|
|
34
34
|
|
|
35
35
|
return strapiAdmin
|
|
36
36
|
.build({
|