@akemona-org/strapi 3.7.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/LICENSE +22 -0
- package/README.md +163 -0
- package/bin/strapi.js +239 -0
- package/index.d.ts +13 -0
- package/lib/Strapi.js +498 -0
- package/lib/commands/admin-reset.js +51 -0
- package/lib/commands/build.js +47 -0
- package/lib/commands/configurationDump.js +50 -0
- package/lib/commands/configurationRestore.js +160 -0
- package/lib/commands/console.js +26 -0
- package/lib/commands/develop.js +155 -0
- package/lib/commands/generate-template.js +97 -0
- package/lib/commands/generate.js +66 -0
- package/lib/commands/install.js +48 -0
- package/lib/commands/new.js +11 -0
- package/lib/commands/start.js +8 -0
- package/lib/commands/uninstall.js +68 -0
- package/lib/commands/watchAdmin.js +35 -0
- package/lib/core/app-configuration/config-loader.js +56 -0
- package/lib/core/app-configuration/config-provider.js +28 -0
- package/lib/core/app-configuration/index.js +99 -0
- package/lib/core/bootstrap.js +166 -0
- package/lib/core/fs.js +52 -0
- package/lib/core/index.js +21 -0
- package/lib/core/load-admin.js +36 -0
- package/lib/core/load-apis.js +22 -0
- package/lib/core/load-components.js +43 -0
- package/lib/core/load-extensions.js +71 -0
- package/lib/core/load-functions.js +21 -0
- package/lib/core/load-hooks.js +117 -0
- package/lib/core/load-middlewares.js +130 -0
- package/lib/core/load-modules.js +61 -0
- package/lib/core/load-plugins.js +68 -0
- package/lib/core/load-policies.js +36 -0
- package/lib/core/walk.js +27 -0
- package/lib/core-api/controller.js +158 -0
- package/lib/core-api/index.js +33 -0
- package/lib/core-api/service/collection-type.js +122 -0
- package/lib/core-api/service/index.js +81 -0
- package/lib/core-api/service/single-type.js +68 -0
- package/lib/hooks/index.js +97 -0
- package/lib/index.js +3 -0
- package/lib/load/check-reserved-filename.js +18 -0
- package/lib/load/filepath-to-prop-path.js +22 -0
- package/lib/load/glob.js +15 -0
- package/lib/load/index.js +9 -0
- package/lib/load/load-config-files.js +22 -0
- package/lib/load/load-files.js +56 -0
- package/lib/load/package-path.js +9 -0
- package/lib/load/require-file-parse.js +15 -0
- package/lib/middlewares/boom/defaults.json +5 -0
- package/lib/middlewares/boom/index.js +147 -0
- package/lib/middlewares/cors/index.js +66 -0
- package/lib/middlewares/cron/defaults.json +5 -0
- package/lib/middlewares/cron/index.js +43 -0
- package/lib/middlewares/csp/defaults.json +5 -0
- package/lib/middlewares/csp/index.js +26 -0
- package/lib/middlewares/favicon/defaults.json +7 -0
- package/lib/middlewares/favicon/index.js +35 -0
- package/lib/middlewares/gzip/defaults.json +6 -0
- package/lib/middlewares/gzip/index.js +19 -0
- package/lib/middlewares/hsts/defaults.json +7 -0
- package/lib/middlewares/hsts/index.js +30 -0
- package/lib/middlewares/index.js +120 -0
- package/lib/middlewares/ip/defaults.json +7 -0
- package/lib/middlewares/ip/index.js +25 -0
- package/lib/middlewares/language/defaults.json +9 -0
- package/lib/middlewares/language/index.js +40 -0
- package/lib/middlewares/logger/defaults.json +8 -0
- package/lib/middlewares/logger/index.js +63 -0
- package/lib/middlewares/p3p/defaults.json +6 -0
- package/lib/middlewares/p3p/index.js +29 -0
- package/lib/middlewares/parser/defaults.json +10 -0
- package/lib/middlewares/parser/index.js +71 -0
- package/lib/middlewares/poweredBy/defaults.json +5 -0
- package/lib/middlewares/poweredBy/index.js +16 -0
- package/lib/middlewares/public/assets/images/group_people_1.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_2.png +0 -0
- package/lib/middlewares/public/assets/images/group_people_3.png +0 -0
- package/lib/middlewares/public/assets/images/logo_login.png +0 -0
- package/lib/middlewares/public/defaults.json +8 -0
- package/lib/middlewares/public/index.html +66 -0
- package/lib/middlewares/public/index.js +98 -0
- package/lib/middlewares/public/serve-static.js +23 -0
- package/lib/middlewares/responseTime/defaults.json +5 -0
- package/lib/middlewares/responseTime/index.js +25 -0
- package/lib/middlewares/responses/defaults.json +5 -0
- package/lib/middlewares/responses/index.js +18 -0
- package/lib/middlewares/router/defaults.json +7 -0
- package/lib/middlewares/router/index.js +64 -0
- package/lib/middlewares/router/utils/composeEndpoint.js +25 -0
- package/lib/middlewares/router/utils/routerChecker.js +92 -0
- package/lib/middlewares/session/defaults.json +18 -0
- package/lib/middlewares/session/index.js +140 -0
- package/lib/middlewares/xframe/defaults.json +6 -0
- package/lib/middlewares/xframe/index.js +33 -0
- package/lib/middlewares/xss/defaults.json +6 -0
- package/lib/middlewares/xss/index.js +30 -0
- package/lib/services/core-store.js +144 -0
- package/lib/services/entity-service.js +260 -0
- package/lib/services/entity-validator/index.js +199 -0
- package/lib/services/entity-validator/validators.js +125 -0
- package/lib/services/event-hub.js +15 -0
- package/lib/services/metrics/index.js +103 -0
- package/lib/services/metrics/is-truthy.js +9 -0
- package/lib/services/metrics/middleware.js +33 -0
- package/lib/services/metrics/rate-limiter.js +27 -0
- package/lib/services/metrics/sender.js +76 -0
- package/lib/services/metrics/stringify-deep.js +22 -0
- package/lib/services/utils/upload-files.js +70 -0
- package/lib/services/webhook-runner.js +159 -0
- package/lib/services/webhook-store.js +97 -0
- package/lib/services/worker-queue.js +58 -0
- package/lib/utils/addSlash.js +10 -0
- package/lib/utils/ee.js +123 -0
- package/lib/utils/get-prefixed-dependencies.js +7 -0
- package/lib/utils/index.js +25 -0
- package/lib/utils/openBrowser.js +145 -0
- package/lib/utils/resources/key.pub +9 -0
- package/lib/utils/resources/openChrome.applescript +83 -0
- package/lib/utils/run-checks.js +37 -0
- package/lib/utils/success.js +31 -0
- package/lib/utils/update-notifier/index.js +96 -0
- package/lib/utils/url-from-segments.js +13 -0
- package/package.json +143 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhook store is the implementation of webhook storage over the core_store
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const webhookModel = config => ({
|
|
7
|
+
connection: config.get('database.defaultConnection'),
|
|
8
|
+
uid: 'strapi::webhooks',
|
|
9
|
+
globalId: 'StrapiWebhooks',
|
|
10
|
+
collectionName: 'strapi_webhooks',
|
|
11
|
+
info: {
|
|
12
|
+
name: 'Strapi webhooks',
|
|
13
|
+
description: '',
|
|
14
|
+
},
|
|
15
|
+
pluginOptions: {
|
|
16
|
+
'content-manager': {
|
|
17
|
+
visible: false,
|
|
18
|
+
},
|
|
19
|
+
'content-type-builder': {
|
|
20
|
+
visible: false,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
attributes: {
|
|
24
|
+
name: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
},
|
|
27
|
+
url: {
|
|
28
|
+
type: 'text',
|
|
29
|
+
},
|
|
30
|
+
headers: {
|
|
31
|
+
type: 'json',
|
|
32
|
+
},
|
|
33
|
+
events: {
|
|
34
|
+
type: 'json',
|
|
35
|
+
},
|
|
36
|
+
enabled: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const toDBObject = data => {
|
|
43
|
+
return {
|
|
44
|
+
name: data.name,
|
|
45
|
+
url: data.url,
|
|
46
|
+
headers: data.headers,
|
|
47
|
+
events: data.events,
|
|
48
|
+
enabled: data.isEnabled,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const fromDBObject = row => {
|
|
53
|
+
return {
|
|
54
|
+
id: row.id,
|
|
55
|
+
name: row.name,
|
|
56
|
+
url: row.url,
|
|
57
|
+
headers: row.headers,
|
|
58
|
+
events: row.events,
|
|
59
|
+
isEnabled: row.enabled,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const createWebhookStore = ({ db }) => {
|
|
64
|
+
const webhookQueries = db.query('strapi_webhooks');
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
async findWebhooks() {
|
|
68
|
+
const results = await webhookQueries.find();
|
|
69
|
+
|
|
70
|
+
return results.map(fromDBObject);
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
async findWebhook(id) {
|
|
74
|
+
const result = await webhookQueries.findOne({ id });
|
|
75
|
+
return result ? fromDBObject(result) : null;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
createWebhook(data) {
|
|
79
|
+
return webhookQueries.create(toDBObject({ ...data, isEnabled: true })).then(fromDBObject);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
async updateWebhook(id, data) {
|
|
83
|
+
const webhook = await webhookQueries.update({ id }, toDBObject(data));
|
|
84
|
+
return webhook ? fromDBObject(webhook) : null;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async deleteWebhook(id) {
|
|
88
|
+
const webhook = await webhookQueries.delete({ id });
|
|
89
|
+
return webhook ? fromDBObject(webhook) : null;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
webhookModel,
|
|
96
|
+
createWebhookStore,
|
|
97
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple worker queue in memory
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const debug = require('debug')('strapi:worker-queue');
|
|
7
|
+
|
|
8
|
+
module.exports = class WorkerQueue {
|
|
9
|
+
constructor({ logger, concurrency = 5 } = {}) {
|
|
10
|
+
debug('Initialize worker queue');
|
|
11
|
+
|
|
12
|
+
this.logger = logger;
|
|
13
|
+
this.worker = noop;
|
|
14
|
+
|
|
15
|
+
this.concurrency = concurrency;
|
|
16
|
+
this.running = 0;
|
|
17
|
+
this.queue = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
subscribe(worker) {
|
|
21
|
+
debug('Subscribe to worker queue');
|
|
22
|
+
this.worker = worker;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enqueue(payload) {
|
|
26
|
+
debug('Enqueue event in worker queue');
|
|
27
|
+
if (this.running < this.concurrency) {
|
|
28
|
+
this.running++;
|
|
29
|
+
this.execute(payload);
|
|
30
|
+
} else {
|
|
31
|
+
this.queue.unshift(payload);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pop() {
|
|
36
|
+
debug('Pop worker queue and execute');
|
|
37
|
+
const payload = this.queue.pop();
|
|
38
|
+
|
|
39
|
+
if (payload) {
|
|
40
|
+
this.execute(payload);
|
|
41
|
+
} else {
|
|
42
|
+
this.running--;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async execute(payload) {
|
|
47
|
+
debug('Execute worker');
|
|
48
|
+
try {
|
|
49
|
+
await this.worker(payload);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
this.logger.error(error);
|
|
52
|
+
} finally {
|
|
53
|
+
this.pop();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
function noop() {}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = path => {
|
|
4
|
+
if (typeof path !== 'string') throw new Error('admin.url must be a string');
|
|
5
|
+
if (path === '' || path === '/') return '/';
|
|
6
|
+
|
|
7
|
+
if (path[0] != '/') path = '/' + path;
|
|
8
|
+
if (path[path.length - 1] != '/') path = path + '/';
|
|
9
|
+
return path;
|
|
10
|
+
};
|
package/lib/utils/ee.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
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'],
|
|
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
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Dependencies.
|
|
4
|
+
const { isEmpty } = require('lodash');
|
|
5
|
+
const openBrowser = require('./openBrowser');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
/*
|
|
9
|
+
* Return false where there is no administrator, otherwise return true.
|
|
10
|
+
*/
|
|
11
|
+
async isInitialised(strapi) {
|
|
12
|
+
try {
|
|
13
|
+
if (isEmpty(strapi.admin)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const numberOfAdministrators = await strapi.query('user', 'admin').find({ _limit: 1 });
|
|
18
|
+
|
|
19
|
+
return numberOfAdministrators.length > 0;
|
|
20
|
+
} catch (err) {
|
|
21
|
+
strapi.stopWithError(err);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
openBrowser,
|
|
25
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
var execSync = require('child_process').execSync;
|
|
11
|
+
var chalk = require('chalk');
|
|
12
|
+
var spawn = require('cross-spawn');
|
|
13
|
+
var opn = require('opn');
|
|
14
|
+
const fetch = require('node-fetch');
|
|
15
|
+
const { getAbsoluteAdminUrl } = require('@akemona-org/strapi-utils');
|
|
16
|
+
|
|
17
|
+
// https://github.com/sindresorhus/opn#app
|
|
18
|
+
var OSX_CHROME = 'google chrome';
|
|
19
|
+
|
|
20
|
+
const Actions = Object.freeze({
|
|
21
|
+
NONE: 0,
|
|
22
|
+
BROWSER: 1,
|
|
23
|
+
SCRIPT: 2,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function getBrowserEnv() {
|
|
27
|
+
// Attempt to honor this environment variable.
|
|
28
|
+
// It is specific to the operating system.
|
|
29
|
+
// See https://github.com/sindresorhus/opn#app for documentation.
|
|
30
|
+
const value = process.env.BROWSER;
|
|
31
|
+
let action;
|
|
32
|
+
if (!value) {
|
|
33
|
+
// Default.
|
|
34
|
+
action = Actions.BROWSER;
|
|
35
|
+
} else if (value.toLowerCase().endsWith('.js')) {
|
|
36
|
+
action = Actions.SCRIPT;
|
|
37
|
+
} else if (value.toLowerCase() === 'none') {
|
|
38
|
+
action = Actions.NONE;
|
|
39
|
+
} else {
|
|
40
|
+
action = Actions.BROWSER;
|
|
41
|
+
}
|
|
42
|
+
return { action, value };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function executeNodeScript(scriptPath, url) {
|
|
46
|
+
const extraArgs = process.argv.slice(2);
|
|
47
|
+
const child = spawn('node', [scriptPath, ...extraArgs, url], {
|
|
48
|
+
stdio: 'inherit',
|
|
49
|
+
});
|
|
50
|
+
child.on('close', (code) => {
|
|
51
|
+
if (code !== 0) {
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.red('The script specified as BROWSER environment variable failed.'));
|
|
54
|
+
console.log(`${chalk.cyan(scriptPath)} exited with code ${code}.`);
|
|
55
|
+
console.log();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function startBrowserProcess(browser, url) {
|
|
63
|
+
// If we're on OS X, the user hasn't specifically
|
|
64
|
+
// requested a different browser, we can try opening
|
|
65
|
+
// Chrome with AppleScript. This lets us reuse an
|
|
66
|
+
// existing tab when possible instead of creating a new one.
|
|
67
|
+
const shouldTryOpenChromeWithAppleScript =
|
|
68
|
+
process.platform === 'darwin' && (typeof browser !== 'string' || browser === OSX_CHROME);
|
|
69
|
+
|
|
70
|
+
if (shouldTryOpenChromeWithAppleScript) {
|
|
71
|
+
try {
|
|
72
|
+
// Try our best to reuse existing tab
|
|
73
|
+
// on OS X Google Chrome with AppleScript
|
|
74
|
+
execSync('ps cax | grep "Google Chrome"');
|
|
75
|
+
execSync(`osascript resources/openChrome.applescript "${encodeURI(url)}"`, {
|
|
76
|
+
cwd: __dirname,
|
|
77
|
+
stdio: 'ignore',
|
|
78
|
+
});
|
|
79
|
+
return true;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
strapi.log.error('Failed to open Google Chrome with AppleScript');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Another special case: on OS X, check if BROWSER has been set to "open".
|
|
86
|
+
// In this case, instead of passing `open` to `opn` (which won't work),
|
|
87
|
+
// just ignore it (thus ensuring the intended behavior, i.e. opening the system browser):
|
|
88
|
+
// https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768
|
|
89
|
+
if (process.platform === 'darwin' && browser === 'open') {
|
|
90
|
+
browser = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Fallback to opn
|
|
94
|
+
// (It will always open new tab)
|
|
95
|
+
try {
|
|
96
|
+
var options = { app: browser };
|
|
97
|
+
opn(url, options).catch(() => {}); // Prevent `unhandledRejection` error.
|
|
98
|
+
return true;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function pingDashboard(url, multipleTime = false) {
|
|
105
|
+
try {
|
|
106
|
+
await fetch(url, { method: 'HEAD', timeout: 300, body: null });
|
|
107
|
+
// Inform the user that we're going to open the administration panel.
|
|
108
|
+
this.log.info('⏳ Opening the admin panel...');
|
|
109
|
+
} catch (e) {
|
|
110
|
+
if (e.code !== 'ECONNREFUSED' && e.type !== 'request-timeout') {
|
|
111
|
+
return console.error(e);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Only display once.
|
|
115
|
+
if (!multipleTime) {
|
|
116
|
+
this.log.warn(`⚠️ The admin panel is unavailable... Impossible to open it in the browser.`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Reads the BROWSER evironment variable and decides what to do with it. Returns
|
|
123
|
+
* true if it opened a browser or ran a node.js script, otherwise false.
|
|
124
|
+
*/
|
|
125
|
+
async function openBrowser() {
|
|
126
|
+
const url = getAbsoluteAdminUrl(strapi.config);
|
|
127
|
+
|
|
128
|
+
// Ping the dashboard to ensure it's available.
|
|
129
|
+
await pingDashboard.call(this, url);
|
|
130
|
+
|
|
131
|
+
const { action, value } = getBrowserEnv();
|
|
132
|
+
switch (action) {
|
|
133
|
+
case Actions.NONE:
|
|
134
|
+
// Special case: BROWSER="none" will prevent opening completely.
|
|
135
|
+
return false;
|
|
136
|
+
case Actions.SCRIPT:
|
|
137
|
+
return executeNodeScript(value, url);
|
|
138
|
+
case Actions.BROWSER:
|
|
139
|
+
return startBrowserProcess(value, url);
|
|
140
|
+
default:
|
|
141
|
+
throw new Error('Not implemented.');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = openBrowser;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApuI1XlPkYos3WsSeVPtS
|
|
3
|
+
l1Q2k8GnLEO5vFZ4EuSghMbqI+yE0tWVEaiptdV3KgERaALRXmH+IFrHqvSRjKQC
|
|
4
|
+
1ORUarBU5ntWbNEr713R3K0BPOzz9OOoWHdk+Wmr4ViOTk0iD1u4bw/97RpyMoBm
|
|
5
|
+
+pXeBLHbEESK2kelk+LEmKUoY5nXp6KzZV5wxgD5QweZheU7mjXL5WMpIBJva8kp
|
|
6
|
+
RZMYXEF+uSZIep0q5FHEo2AazGUMAU3GjY/dpXisLmtleOa1xlKZmkvaXl/D2Mhb
|
|
7
|
+
BBqPbDMa72ToZg2J8K5UP9zXUP41FHr7o9rwSJ2uOkuZPg5nhDXeoVbrJwxP/U1M
|
|
8
|
+
nQIDAQAB
|
|
9
|
+
-----END PUBLIC KEY-----
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
(*
|
|
2
|
+
Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
|
|
4
|
+
This source code is licensed under the MIT license found in the
|
|
5
|
+
LICENSE file in the root directory of this source tree.
|
|
6
|
+
*)
|
|
7
|
+
|
|
8
|
+
property targetTab: null
|
|
9
|
+
property targetTabIndex: -1
|
|
10
|
+
property targetWindow: null
|
|
11
|
+
|
|
12
|
+
on run argv
|
|
13
|
+
set theURL to item 1 of argv
|
|
14
|
+
|
|
15
|
+
tell application "Chrome"
|
|
16
|
+
|
|
17
|
+
if (count every window) = 0 then
|
|
18
|
+
make new window
|
|
19
|
+
end if
|
|
20
|
+
|
|
21
|
+
-- 1: Looking for tab running debugger
|
|
22
|
+
-- then, Reload debugging tab if found
|
|
23
|
+
-- then return
|
|
24
|
+
set found to my lookupTabWithUrl(theURL)
|
|
25
|
+
if found then
|
|
26
|
+
set targetWindow's active tab index to targetTabIndex
|
|
27
|
+
tell targetTab to reload
|
|
28
|
+
tell targetWindow to activate
|
|
29
|
+
set index of targetWindow to 1
|
|
30
|
+
return
|
|
31
|
+
end if
|
|
32
|
+
|
|
33
|
+
-- 2: Looking for Empty tab
|
|
34
|
+
-- In case debugging tab was not found
|
|
35
|
+
-- We try to find an empty tab instead
|
|
36
|
+
set found to my lookupTabWithUrl("chrome://newtab/")
|
|
37
|
+
if found then
|
|
38
|
+
set targetWindow's active tab index to targetTabIndex
|
|
39
|
+
set URL of targetTab to theURL
|
|
40
|
+
tell targetWindow to activate
|
|
41
|
+
return
|
|
42
|
+
end if
|
|
43
|
+
|
|
44
|
+
-- 3: Create new tab
|
|
45
|
+
-- both debugging and empty tab were not found
|
|
46
|
+
-- make a new tab with url
|
|
47
|
+
tell window 1
|
|
48
|
+
activate
|
|
49
|
+
make new tab with properties {URL:theURL}
|
|
50
|
+
end tell
|
|
51
|
+
end tell
|
|
52
|
+
end run
|
|
53
|
+
|
|
54
|
+
-- Function:
|
|
55
|
+
-- Lookup tab with given url
|
|
56
|
+
-- if found, store tab, index, and window in properties
|
|
57
|
+
-- (properties were declared on top of file)
|
|
58
|
+
on lookupTabWithUrl(lookupUrl)
|
|
59
|
+
tell application "Chrome"
|
|
60
|
+
-- Find a tab with the given url
|
|
61
|
+
set found to false
|
|
62
|
+
set theTabIndex to -1
|
|
63
|
+
repeat with theWindow in every window
|
|
64
|
+
set theTabIndex to 0
|
|
65
|
+
repeat with theTab in every tab of theWindow
|
|
66
|
+
set theTabIndex to theTabIndex + 1
|
|
67
|
+
if (theTab's URL as string) contains lookupUrl then
|
|
68
|
+
-- assign tab, tab index, and window to properties
|
|
69
|
+
set targetTab to theTab
|
|
70
|
+
set targetTabIndex to theTabIndex
|
|
71
|
+
set targetWindow to theWindow
|
|
72
|
+
set found to true
|
|
73
|
+
exit repeat
|
|
74
|
+
end if
|
|
75
|
+
end repeat
|
|
76
|
+
|
|
77
|
+
if found then
|
|
78
|
+
exit repeat
|
|
79
|
+
end if
|
|
80
|
+
end repeat
|
|
81
|
+
end tell
|
|
82
|
+
return found
|
|
83
|
+
end lookupTabWithUrl
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const _ = require('lodash');
|
|
6
|
+
|
|
7
|
+
const requiredPaths = ['api', 'extensions', 'plugins', 'config', 'public'];
|
|
8
|
+
const checkFoldersExist = ({ appPath }) => {
|
|
9
|
+
let missingPaths = [];
|
|
10
|
+
for (let reqPath of requiredPaths) {
|
|
11
|
+
if (!fs.pathExistsSync(path.resolve(appPath, reqPath))) {
|
|
12
|
+
missingPaths.push(reqPath);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (missingPaths.length > 0) {
|
|
17
|
+
throw new Error(`Missing required folders:\n${missingPaths.map(p => `- ./${p}`).join('\n')}`);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const checkPluginsConflicts = ({ appPath, installedPlugins }) => {
|
|
22
|
+
const localPluginNames = fs.readdirSync(path.resolve(appPath, 'plugins'));
|
|
23
|
+
const pluginsIntersection = _.intersection(localPluginNames, installedPlugins);
|
|
24
|
+
|
|
25
|
+
if (pluginsIntersection.length > 0) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`You have some local plugins with the same name as npm installed plugins:\n${pluginsIntersection
|
|
28
|
+
.map(p => `- ${p}`)
|
|
29
|
+
.join('\n')}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports = config => {
|
|
35
|
+
checkFoldersExist(config);
|
|
36
|
+
checkPluginsConflicts(config);
|
|
37
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Module dependencies
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// const fetch = require('node-fetch');
|
|
8
|
+
// const { machineIdSync } = require('node-machine-id');
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* No need to worry about this file, we only retrieve anonymous data here.
|
|
12
|
+
* It allows us to know on how many times the package has been installed globally.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* try {
|
|
16
|
+
if (
|
|
17
|
+
process.env.npm_config_global === 'true' ||
|
|
18
|
+
JSON.parse(process.env.npm_config_argv).original.includes('global')
|
|
19
|
+
) {
|
|
20
|
+
fetch('https://analytics.strapi.io/track', {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
event: 'didInstallStrapi',
|
|
24
|
+
deviceId: machineIdSync(),
|
|
25
|
+
}),
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
}).catch(() => {});
|
|
28
|
+
}
|
|
29
|
+
} catch (e) {
|
|
30
|
+
//...
|
|
31
|
+
} */
|