@strapi/strapi 4.6.0-beta.2 → 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 +6 -6
- package/bin/strapi.js +80 -55
- 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 +14 -4
- package/lib/commands/builders/admin.js +1 -1
- package/lib/commands/transfer/export.js +12 -8
- package/lib/commands/transfer/import.js +12 -22
- package/lib/commands/transfer/transfer.js +4 -2
- package/lib/commands/transfer/utils.js +59 -10
- package/lib/commands/utils/commander.js +1 -1
- package/lib/core/loaders/plugins/index.js +9 -1
- package/lib/services/entity-service/components.js +39 -36
- package/lib/services/entity-service/index.js +1 -0
- package/lib/services/metrics/index.js +3 -54
- package/lib/services/metrics/sender.js +1 -3
- 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
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
buildTransferTable,
|
|
16
16
|
createStrapiInstance,
|
|
17
17
|
DEFAULT_IGNORED_CONTENT_TYPES,
|
|
18
|
+
formatDiagnostic,
|
|
18
19
|
} = require('./utils');
|
|
19
20
|
|
|
20
21
|
const logger = console;
|
|
@@ -109,6 +110,8 @@ module.exports = async (opts) => {
|
|
|
109
110
|
},
|
|
110
111
|
});
|
|
111
112
|
|
|
113
|
+
engine.diagnostics.onDiagnostic(formatDiagnostic('transfer'));
|
|
114
|
+
|
|
112
115
|
try {
|
|
113
116
|
logger.log(`Starting transfer...`);
|
|
114
117
|
|
|
@@ -120,8 +123,7 @@ module.exports = async (opts) => {
|
|
|
120
123
|
logger.log(`${chalk.bold('Transfer process has been completed successfully!')}`);
|
|
121
124
|
process.exit(0);
|
|
122
125
|
} catch (e) {
|
|
123
|
-
logger.error('Transfer process failed
|
|
124
|
-
logger.error(e);
|
|
126
|
+
logger.error('Transfer process failed.');
|
|
125
127
|
process.exit(1);
|
|
126
128
|
}
|
|
127
129
|
};
|
|
@@ -4,6 +4,11 @@ const chalk = require('chalk');
|
|
|
4
4
|
const Table = require('cli-table3');
|
|
5
5
|
const { Option } = require('commander');
|
|
6
6
|
const { TransferGroupPresets } = require('@strapi/data-transfer/lib/engine');
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
configs: { createOutputFileConfiguration },
|
|
10
|
+
createLogger,
|
|
11
|
+
} = require('@strapi/logger');
|
|
7
12
|
const { readableBytes, exitWith } = require('../utils/helpers');
|
|
8
13
|
const strapi = require('../../index');
|
|
9
14
|
const { getParseListWithChoices } = require('../utils/commander');
|
|
@@ -77,29 +82,34 @@ const DEFAULT_IGNORED_CONTENT_TYPES = [
|
|
|
77
82
|
'admin::role',
|
|
78
83
|
'admin::api-token',
|
|
79
84
|
'admin::api-token-permission',
|
|
85
|
+
'admin::audit-log',
|
|
80
86
|
];
|
|
81
87
|
|
|
82
88
|
const createStrapiInstance = async (logLevel = 'error') => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
try {
|
|
90
|
+
const appContext = await strapi.compile();
|
|
91
|
+
const app = strapi(appContext);
|
|
92
|
+
|
|
93
|
+
app.log.level = logLevel;
|
|
94
|
+
return await app.load();
|
|
95
|
+
} catch (err) {
|
|
96
|
+
if (err.code === 'ECONNREFUSED') {
|
|
97
|
+
throw new Error('Process failed. Check the database connection with your Strapi project.');
|
|
98
|
+
}
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
89
101
|
};
|
|
90
102
|
|
|
91
103
|
const transferDataTypes = Object.keys(TransferGroupPresets);
|
|
92
104
|
|
|
93
105
|
const excludeOption = new Option(
|
|
94
106
|
'--exclude <comma-separated data types>',
|
|
95
|
-
`Exclude
|
|
96
|
-
','
|
|
97
|
-
)}`
|
|
107
|
+
`Exclude data using comma-separated types. Available types: ${transferDataTypes.join(',')}`
|
|
98
108
|
).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "exclude"'));
|
|
99
109
|
|
|
100
110
|
const onlyOption = new Option(
|
|
101
111
|
'--only <command-separated data types>',
|
|
102
|
-
`Include only
|
|
112
|
+
`Include only these types of data (plus schemas). Available types: ${transferDataTypes.join(',')}`
|
|
103
113
|
).argParser(getParseListWithChoices(transferDataTypes, 'Invalid options for "only"'));
|
|
104
114
|
|
|
105
115
|
const validateExcludeOnly = (command) => {
|
|
@@ -121,6 +131,44 @@ const validateExcludeOnly = (command) => {
|
|
|
121
131
|
}
|
|
122
132
|
};
|
|
123
133
|
|
|
134
|
+
const errorColors = {
|
|
135
|
+
fatal: chalk.red,
|
|
136
|
+
error: chalk.red,
|
|
137
|
+
silly: chalk.yellow,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const formatDiagnostic =
|
|
141
|
+
(operation) =>
|
|
142
|
+
({ details, kind }) => {
|
|
143
|
+
const logger = createLogger(
|
|
144
|
+
createOutputFileConfiguration(`${operation}_error_log_${Date.now()}.log`)
|
|
145
|
+
);
|
|
146
|
+
try {
|
|
147
|
+
if (kind === 'error') {
|
|
148
|
+
const { message, severity = 'fatal' } = details;
|
|
149
|
+
|
|
150
|
+
const colorizeError = errorColors[severity];
|
|
151
|
+
const errorMessage = colorizeError(`[${severity.toUpperCase()}] ${message}`);
|
|
152
|
+
|
|
153
|
+
logger.error(errorMessage);
|
|
154
|
+
}
|
|
155
|
+
if (kind === 'info') {
|
|
156
|
+
const { message, params } = details;
|
|
157
|
+
|
|
158
|
+
const msg = `${message}\n${params ? JSON.stringify(params, null, 2) : ''}`;
|
|
159
|
+
|
|
160
|
+
logger.info(msg);
|
|
161
|
+
}
|
|
162
|
+
if (kind === 'warning') {
|
|
163
|
+
const { origin, message } = details;
|
|
164
|
+
|
|
165
|
+
logger.warn(`(${origin ?? 'transfer'}) ${message}`);
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
logger.error(err);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
124
172
|
module.exports = {
|
|
125
173
|
buildTransferTable,
|
|
126
174
|
getDefaultExportName,
|
|
@@ -129,4 +177,5 @@ module.exports = {
|
|
|
129
177
|
excludeOption,
|
|
130
178
|
onlyOption,
|
|
131
179
|
validateExcludeOnly,
|
|
180
|
+
formatDiagnostic,
|
|
132
181
|
};
|
|
@@ -85,7 +85,15 @@ const loadPlugins = async (strapi) => {
|
|
|
85
85
|
for (const pluginName of Object.keys(enabledPlugins)) {
|
|
86
86
|
const enabledPlugin = enabledPlugins[pluginName];
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
let serverEntrypointPath;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
serverEntrypointPath = join(enabledPlugin.pathToPlugin, 'strapi-server.js');
|
|
92
|
+
} catch (e) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Error loading the plugin ${pluginName} because ${pluginName} is not installed. Please either install the plugin or remove it's configuration.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
89
97
|
|
|
90
98
|
// only load plugins with a server entrypoint
|
|
91
99
|
if (!(await fse.pathExists(serverEntrypointPath))) {
|
|
@@ -43,9 +43,10 @@ const createComponents = async (uid, data) => {
|
|
|
43
43
|
throw new Error('Expected an array to create repeatable component');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const components =
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
const components = [];
|
|
47
|
+
for (const value of componentValue) {
|
|
48
|
+
components.push(await createComponent(componentUID, value));
|
|
49
|
+
}
|
|
49
50
|
|
|
50
51
|
componentBody[attributeName] = components.map(({ id }) => {
|
|
51
52
|
return {
|
|
@@ -77,18 +78,19 @@ const createComponents = async (uid, data) => {
|
|
|
77
78
|
throw new Error('Expected an array to create repeatable component');
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
const dynamicZoneData = [];
|
|
82
|
+
for (const value of dynamiczoneValues) {
|
|
83
|
+
const { id } = await createComponent(value.__component, value);
|
|
84
|
+
dynamicZoneData.push({
|
|
85
|
+
id,
|
|
86
|
+
__component: value.__component,
|
|
87
|
+
__pivot: {
|
|
88
|
+
field: attributeName,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
componentBody[attributeName] = dynamicZoneData;
|
|
92
94
|
|
|
93
95
|
continue;
|
|
94
96
|
}
|
|
@@ -137,9 +139,10 @@ const updateComponents = async (uid, entityToUpdate, data) => {
|
|
|
137
139
|
throw new Error('Expected an array to create repeatable component');
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
const components =
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
const components = [];
|
|
143
|
+
for (const value of componentValue) {
|
|
144
|
+
components.push(await updateOrCreateComponent(componentUID, value));
|
|
145
|
+
}
|
|
143
146
|
|
|
144
147
|
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
|
|
145
148
|
return {
|
|
@@ -173,19 +176,19 @@ const updateComponents = async (uid, entityToUpdate, data) => {
|
|
|
173
176
|
throw new Error('Expected an array to create repeatable component');
|
|
174
177
|
}
|
|
175
178
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
const dynamicZoneData = [];
|
|
180
|
+
for (const value of dynamiczoneValues) {
|
|
181
|
+
const { id } = await updateOrCreateComponent(value.__component, value);
|
|
182
|
+
dynamicZoneData.push({
|
|
183
|
+
id,
|
|
184
|
+
__component: value.__component,
|
|
185
|
+
__pivot: {
|
|
186
|
+
field: attributeName,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
}
|
|
179
190
|
|
|
180
|
-
|
|
181
|
-
id,
|
|
182
|
-
__component: value.__component,
|
|
183
|
-
__pivot: {
|
|
184
|
-
field: attributeName,
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
})
|
|
188
|
-
);
|
|
191
|
+
componentBody[attributeName] = dynamicZoneData;
|
|
189
192
|
|
|
190
193
|
continue;
|
|
191
194
|
}
|
|
@@ -287,14 +290,14 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
|
|
|
287
290
|
|
|
288
291
|
if (attribute.type === 'component') {
|
|
289
292
|
const { component: componentUID } = attribute;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
+
for (const subValue of _.castArray(value)) {
|
|
294
|
+
await deleteComponent(componentUID, subValue);
|
|
295
|
+
}
|
|
293
296
|
} else {
|
|
294
297
|
// delete dynamic zone components
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
+
for (const subValue of _.castArray(value)) {
|
|
299
|
+
await deleteComponent(subValue.__component, subValue);
|
|
300
|
+
}
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
continue;
|
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
* You can learn more at https://docs.strapi.io/developer-docs/latest/getting-started/usage-information.html
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const crypto = require('crypto');
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
8
|
const { scheduleJob } = require('node-schedule');
|
|
12
9
|
|
|
13
|
-
const ee = require('../../utils/ee');
|
|
14
10
|
const wrapWithRateLimit = require('./rate-limiter');
|
|
15
11
|
const createSender = require('./sender');
|
|
16
12
|
const createMiddleware = require('./middleware');
|
|
@@ -46,41 +42,14 @@ const createTelemetryInstance = (strapi) => {
|
|
|
46
42
|
strapi.server.use(createMiddleware({ sendEvent }));
|
|
47
43
|
}
|
|
48
44
|
},
|
|
49
|
-
bootstrap() {
|
|
50
|
-
if (strapi.EE === true && ee.isEE === true) {
|
|
51
|
-
const pingDisabled =
|
|
52
|
-
isTruthy(process.env.STRAPI_LICENSE_PING_DISABLED) && ee.licenseInfo.type === 'gold';
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
return sendEvent(
|
|
56
|
-
'didCheckLicense',
|
|
57
|
-
{
|
|
58
|
-
groupProperties: {
|
|
59
|
-
licenseInfo: {
|
|
60
|
-
...ee.licenseInfo,
|
|
61
|
-
projectHash: hashProject(strapi),
|
|
62
|
-
dependencyHash: hashDep(strapi),
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
headers: { 'x-strapi-project': 'enterprise' },
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
};
|
|
46
|
+
bootstrap() {},
|
|
71
47
|
|
|
72
|
-
if (!pingDisabled) {
|
|
73
|
-
const licenseCron = scheduleJob('0 0 0 * * 7', () => sendLicenseCheck());
|
|
74
|
-
crons.push(licenseCron);
|
|
75
|
-
|
|
76
|
-
sendLicenseCheck();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
48
|
destroy() {
|
|
81
|
-
//
|
|
49
|
+
// Clear open handles
|
|
82
50
|
crons.forEach((cron) => cron.cancel());
|
|
83
51
|
},
|
|
52
|
+
|
|
84
53
|
async send(event, payload) {
|
|
85
54
|
if (isDisabled) return true;
|
|
86
55
|
return sendEvent(event, payload);
|
|
@@ -88,24 +57,4 @@ const createTelemetryInstance = (strapi) => {
|
|
|
88
57
|
};
|
|
89
58
|
};
|
|
90
59
|
|
|
91
|
-
const hash = (str) => crypto.createHash('sha256').update(str).digest('hex');
|
|
92
|
-
|
|
93
|
-
const hashProject = (strapi) =>
|
|
94
|
-
hash(`${strapi.config.get('info.name')}${strapi.config.get('info.description')}`);
|
|
95
|
-
|
|
96
|
-
const hashDep = (strapi) => {
|
|
97
|
-
const depStr = JSON.stringify(strapi.config.info.dependencies);
|
|
98
|
-
const readmePath = path.join(strapi.dirs.app.root, 'README.md');
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
if (fs.existsSync(readmePath)) {
|
|
102
|
-
return hash(`${depStr}${fs.readFileSync(readmePath)}`);
|
|
103
|
-
}
|
|
104
|
-
} catch (err) {
|
|
105
|
-
return hash(`${depStr}`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return hash(`${depStr}`);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
60
|
module.exports = createTelemetryInstance;
|
|
@@ -8,7 +8,6 @@ const fetch = require('node-fetch');
|
|
|
8
8
|
const ciEnv = require('ci-info');
|
|
9
9
|
const { isUsingTypeScriptSync } = require('@strapi/typescript-utils');
|
|
10
10
|
const { env } = require('@strapi/utils');
|
|
11
|
-
const ee = require('../../utils/ee');
|
|
12
11
|
const machineID = require('../../utils/machine-id');
|
|
13
12
|
const { generateAdminUserHash } = require('./admin-user-hash');
|
|
14
13
|
|
|
@@ -37,7 +36,6 @@ const addPackageJsonStrapiMetadata = (metadata, strapi) => {
|
|
|
37
36
|
module.exports = (strapi) => {
|
|
38
37
|
const { uuid } = strapi.config;
|
|
39
38
|
const deviceId = machineID();
|
|
40
|
-
const isEE = strapi.EE === true && ee.isEE === true;
|
|
41
39
|
|
|
42
40
|
const serverRootPath = strapi.dirs.app.root;
|
|
43
41
|
const adminRootPath = path.join(strapi.dirs.app.root, 'src', 'admin');
|
|
@@ -55,7 +53,6 @@ module.exports = (strapi) => {
|
|
|
55
53
|
docker: process.env.DOCKER || isDocker(),
|
|
56
54
|
isCI: ciEnv.isCI,
|
|
57
55
|
version: strapi.config.get('info.strapi'),
|
|
58
|
-
projectType: isEE ? 'Enterprise' : 'Community',
|
|
59
56
|
useTypescriptOnServer: isUsingTypeScriptSync(serverRootPath),
|
|
60
57
|
useTypescriptOnAdmin: isUsingTypeScriptSync(adminRootPath),
|
|
61
58
|
projectId: uuid,
|
|
@@ -77,6 +74,7 @@ module.exports = (strapi) => {
|
|
|
77
74
|
userProperties: userId ? { ...anonymousUserProperties, ...payload.userProperties } : {},
|
|
78
75
|
groupProperties: {
|
|
79
76
|
...anonymousGroupProperties,
|
|
77
|
+
projectType: strapi.EE ? 'Enterprise' : 'Community',
|
|
80
78
|
...payload.groupProperties,
|
|
81
79
|
},
|
|
82
80
|
}),
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isEmpty, negate } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const INTEGER_REGEX = /^\d+$/;
|
|
6
|
+
const STEP_REGEX = /^\*\/\d+$/;
|
|
7
|
+
const COMPONENTS = [
|
|
8
|
+
{ limit: 60, zeroBasedIndices: true, functionName: 'getSeconds' },
|
|
9
|
+
{ limit: 60, zeroBasedIndices: true, functionName: 'getMinutes' },
|
|
10
|
+
{ limit: 24, zeroBasedIndices: true, functionName: 'getHours' },
|
|
11
|
+
{ limit: 31, zeroBasedIndices: false, functionName: 'getDate' },
|
|
12
|
+
{ limit: 12, zeroBasedIndices: false, functionName: 'getMonth' },
|
|
13
|
+
{ limit: 7, zeroBasedIndices: true, functionName: 'getDay' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const shift = (component, index, date) => {
|
|
17
|
+
if (component === '*') {
|
|
18
|
+
return '*';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { limit, zeroBasedIndices, functionName } = COMPONENTS[index];
|
|
22
|
+
const offset = +!zeroBasedIndices;
|
|
23
|
+
const currentValue = date[functionName]();
|
|
24
|
+
|
|
25
|
+
if (INTEGER_REGEX.test(component)) {
|
|
26
|
+
return ((Number.parseInt(component, 10) + currentValue) % limit) + offset;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (STEP_REGEX.test(component)) {
|
|
30
|
+
const [, step] = component.split('/');
|
|
31
|
+
const frequency = Math.floor(limit / step);
|
|
32
|
+
const list = Array.from({ length: frequency }, (_, index) => index * step);
|
|
33
|
+
return list.map((value) => ((value + currentValue) % limit) + offset).sort((a, b) => a - b);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Unsupported syntax
|
|
37
|
+
return component;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Simulate an interval by shifting a cron expression using the specified date.
|
|
42
|
+
* @param {string} rule A cron expression you want to shift.
|
|
43
|
+
* @param {Date} date The date that's gonna be used as the start of the "interval", it defaults to now.
|
|
44
|
+
* @returns The shifted cron expression.
|
|
45
|
+
*/
|
|
46
|
+
const shiftCronExpression = (rule, date = new Date()) => {
|
|
47
|
+
const components = rule.trim().split(' ').filter(negate(isEmpty));
|
|
48
|
+
const secondsIncluded = components.length === 6;
|
|
49
|
+
return components
|
|
50
|
+
.map((component, index) => shift(component, secondsIncluded ? index : index + 1, date))
|
|
51
|
+
.join(' ');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
shiftCronExpression,
|
|
56
|
+
};
|
package/lib/utils/ee.js
CHANGED
|
@@ -1,123 +1,3 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const crypto = require('crypto');
|
|
6
|
-
const _ = require('lodash');
|
|
7
|
-
|
|
8
|
-
const publicKey = fs.readFileSync(path.join(__dirname, '../utils/resources/key.pub'));
|
|
9
|
-
|
|
10
|
-
const noop = () => {};
|
|
11
|
-
|
|
12
|
-
const noLog = {
|
|
13
|
-
warn: noop,
|
|
14
|
-
info: noop,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const internals = {};
|
|
18
|
-
const features = {
|
|
19
|
-
bronze: [],
|
|
20
|
-
silver: [],
|
|
21
|
-
gold: ['sso', 'audit-logs'],
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
module.exports = ({ dir, logger = noLog }) => {
|
|
25
|
-
if (_.has(internals, 'isEE')) return internals.isEE;
|
|
26
|
-
|
|
27
|
-
const warnAndReturn = (msg = 'Invalid license. Starting in CE.') => {
|
|
28
|
-
logger.warn(msg);
|
|
29
|
-
internals.isEE = false;
|
|
30
|
-
return false;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
if (process.env.STRAPI_DISABLE_EE === 'true') {
|
|
34
|
-
internals.isEE = false;
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const licensePath = path.join(dir, 'license.txt');
|
|
39
|
-
|
|
40
|
-
let license;
|
|
41
|
-
if (_.has(process.env, 'STRAPI_LICENSE')) {
|
|
42
|
-
license = process.env.STRAPI_LICENSE;
|
|
43
|
-
} else if (fs.existsSync(licensePath)) {
|
|
44
|
-
license = fs.readFileSync(licensePath).toString();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (_.isNil(license)) {
|
|
48
|
-
internals.isEE = false;
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const plainLicense = Buffer.from(license, 'base64').toString();
|
|
54
|
-
const [signatureb64, contentb64] = plainLicense.split('\n');
|
|
55
|
-
|
|
56
|
-
const signature = Buffer.from(signatureb64, 'base64');
|
|
57
|
-
const content = Buffer.from(contentb64, 'base64').toString();
|
|
58
|
-
|
|
59
|
-
const verifier = crypto.createVerify('RSA-SHA256');
|
|
60
|
-
verifier.update(content);
|
|
61
|
-
verifier.end();
|
|
62
|
-
|
|
63
|
-
const isValid = verifier.verify(publicKey, signature);
|
|
64
|
-
if (!isValid) return warnAndReturn();
|
|
65
|
-
|
|
66
|
-
internals.licenseInfo = JSON.parse(content);
|
|
67
|
-
|
|
68
|
-
const expirationTime = new Date(internals.licenseInfo.expireAt).getTime();
|
|
69
|
-
if (expirationTime < new Date().getTime()) {
|
|
70
|
-
return warnAndReturn('License expired. Starting in CE');
|
|
71
|
-
}
|
|
72
|
-
} catch (err) {
|
|
73
|
-
return warnAndReturn();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
internals.isEE = true;
|
|
77
|
-
return true;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
Object.defineProperty(module.exports, 'licenseInfo', {
|
|
81
|
-
get() {
|
|
82
|
-
mustHaveKey('licenseInfo');
|
|
83
|
-
return internals.licenseInfo;
|
|
84
|
-
},
|
|
85
|
-
configurable: false,
|
|
86
|
-
enumerable: false,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
Object.defineProperty(module.exports, 'isEE', {
|
|
90
|
-
get() {
|
|
91
|
-
mustHaveKey('isEE');
|
|
92
|
-
return internals.isEE;
|
|
93
|
-
},
|
|
94
|
-
configurable: false,
|
|
95
|
-
enumerable: false,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
Object.defineProperty(module.exports, 'features', {
|
|
99
|
-
get() {
|
|
100
|
-
mustHaveKey('licenseInfo');
|
|
101
|
-
|
|
102
|
-
const { type: licenseType } = module.exports.licenseInfo;
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
isEnabled(feature) {
|
|
106
|
-
return features[licenseType].includes(feature);
|
|
107
|
-
},
|
|
108
|
-
getEnabled() {
|
|
109
|
-
return features[licenseType];
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
},
|
|
113
|
-
configurable: false,
|
|
114
|
-
enumerable: false,
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const mustHaveKey = (key) => {
|
|
118
|
-
if (!_.has(internals, key)) {
|
|
119
|
-
const err = new Error('Tampering with license');
|
|
120
|
-
// err.stack = null;
|
|
121
|
-
throw err;
|
|
122
|
-
}
|
|
123
|
-
};
|
|
3
|
+
module.exports = require('../../ee');
|
|
@@ -4,7 +4,6 @@ const chalk = require('chalk');
|
|
|
4
4
|
const CLITable = require('cli-table3');
|
|
5
5
|
const _ = require('lodash/fp');
|
|
6
6
|
const { getAbsoluteAdminUrl, getAbsoluteServerUrl } = require('@strapi/utils');
|
|
7
|
-
const ee = require('./ee');
|
|
8
7
|
|
|
9
8
|
module.exports = (app) => {
|
|
10
9
|
return {
|
|
@@ -19,15 +18,14 @@ module.exports = (app) => {
|
|
|
19
18
|
chars: { mid: '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' },
|
|
20
19
|
});
|
|
21
20
|
|
|
22
|
-
const isEE = app.EE === true && ee.isEE === true;
|
|
23
|
-
|
|
24
21
|
infoTable.push(
|
|
25
22
|
[chalk.blue('Time'), `${new Date()}`],
|
|
26
23
|
[chalk.blue('Launched in'), `${Date.now() - app.config.launchedAt} ms`],
|
|
27
24
|
[chalk.blue('Environment'), app.config.environment],
|
|
28
25
|
[chalk.blue('Process PID'), process.pid],
|
|
29
26
|
[chalk.blue('Version'), `${app.config.info.strapi} (node ${process.version})`],
|
|
30
|
-
[chalk.blue('Edition'),
|
|
27
|
+
[chalk.blue('Edition'), app.EE ? 'Enterprise' : 'Community'],
|
|
28
|
+
[chalk.blue('Database'), app.db.dialect.client]
|
|
31
29
|
);
|
|
32
30
|
|
|
33
31
|
console.log(infoTable.toString());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/strapi",
|
|
3
|
-
"version": "4.6.0
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
},
|
|
72
72
|
"directories": {
|
|
73
73
|
"lib": "./lib",
|
|
74
|
-
"bin": "./bin"
|
|
74
|
+
"bin": "./bin",
|
|
75
|
+
"ee": "./ee"
|
|
75
76
|
},
|
|
76
77
|
"scripts": {
|
|
77
78
|
"postinstall": "node lib/utils/success.js",
|
|
@@ -80,26 +81,26 @@
|
|
|
80
81
|
"dependencies": {
|
|
81
82
|
"@koa/cors": "3.4.3",
|
|
82
83
|
"@koa/router": "10.1.1",
|
|
83
|
-
"@strapi/admin": "4.6.0
|
|
84
|
-
"@strapi/data-transfer": "4.6.0
|
|
85
|
-
"@strapi/database": "4.6.0
|
|
86
|
-
"@strapi/generate-new": "4.6.0
|
|
87
|
-
"@strapi/generators": "4.6.0
|
|
88
|
-
"@strapi/logger": "4.6.0
|
|
89
|
-
"@strapi/permissions": "4.6.0
|
|
90
|
-
"@strapi/plugin-content-manager": "4.6.0
|
|
91
|
-
"@strapi/plugin-content-type-builder": "4.6.0
|
|
92
|
-
"@strapi/plugin-email": "4.6.0
|
|
93
|
-
"@strapi/plugin-upload": "4.6.0
|
|
94
|
-
"@strapi/typescript-utils": "4.6.0
|
|
95
|
-
"@strapi/utils": "4.6.0
|
|
84
|
+
"@strapi/admin": "4.6.0",
|
|
85
|
+
"@strapi/data-transfer": "4.6.0",
|
|
86
|
+
"@strapi/database": "4.6.0",
|
|
87
|
+
"@strapi/generate-new": "4.6.0",
|
|
88
|
+
"@strapi/generators": "4.6.0",
|
|
89
|
+
"@strapi/logger": "4.6.0",
|
|
90
|
+
"@strapi/permissions": "4.6.0",
|
|
91
|
+
"@strapi/plugin-content-manager": "4.6.0",
|
|
92
|
+
"@strapi/plugin-content-type-builder": "4.6.0",
|
|
93
|
+
"@strapi/plugin-email": "4.6.0",
|
|
94
|
+
"@strapi/plugin-upload": "4.6.0",
|
|
95
|
+
"@strapi/typescript-utils": "4.6.0",
|
|
96
|
+
"@strapi/utils": "4.6.0",
|
|
96
97
|
"bcryptjs": "2.4.3",
|
|
97
98
|
"boxen": "5.1.2",
|
|
98
99
|
"chalk": "4.1.2",
|
|
99
100
|
"chokidar": "3.5.2",
|
|
100
101
|
"ci-info": "3.5.0",
|
|
101
102
|
"cli-table3": "0.6.2",
|
|
102
|
-
"commander": "8.
|
|
103
|
+
"commander": "8.3.0",
|
|
103
104
|
"configstore": "5.0.1",
|
|
104
105
|
"debug": "4.3.4",
|
|
105
106
|
"delegates": "1.0.0",
|
|
@@ -141,5 +142,5 @@
|
|
|
141
142
|
"node": ">=14.19.1 <=18.x.x",
|
|
142
143
|
"npm": ">=6.0.0"
|
|
143
144
|
},
|
|
144
|
-
"gitHead": "
|
|
145
|
+
"gitHead": "a9e55435c489f3379d88565bf3f729deb29bfb45"
|
|
145
146
|
}
|