@strapi/admin 4.13.0-beta.0 → 4.13.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/admin/src/components/NpsSurvey/hooks/useNpsSurveySettings.js +17 -0
- package/admin/src/components/NpsSurvey/index.js +365 -0
- package/admin/src/content-manager/components/DynamicZone/components/DynamicZoneLabel.js +1 -1
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +7 -9
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +6 -0
- package/admin/src/content-manager/components/Filter/Filter.js +21 -23
- package/admin/src/content-manager/components/InputUID/index.js +222 -216
- package/admin/src/content-manager/components/RelationInput/RelationInput.js +4 -0
- package/admin/src/content-manager/components/RepeatableComponent/index.js +32 -2
- package/admin/src/content-manager/components/Wysiwyg/Editor.js +432 -68
- package/admin/src/content-manager/components/Wysiwyg/WysiwygNav.js +7 -30
- package/admin/src/content-manager/components/Wysiwyg/WysiwygStyles.js +0 -7
- package/admin/src/content-manager/components/Wysiwyg/index.js +147 -152
- package/admin/src/content-manager/constants/attributes.js +3 -0
- package/admin/src/content-manager/hooks/useAllowedAttributes.js +3 -7
- package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +1 -1
- package/admin/src/content-manager/pages/ListSettingsView/index.js +16 -41
- package/admin/src/content-manager/pages/ListView/components/ViewSettingsMenu/index.js +7 -1
- package/admin/src/content-manager/pages/ListView/index.js +14 -5
- package/admin/src/pages/Admin/index.js +3 -1
- package/admin/src/pages/AuthPage/components/Register/index.js +5 -0
- package/admin/src/pages/MarketplacePage/index.js +0 -1
- package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
- package/admin/src/pages/SettingsPage/index.js +16 -26
- package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +24 -31
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
- package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +11 -6
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -0
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +1 -0
- package/admin/src/plugins.js +7 -8
- package/admin/src/translations/en.json +7 -0
- package/build/{1049.f76cb14b.chunk.js → 1049.ec69f5e0.chunk.js} +1 -1
- package/build/1227.9f37e1dc.chunk.js +1 -0
- package/build/{1386.879bcd90.chunk.js → 1386.ea73b677.chunk.js} +1 -1
- package/build/1504.eff012f7.chunk.js +95 -0
- package/build/{2225.c6244756.chunk.js → 2225.649fb7bc.chunk.js} +11 -11
- package/build/2237.b832ae6e.chunk.js +114 -0
- package/build/2379.1f98a31a.chunk.js +1 -0
- package/build/2395.0e5e8ded.chunk.js +26 -0
- package/build/2801.8e1aa82a.chunk.js +1 -0
- package/build/{3483.03c24f96.chunk.js → 3483.19381b40.chunk.js} +1 -1
- package/build/{4174.fa8f9954.chunk.js → 4174.f1f39e40.chunk.js} +1 -1
- package/build/{4546.ff09eeda.chunk.js → 4546.a5946d22.chunk.js} +1 -1
- package/build/4724.aea5c8c1.chunk.js +6 -0
- package/build/502.7bba43b1.chunk.js +1 -0
- package/build/7464.eb057bec.chunk.js +1 -0
- package/build/8276.be3ed581.chunk.js +26 -0
- package/build/{Admin-authenticatedApp.53a24d28.chunk.js → Admin-authenticatedApp.73b6f8af.chunk.js} +2 -2
- package/build/{Admin_InternalErrorPage.f45f2462.chunk.js → Admin_InternalErrorPage.38155af3.chunk.js} +1 -1
- package/build/{Admin_homePage.ac9dfb86.chunk.js → Admin_homePage.6f128523.chunk.js} +1 -1
- package/build/{Admin_marketplace.dde9c148.chunk.js → Admin_marketplace.061a6e5a.chunk.js} +2 -2
- package/build/{Admin_pluginsPage.bbe79434.chunk.js → Admin_pluginsPage.16f837b8.chunk.js} +1 -1
- package/build/{Admin_profilePage.192edc52.chunk.js → Admin_profilePage.678bce24.chunk.js} +2 -2
- package/build/Admin_settingsPage.af7309e4.chunk.js +111 -0
- package/build/{Upload_ConfigureTheView.345ac1e0.chunk.js → Upload_ConfigureTheView.3fc1c100.chunk.js} +1 -1
- package/build/admin-app.d63bd229.chunk.js +36 -0
- package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.38a6c863.chunk.js} +3 -3
- package/build/admin-edit-users.545fc882.chunk.js +10 -0
- package/build/{admin-roles-list.23ddff26.chunk.js → admin-roles-list.1e2e814d.chunk.js} +1 -1
- package/build/{admin-users.123aa08e.chunk.js → admin-users.b8ea5677.chunk.js} +2 -2
- package/build/{api-tokens-create-page.46c2ea84.chunk.js → api-tokens-create-page.e0c15627.chunk.js} +1 -1
- package/build/{api-tokens-edit-page.58139df9.chunk.js → api-tokens-edit-page.9f2dce47.chunk.js} +1 -1
- package/build/api-tokens-list-page.d747051c.chunk.js +16 -0
- package/build/{audit-logs-settings-page.0f73ccf8.chunk.js → audit-logs-settings-page.96f9d608.chunk.js} +1 -1
- package/build/content-manager.2d676432.chunk.js +1097 -0
- package/build/{content-type-builder-list-view.bf9be456.chunk.js → content-type-builder-list-view.b71cf240.chunk.js} +1 -1
- package/build/{content-type-builder.cd999f6e.chunk.js → content-type-builder.e5669749.chunk.js} +2 -2
- package/build/email-settings-page.2809f0bf.chunk.js +11 -0
- package/build/en-json.e12fd5fc.chunk.js +1 -0
- package/build/{i18n-settings-page.47f78016.chunk.js → i18n-settings-page.5f716172.chunk.js} +1 -1
- package/build/index.html +1 -1
- package/build/main.c6c9e04c.js +2859 -0
- package/build/review-workflows-settings-create-view.4a156a19.chunk.js +1 -0
- package/build/review-workflows-settings-edit-view.ce984d1f.chunk.js +1 -0
- package/build/review-workflows-settings-list-view.419b8deb.chunk.js +56 -0
- package/build/{runtime~main.b16af570.js → runtime~main.3d78854e.js} +2 -2
- package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.45153df5.chunk.js} +1 -1
- package/build/{transfer-tokens-create-page.1597e6ab.chunk.js → transfer-tokens-create-page.ebba16d8.chunk.js} +1 -1
- package/build/{transfer-tokens-edit-page.8741529f.chunk.js → transfer-tokens-edit-page.d7bb2b3e.chunk.js} +1 -1
- package/build/transfer-tokens-list-page.cfe1736c.chunk.js +16 -0
- package/build/{upload-settings.7f93d4c0.chunk.js → upload-settings.cc5ad813.chunk.js} +1 -1
- package/build/{upload.37488080.chunk.js → upload.756efc28.chunk.js} +1 -1
- package/build/users-advanced-settings-page.818d84eb.chunk.js +9 -0
- package/build/users-email-settings-page.c1967c09.chunk.js +9 -0
- package/build/users-providers-settings-page.11893e08.chunk.js +14 -0
- package/build/users-roles-settings-page.2b051e6a.chunk.js +55 -0
- package/build/{webhook-edit-page.6cb479ff.chunk.js → webhook-edit-page.de45c635.chunk.js} +2 -2
- package/build/{webhook-list-page.65e1b5bb.chunk.js → webhook-list-page.ca91df8b.chunk.js} +1 -1
- package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/AssigneeSelect.js +69 -71
- package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/StageSelect.js +3 -1
- package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/ReviewWorkflowsAssigneeEE.js +8 -38
- package/ee/admin/hooks/useAuthProviders.js +25 -0
- package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
- package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
- package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
- package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
- package/ee/admin/pages/HomePage/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
- package/index.js +2 -6
- package/package.json +9 -9
- package/scripts/build.js +15 -15
- package/scripts/create-dev-plugins-file.js +5 -38
- package/server/controllers/role.js +2 -0
- package/server/controllers/user.js +2 -0
- package/server/services/permission/permissions-manager/index.js +3 -1
- package/server/services/permission/permissions-manager/sanitize.js +7 -7
- package/server/services/permission/permissions-manager/validate.js +218 -0
- package/utils/create-cache-dir.js +62 -16
- package/utils/create-plugins-exclude-path.js +3 -23
- package/utils/get-plugins.js +110 -0
- package/utils/index.js +1 -1
- package/webpack.config.js +10 -13
- package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +0 -344
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
- package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
- package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
- package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
- package/admin/src/pages/SettingsPage/utils/index.js +0 -2
- package/build/1227.32fe57ce.chunk.js +0 -1
- package/build/2379.f1641312.chunk.js +0 -1
- package/build/2395.46f8d0c1.chunk.js +0 -26
- package/build/2801.5cef5ec8.chunk.js +0 -1
- package/build/3929.5632f24d.chunk.js +0 -114
- package/build/4724.baf7c5b1.chunk.js +0 -6
- package/build/502.8ae8ef60.chunk.js +0 -1
- package/build/5542.2415a393.chunk.js +0 -63
- package/build/7464.3e64a1d5.chunk.js +0 -1
- package/build/8276.10a3f883.chunk.js +0 -26
- package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
- package/build/admin-app.91898385.chunk.js +0 -36
- package/build/admin-edit-users.79eeb125.chunk.js +0 -10
- package/build/api-tokens-list-page.505bf7e0.chunk.js +0 -16
- package/build/content-manager.7f96a2f1.chunk.js +0 -1097
- package/build/email-settings-page.d494d1eb.chunk.js +0 -11
- package/build/en-json.4f06fe03.chunk.js +0 -1
- package/build/main.40b94779.js +0 -2859
- package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
- package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
- package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
- package/build/transfer-tokens-list-page.22147d2c.chunk.js +0 -16
- package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
- package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
- package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
- package/build/users-roles-settings-page.9d9a1eff.chunk.js +0 -30
- package/ee/admin/hooks/index.js +0 -4
- package/ee/admin/hooks/useAuthProviders/index.js +0 -50
- package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
- package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
- package/scripts/create-plugins-file.js +0 -92
- package/utils/get-plugins-path.js +0 -41
- /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
- /package/server/services/permission/permissions-manager/{query-builers.js → query-builders.js} +0 -0
package/scripts/build.js
CHANGED
|
@@ -7,14 +7,8 @@ const { isObject } = require('lodash');
|
|
|
7
7
|
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
|
|
8
8
|
|
|
9
9
|
const webpackConfig = require('../webpack.config');
|
|
10
|
-
const
|
|
11
|
-
const {
|
|
12
|
-
getCorePluginsPath,
|
|
13
|
-
getPluginToInstallPath,
|
|
14
|
-
createPluginsFile,
|
|
15
|
-
} = require('./create-plugins-file');
|
|
16
|
-
|
|
17
|
-
const PLUGINS_TO_INSTALL = ['i18n', 'users-permissions'];
|
|
10
|
+
const { getPlugins } = require('../utils/get-plugins');
|
|
11
|
+
const { createPluginsJs } = require('../utils/create-cache-dir');
|
|
18
12
|
|
|
19
13
|
// Wrapper that outputs the webpack speed
|
|
20
14
|
const smp = new SpeedMeasurePlugin();
|
|
@@ -24,18 +18,24 @@ const buildAdmin = async () => {
|
|
|
24
18
|
const dest = path.join(__dirname, '..', 'build');
|
|
25
19
|
const tsConfigFilePath = path.join(__dirname, '..', 'admin', 'src', 'tsconfig.json');
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
/**
|
|
22
|
+
* We _always_ install these FE plugins, they're considered "core"
|
|
23
|
+
* and are typically marked as `required` in their package.json
|
|
24
|
+
*/
|
|
25
|
+
const plugins = getPlugins([
|
|
26
|
+
'@strapi/plugin-content-type-builder',
|
|
27
|
+
'@strapi/plugin-email',
|
|
28
|
+
'@strapi/plugin-upload',
|
|
29
|
+
'@strapi/plugin-i18n',
|
|
30
|
+
'@strapi/plugin-users-permissions',
|
|
31
|
+
]);
|
|
31
32
|
|
|
32
|
-
await
|
|
33
|
+
await createPluginsJs(plugins, path.join(__dirname, '..'));
|
|
33
34
|
|
|
34
35
|
const args = {
|
|
35
36
|
entry,
|
|
36
37
|
dest,
|
|
37
|
-
|
|
38
|
-
pluginsPath,
|
|
38
|
+
plugins,
|
|
39
39
|
env: 'production',
|
|
40
40
|
optimize: true,
|
|
41
41
|
options: {
|
|
@@ -1,40 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { join
|
|
4
|
-
const { promisify } = require('util');
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
7
|
-
const glob = promisify(require('glob').glob);
|
|
3
|
+
const { join } = require('path');
|
|
8
4
|
const fs = require('fs-extra');
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Retrieve all plugins that are inside the plugins folder
|
|
13
|
-
* @returns Object the plugins
|
|
14
|
-
*/
|
|
15
|
-
const getPluginsPackages = async () => {
|
|
16
|
-
const pathToPackages = resolve(__dirname, '..', '..', '..', 'plugins', '*');
|
|
17
|
-
const pluginsPackageDirs = await glob(pathToPackages);
|
|
18
|
-
|
|
19
|
-
return pluginsPackageDirs
|
|
20
|
-
.filter((pluginDir) => {
|
|
21
|
-
return fs.existsSync(join(pluginDir, 'admin', 'src', 'index.js'));
|
|
22
|
-
})
|
|
23
|
-
.reduce((acc, current) => {
|
|
24
|
-
const depName = current.replace(/\\/g, '/').split('/').slice(-1)[0];
|
|
25
|
-
|
|
26
|
-
const adminEntryPoint = join(__dirname, '..', 'admin', 'src');
|
|
27
|
-
|
|
28
|
-
const pathToPlugin = join(relative(adminEntryPoint, current), 'admin', 'src').replace(
|
|
29
|
-
/\\/g,
|
|
30
|
-
'/'
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
acc[depName] = pathToPlugin;
|
|
34
|
-
|
|
35
|
-
return acc;
|
|
36
|
-
}, {});
|
|
37
|
-
};
|
|
5
|
+
const { getPlugins } = require('../utils/get-plugins');
|
|
6
|
+
const { createPluginsJs } = require('../utils/create-cache-dir');
|
|
38
7
|
|
|
39
8
|
/**
|
|
40
9
|
* Write the plugins.js file or copy the plugins-dev.js file if it exists
|
|
@@ -49,11 +18,9 @@ const createFile = async () => {
|
|
|
49
18
|
return;
|
|
50
19
|
}
|
|
51
20
|
|
|
52
|
-
const
|
|
53
|
-
const plugins = await getPluginsPackages();
|
|
54
|
-
const allPlugins = { ...corePlugins, ...plugins };
|
|
21
|
+
const plugins = getPlugins();
|
|
55
22
|
|
|
56
|
-
return
|
|
23
|
+
return createPluginsJs(plugins, join(__dirname, '..'));
|
|
57
24
|
};
|
|
58
25
|
|
|
59
26
|
createFile()
|
|
@@ -55,6 +55,8 @@ module.exports = {
|
|
|
55
55
|
ability: ctx.state.userAbility,
|
|
56
56
|
model: 'admin::role',
|
|
57
57
|
});
|
|
58
|
+
|
|
59
|
+
await permissionsManager.validateQuery(query);
|
|
58
60
|
const sanitizedQuery = await permissionsManager.sanitizeQuery(query);
|
|
59
61
|
|
|
60
62
|
const roles = await getService('role').findAllWithUsersCount(sanitizedQuery);
|
|
@@ -52,6 +52,8 @@ module.exports = {
|
|
|
52
52
|
ability: ctx.state.userAbility,
|
|
53
53
|
model: 'admin::user',
|
|
54
54
|
});
|
|
55
|
+
|
|
56
|
+
await permissionsManager.validateQuery(ctx.query);
|
|
55
57
|
const sanitizedQuery = await permissionsManager.sanitizeQuery(ctx.query);
|
|
56
58
|
|
|
57
59
|
const { results, pagination } = await userService.findPage(sanitizedQuery);
|
|
@@ -4,8 +4,9 @@ const _ = require('lodash');
|
|
|
4
4
|
const { cloneDeep, isPlainObject } = require('lodash/fp');
|
|
5
5
|
const { subject: asSubject } = require('@casl/ability');
|
|
6
6
|
const createSanitizeHelpers = require('./sanitize');
|
|
7
|
+
const createValidateHelpers = require('./validate');
|
|
7
8
|
|
|
8
|
-
const { buildStrapiQuery, buildCaslQuery } = require('./query-
|
|
9
|
+
const { buildStrapiQuery, buildCaslQuery } = require('./query-builders');
|
|
9
10
|
|
|
10
11
|
module.exports = ({ ability, action, model }) => ({
|
|
11
12
|
ability,
|
|
@@ -48,4 +49,5 @@ module.exports = ({ ability, action, model }) => ({
|
|
|
48
49
|
},
|
|
49
50
|
|
|
50
51
|
...createSanitizeHelpers({ action, ability, model }),
|
|
52
|
+
...createValidateHelpers({ action, ability, model }),
|
|
51
53
|
});
|
|
@@ -45,7 +45,7 @@ const STATIC_FIELDS = [ID_ATTRIBUTE];
|
|
|
45
45
|
module.exports = ({ action, ability, model }) => {
|
|
46
46
|
const schema = strapi.getModel(model);
|
|
47
47
|
|
|
48
|
-
const {
|
|
48
|
+
const { removeDisallowedFields } = sanitize.visitors;
|
|
49
49
|
|
|
50
50
|
const createSanitizeQuery = (options = {}) => {
|
|
51
51
|
const { fields } = options;
|
|
@@ -54,7 +54,7 @@ module.exports = ({ action, ability, model }) => {
|
|
|
54
54
|
const permittedFields = fields.shouldIncludeAll ? null : getQueryFields(fields.permitted);
|
|
55
55
|
|
|
56
56
|
const sanitizeFilters = pipeAsync(
|
|
57
|
-
traverse.traverseQueryFilters(
|
|
57
|
+
traverse.traverseQueryFilters(removeDisallowedFields(permittedFields), { schema }),
|
|
58
58
|
traverse.traverseQueryFilters(omitDisallowedAdminUserFields, { schema }),
|
|
59
59
|
traverse.traverseQueryFilters(omitHiddenFields, { schema }),
|
|
60
60
|
traverse.traverseQueryFilters(removePassword, { schema }),
|
|
@@ -69,7 +69,7 @@ module.exports = ({ action, ability, model }) => {
|
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
const sanitizeSort = pipeAsync(
|
|
72
|
-
traverse.traverseQuerySort(
|
|
72
|
+
traverse.traverseQuerySort(removeDisallowedFields(permittedFields), { schema }),
|
|
73
73
|
traverse.traverseQuerySort(omitDisallowedAdminUserFields, { schema }),
|
|
74
74
|
traverse.traverseQuerySort(omitHiddenFields, { schema }),
|
|
75
75
|
traverse.traverseQuerySort(removePassword, { schema }),
|
|
@@ -84,14 +84,14 @@ module.exports = ({ action, ability, model }) => {
|
|
|
84
84
|
);
|
|
85
85
|
|
|
86
86
|
const sanitizePopulate = pipeAsync(
|
|
87
|
-
traverse.traverseQueryPopulate(
|
|
87
|
+
traverse.traverseQueryPopulate(removeDisallowedFields(permittedFields), { schema }),
|
|
88
88
|
traverse.traverseQueryPopulate(omitDisallowedAdminUserFields, { schema }),
|
|
89
89
|
traverse.traverseQueryPopulate(omitHiddenFields, { schema }),
|
|
90
90
|
traverse.traverseQueryPopulate(removePassword, { schema })
|
|
91
91
|
);
|
|
92
92
|
|
|
93
93
|
const sanitizeFields = pipeAsync(
|
|
94
|
-
traverse.traverseQueryFields(
|
|
94
|
+
traverse.traverseQueryFields(removeDisallowedFields(permittedFields), { schema }),
|
|
95
95
|
traverse.traverseQueryFields(omitHiddenFields, { schema }),
|
|
96
96
|
traverse.traverseQueryFields(removePassword, { schema })
|
|
97
97
|
);
|
|
@@ -130,7 +130,7 @@ module.exports = ({ action, ability, model }) => {
|
|
|
130
130
|
// Remove unallowed fields from admin::user relations
|
|
131
131
|
traverseEntity(pickAllowedAdminUserFields, { schema }),
|
|
132
132
|
// Remove not allowed fields (RBAC)
|
|
133
|
-
traverseEntity(
|
|
133
|
+
traverseEntity(removeDisallowedFields(permittedFields), { schema }),
|
|
134
134
|
// Remove all fields of type 'password'
|
|
135
135
|
sanitize.sanitizers.sanitizePasswords(schema)
|
|
136
136
|
);
|
|
@@ -145,7 +145,7 @@ module.exports = ({ action, ability, model }) => {
|
|
|
145
145
|
// Remove fields hidden from the admin
|
|
146
146
|
traverseEntity(omitHiddenFields, { schema }),
|
|
147
147
|
// Remove not allowed fields (RBAC)
|
|
148
|
-
traverseEntity(
|
|
148
|
+
traverseEntity(removeDisallowedFields(permittedFields), { schema }),
|
|
149
149
|
// Remove roles from createdBy & updateBy fields
|
|
150
150
|
omitCreatorRoles
|
|
151
151
|
);
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { subject: asSubject, detectSubjectType } = require('@casl/ability');
|
|
4
|
+
const { permittedFieldsOf } = require('@casl/ability/extra');
|
|
5
|
+
const {
|
|
6
|
+
defaults,
|
|
7
|
+
omit,
|
|
8
|
+
isArray,
|
|
9
|
+
isEmpty,
|
|
10
|
+
isNil,
|
|
11
|
+
flatMap,
|
|
12
|
+
some,
|
|
13
|
+
prop,
|
|
14
|
+
uniq,
|
|
15
|
+
intersection,
|
|
16
|
+
getOr,
|
|
17
|
+
isObject,
|
|
18
|
+
} = require('lodash/fp');
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
contentTypes,
|
|
22
|
+
traverseEntity,
|
|
23
|
+
traverse,
|
|
24
|
+
validate,
|
|
25
|
+
pipeAsync,
|
|
26
|
+
errors: { ValidationError },
|
|
27
|
+
} = require('@strapi/utils');
|
|
28
|
+
|
|
29
|
+
const { throwPassword, throwDisallowedFields } = validate.visitors;
|
|
30
|
+
const { ADMIN_USER_ALLOWED_FIELDS } = require('../../../domain/user');
|
|
31
|
+
|
|
32
|
+
const { constants, isScalarAttribute, getNonVisibleAttributes, getWritableAttributes } =
|
|
33
|
+
contentTypes;
|
|
34
|
+
const {
|
|
35
|
+
ID_ATTRIBUTE,
|
|
36
|
+
CREATED_AT_ATTRIBUTE,
|
|
37
|
+
UPDATED_AT_ATTRIBUTE,
|
|
38
|
+
PUBLISHED_AT_ATTRIBUTE,
|
|
39
|
+
CREATED_BY_ATTRIBUTE,
|
|
40
|
+
UPDATED_BY_ATTRIBUTE,
|
|
41
|
+
} = constants;
|
|
42
|
+
|
|
43
|
+
const COMPONENT_FIELDS = ['__component'];
|
|
44
|
+
|
|
45
|
+
const STATIC_FIELDS = [ID_ATTRIBUTE];
|
|
46
|
+
|
|
47
|
+
const throwInvalidParam = ({ key }) => {
|
|
48
|
+
throw new ValidationError(`Invalid parameter ${key}`);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
module.exports = ({ action, ability, model }) => {
|
|
52
|
+
const schema = strapi.getModel(model);
|
|
53
|
+
|
|
54
|
+
const createValidateQuery = (options = {}) => {
|
|
55
|
+
const { fields } = options;
|
|
56
|
+
|
|
57
|
+
// TODO: validate relations to admin users in all validators
|
|
58
|
+
const permittedFields = fields.shouldIncludeAll ? null : getQueryFields(fields.permitted);
|
|
59
|
+
|
|
60
|
+
const validateFilters = pipeAsync(
|
|
61
|
+
traverse.traverseQueryFilters(throwDisallowedFields(permittedFields), { schema }),
|
|
62
|
+
traverse.traverseQueryFilters(throwDisallowedAdminUserFields, { schema }),
|
|
63
|
+
traverse.traverseQueryFilters(throwPassword, { schema }),
|
|
64
|
+
traverse.traverseQueryFilters(
|
|
65
|
+
({ key, value }) => {
|
|
66
|
+
if (isObject(value) && isEmpty(value)) {
|
|
67
|
+
throwInvalidParam({ key });
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{ schema }
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const validateSort = pipeAsync(
|
|
75
|
+
traverse.traverseQuerySort(throwDisallowedFields(permittedFields), { schema }),
|
|
76
|
+
traverse.traverseQuerySort(throwDisallowedAdminUserFields, { schema }),
|
|
77
|
+
traverse.traverseQuerySort(throwPassword, { schema }),
|
|
78
|
+
traverse.traverseQuerySort(
|
|
79
|
+
({ key, attribute, value }) => {
|
|
80
|
+
if (!isScalarAttribute(attribute) && isEmpty(value)) {
|
|
81
|
+
throwInvalidParam({ key });
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{ schema }
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const validateFields = pipeAsync(
|
|
89
|
+
traverse.traverseQueryFields(throwDisallowedFields(permittedFields), { schema }),
|
|
90
|
+
traverse.traverseQueryFields(throwPassword, { schema })
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return async (query) => {
|
|
94
|
+
if (query.filters) {
|
|
95
|
+
await validateFilters(query.filters);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (query.sort) {
|
|
99
|
+
await validateSort(query.sort);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (query.fields) {
|
|
103
|
+
await validateFields(query.fields);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return true;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const createValidateInput = (options = {}) => {
|
|
111
|
+
const { fields } = options;
|
|
112
|
+
|
|
113
|
+
const permittedFields = fields.shouldIncludeAll ? null : getInputFields(fields.permitted);
|
|
114
|
+
|
|
115
|
+
return pipeAsync(
|
|
116
|
+
// Remove fields hidden from the admin
|
|
117
|
+
traverseEntity(throwHiddenFields, { schema }),
|
|
118
|
+
// Remove not allowed fields (RBAC)
|
|
119
|
+
traverseEntity(throwDisallowedFields(permittedFields), { schema }),
|
|
120
|
+
// Remove roles from createdBy & updatedBy fields
|
|
121
|
+
omitCreatorRoles
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const wrapValidate = (createValidateFunction) => {
|
|
126
|
+
const wrappedValidate = async (data, options = {}) => {
|
|
127
|
+
if (isArray(data)) {
|
|
128
|
+
return Promise.all(data.map((entity) => wrappedValidate(entity, options)));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const { subject, action: actionOverride } = getDefaultOptions(data, options);
|
|
132
|
+
|
|
133
|
+
const permittedFields = permittedFieldsOf(ability, actionOverride, subject, {
|
|
134
|
+
fieldsFrom: (rule) => rule.fields || [],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const hasAtLeastOneRegistered = some(
|
|
138
|
+
(fields) => !isNil(fields),
|
|
139
|
+
flatMap(prop('fields'), ability.rulesFor(actionOverride, detectSubjectType(subject)))
|
|
140
|
+
);
|
|
141
|
+
const shouldIncludeAllFields = isEmpty(permittedFields) && !hasAtLeastOneRegistered;
|
|
142
|
+
|
|
143
|
+
const validateOptions = {
|
|
144
|
+
...options,
|
|
145
|
+
fields: {
|
|
146
|
+
shouldIncludeAll: shouldIncludeAllFields,
|
|
147
|
+
permitted: permittedFields,
|
|
148
|
+
hasAtLeastOneRegistered,
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const validateFunction = createValidateFunction(validateOptions);
|
|
153
|
+
|
|
154
|
+
return validateFunction(data);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return wrappedValidate;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const getDefaultOptions = (data, options) => {
|
|
161
|
+
return defaults({ subject: asSubject(model, data), action }, options);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Omit creator fields' (createdBy & updatedBy) roles from the admin API responses
|
|
166
|
+
*/
|
|
167
|
+
const omitCreatorRoles = omit([`${CREATED_BY_ATTRIBUTE}.roles`, `${UPDATED_BY_ATTRIBUTE}.roles`]);
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Visitor used to remove hidden fields from the admin API responses
|
|
171
|
+
*/
|
|
172
|
+
const throwHiddenFields = ({ key, schema }) => {
|
|
173
|
+
const isHidden = getOr(false, ['config', 'attributes', key, 'hidden'], schema);
|
|
174
|
+
|
|
175
|
+
if (isHidden) {
|
|
176
|
+
throwInvalidParam({ key });
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Visitor used to omit disallowed fields from the admin users entities & avoid leaking sensitive information
|
|
182
|
+
*/
|
|
183
|
+
const throwDisallowedAdminUserFields = ({ key, attribute, schema }) => {
|
|
184
|
+
if (schema.uid === 'admin::user' && attribute && !ADMIN_USER_ALLOWED_FIELDS.includes(key)) {
|
|
185
|
+
throwInvalidParam({ key });
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const getInputFields = (fields = []) => {
|
|
190
|
+
const nonVisibleAttributes = getNonVisibleAttributes(schema);
|
|
191
|
+
const writableAttributes = getWritableAttributes(schema);
|
|
192
|
+
|
|
193
|
+
const nonVisibleWritableAttributes = intersection(nonVisibleAttributes, writableAttributes);
|
|
194
|
+
|
|
195
|
+
return uniq([
|
|
196
|
+
...fields,
|
|
197
|
+
...STATIC_FIELDS,
|
|
198
|
+
...COMPONENT_FIELDS,
|
|
199
|
+
...nonVisibleWritableAttributes,
|
|
200
|
+
]);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const getQueryFields = (fields = []) => {
|
|
204
|
+
return uniq([
|
|
205
|
+
...fields,
|
|
206
|
+
...STATIC_FIELDS,
|
|
207
|
+
...COMPONENT_FIELDS,
|
|
208
|
+
CREATED_AT_ATTRIBUTE,
|
|
209
|
+
UPDATED_AT_ATTRIBUTE,
|
|
210
|
+
PUBLISHED_AT_ATTRIBUTE,
|
|
211
|
+
]);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
validateQuery: wrapValidate(createValidateQuery),
|
|
216
|
+
validateInput: wrapValidate(createValidateInput),
|
|
217
|
+
};
|
|
218
|
+
};
|
|
@@ -9,20 +9,29 @@ const getCustomAppConfigFile = require('./get-custom-app-config-file');
|
|
|
9
9
|
const getPkgPath = (name) => path.dirname(require.resolve(`${name}/package.json`));
|
|
10
10
|
|
|
11
11
|
async function createPluginsJs(plugins, dest) {
|
|
12
|
-
const pluginsArray = plugins.map(({ pathToPlugin, name }) => {
|
|
12
|
+
const pluginsArray = plugins.map(({ pathToPlugin, name, info }) => {
|
|
13
13
|
const shortName = _.camelCase(name);
|
|
14
14
|
|
|
15
|
+
let realPath = '';
|
|
16
|
+
|
|
15
17
|
/**
|
|
16
|
-
*
|
|
17
|
-
* The problem is that Webpack does not windows paths
|
|
18
|
-
* With this tool, we need to rely on "/" and not "\".
|
|
19
|
-
* This is the reason why '..\\..\\..\\node_modules\\@strapi\\plugin-content-type-builder/strapi-admin.js' was not working.
|
|
20
|
-
* The regexp at line 105 aims to replace the windows backslashes by standard slash so that webpack can deal with them.
|
|
21
|
-
* Backslash looks to work only for absolute paths with webpack => https://webpack.js.org/concepts/module-resolution/#absolute-paths
|
|
18
|
+
* We're using a module here so we want to keep using the module resolution procedure.
|
|
22
19
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if (info?.packageName || info?.required) {
|
|
21
|
+
/**
|
|
22
|
+
* path.join, on windows, it uses backslashes to resolve path.
|
|
23
|
+
* The problem is that Webpack does not windows paths
|
|
24
|
+
* With this tool, we need to rely on "/" and not "\".
|
|
25
|
+
* This is the reason why '..\\..\\..\\node_modules\\@strapi\\plugin-content-type-builder/strapi-admin.js' was not working.
|
|
26
|
+
* The regexp at line 105 aims to replace the windows backslashes by standard slash so that webpack can deal with them.
|
|
27
|
+
* Backslash looks to work only for absolute paths with webpack => https://webpack.js.org/concepts/module-resolution/#absolute-paths
|
|
28
|
+
*/
|
|
29
|
+
realPath = path.join(pathToPlugin, 'strapi-admin').replace(/\\/g, '/');
|
|
30
|
+
} else {
|
|
31
|
+
realPath = path
|
|
32
|
+
.join(path.relative(path.resolve(dest, 'admin', 'src'), pathToPlugin), 'strapi-admin')
|
|
33
|
+
.replace(/\\/g, '/');
|
|
34
|
+
}
|
|
26
35
|
|
|
27
36
|
return {
|
|
28
37
|
name,
|
|
@@ -76,12 +85,49 @@ async function createCacheDir({ appDir, plugins }) {
|
|
|
76
85
|
'tsconfig.json'
|
|
77
86
|
);
|
|
78
87
|
|
|
79
|
-
const pluginsWithFront = Object.
|
|
80
|
-
.filter((
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
const pluginsWithFront = Object.entries(plugins)
|
|
89
|
+
.filter(([, plugin]) => {
|
|
90
|
+
/**
|
|
91
|
+
* There are two ways a plugin should be imported, either it's local to the strapi app,
|
|
92
|
+
* or it's an actual npm module that's installed and resolved via node_modules.
|
|
93
|
+
*
|
|
94
|
+
* We first check if the plugin is local to the strapi app, using a regular `resolve` because
|
|
95
|
+
* the pathToPlugin will be relative i.e. `/Users/my-name/strapi-app/src/plugins/my-plugin`.
|
|
96
|
+
*
|
|
97
|
+
* If the file doesn't exist well then it's probably a node_module, so instead we use `require.resolve`
|
|
98
|
+
* which will resolve the path to the module in node_modules. If it fails with the specific code `MODULE_NOT_FOUND`
|
|
99
|
+
* then it doesn't have an admin part to the package.
|
|
100
|
+
*
|
|
101
|
+
* NOTE: we should try to move to `./package.json[exports]` map with bundling of our own plugins,
|
|
102
|
+
* because these entry files are written in commonjs restricting features e.g. tree-shaking.
|
|
103
|
+
*/
|
|
104
|
+
try {
|
|
105
|
+
const isLocalPluginWithLegacyAdminFile = fs.existsSync(
|
|
106
|
+
path.resolve(`${plugin.pathToPlugin}/strapi-admin.js`)
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (!isLocalPluginWithLegacyAdminFile) {
|
|
110
|
+
const isModulewithLegacyAdminFile = require.resolve(
|
|
111
|
+
`${plugin.pathToPlugin}/strapi-admin.js`
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return isModulewithLegacyAdminFile;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return isLocalPluginWithLegacyAdminFile;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (err.code === 'MODULE_NOT_FOUND') {
|
|
120
|
+
/**
|
|
121
|
+
* the plugin does not contain FE code, so we
|
|
122
|
+
* don't want to import it anyway
|
|
123
|
+
*/
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
83
129
|
})
|
|
84
|
-
.map((name) => ({ name, ...
|
|
130
|
+
.map(([name, plugin]) => ({ name, ...plugin }));
|
|
85
131
|
|
|
86
132
|
// create .cache dir
|
|
87
133
|
await fs.emptyDir(cacheDir);
|
|
@@ -128,4 +174,4 @@ async function createCacheDir({ appDir, plugins }) {
|
|
|
128
174
|
}
|
|
129
175
|
}
|
|
130
176
|
|
|
131
|
-
module.exports = createCacheDir;
|
|
177
|
+
module.exports = { createCacheDir, createPluginsJs };
|
|
@@ -1,40 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { sep, join } = require('path');
|
|
4
|
-
|
|
5
3
|
const NODE_MODULES = 'node_modules';
|
|
6
4
|
/**
|
|
7
5
|
* @param {string[]} pluginsPath – an array of paths to the plugins from the user's directory
|
|
8
6
|
* @returns {RegExp} a regex that will exclude _all_ node_modules except for the plugins in the pluginsPath array.
|
|
9
7
|
*/
|
|
10
8
|
const createPluginsExcludePath = (pluginsPath = []) => {
|
|
11
|
-
/**
|
|
12
|
-
* converts the full path to just the plugin path
|
|
13
|
-
* e.g. `/Users/username/strapi/node_modules/@scope/plugin-name`
|
|
14
|
-
* to `@scope/plugin-name`
|
|
15
|
-
*/
|
|
16
|
-
const tsxPlugins = pluginsPath.reduce((acc, curr) => {
|
|
17
|
-
const dirPaths = curr.split(sep);
|
|
18
|
-
|
|
19
|
-
const nodeModulePathIndex = dirPaths.findIndex((val) => val === NODE_MODULES);
|
|
20
|
-
|
|
21
|
-
if (nodeModulePathIndex > 0) {
|
|
22
|
-
const pluginNodeModulePath = dirPaths.slice(nodeModulePathIndex + 1);
|
|
23
|
-
return [...acc, join(...pluginNodeModulePath)];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return acc;
|
|
27
|
-
}, []);
|
|
28
|
-
|
|
29
9
|
/**
|
|
30
10
|
* If there aren't any plugins in the node_modules array, just return the node_modules regex
|
|
31
11
|
* without complicating it.
|
|
32
12
|
*/
|
|
33
|
-
if (
|
|
13
|
+
if (pluginsPath.length === 0) {
|
|
34
14
|
return /node_modules/;
|
|
35
15
|
}
|
|
36
16
|
|
|
37
|
-
return new RegExp(`${NODE_MODULES}/(?!(${
|
|
17
|
+
return new RegExp(`${NODE_MODULES}/(?!(${pluginsPath.join('|')}))`);
|
|
38
18
|
};
|
|
39
19
|
|
|
40
|
-
module.exports = createPluginsExcludePath;
|
|
20
|
+
module.exports = { createPluginsExcludePath };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { join, resolve, sep, posix } = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
6
|
+
const glob = require('glob');
|
|
7
|
+
|
|
8
|
+
const getPlugins = (pluginsAllowlist) => {
|
|
9
|
+
const rootPath = resolve(__dirname, '..', join('..', '..', '..', 'packages'));
|
|
10
|
+
/**
|
|
11
|
+
* So `glob` only supports '/' as a path separator, so we need to replace
|
|
12
|
+
* the path separator for the current OS with '/'. e.g. on windows it's `\`.
|
|
13
|
+
*
|
|
14
|
+
* see https://github.com/isaacs/node-glob/#windows for more information
|
|
15
|
+
*
|
|
16
|
+
* and see https://github.com/isaacs/node-glob/issues/467#issuecomment-1114240501 for the recommended fix.
|
|
17
|
+
*/
|
|
18
|
+
let corePath = join(rootPath, 'core', '*');
|
|
19
|
+
let pluginsPath = join(rootPath, 'plugins', '*');
|
|
20
|
+
|
|
21
|
+
if (process.platform === 'win32') {
|
|
22
|
+
corePath = corePath.split(sep).join(posix.sep);
|
|
23
|
+
pluginsPath = pluginsPath.split(sep).join(posix.sep);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const corePackageDirs = glob.sync(corePath);
|
|
27
|
+
const pluginsPackageDirs = glob.sync(pluginsPath);
|
|
28
|
+
|
|
29
|
+
const plugins = [...corePackageDirs, ...pluginsPackageDirs]
|
|
30
|
+
.map((directory) => {
|
|
31
|
+
const isCoreAdmin = directory.includes('packages/core/admin');
|
|
32
|
+
|
|
33
|
+
if (isCoreAdmin) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { name, strapi } = require(join(directory, 'package.json'));
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* this will remove any of our packages that are
|
|
41
|
+
* not actually plugins for the application
|
|
42
|
+
*/
|
|
43
|
+
if (!strapi) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* we want the name of the node_module
|
|
49
|
+
*/
|
|
50
|
+
return {
|
|
51
|
+
pathToPlugin: name,
|
|
52
|
+
name: strapi.name,
|
|
53
|
+
info: { ...strapi, packageName: name },
|
|
54
|
+
directory,
|
|
55
|
+
};
|
|
56
|
+
})
|
|
57
|
+
.filter((plugin) => {
|
|
58
|
+
if (!plugin) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* There are two ways a plugin should be imported, either it's local to the strapi app,
|
|
64
|
+
* or it's an actual npm module that's installed and resolved via node_modules.
|
|
65
|
+
*
|
|
66
|
+
* We first check if the plugin is local to the strapi app, using a regular `resolve` because
|
|
67
|
+
* the pathToPlugin will be relative i.e. `/Users/my-name/strapi-app/src/plugins/my-plugin`.
|
|
68
|
+
*
|
|
69
|
+
* If the file doesn't exist well then it's probably a node_module, so instead we use `require.resolve`
|
|
70
|
+
* which will resolve the path to the module in node_modules. If it fails with the specific code `MODULE_NOT_FOUND`
|
|
71
|
+
* then it doesn't have an admin part to the package.
|
|
72
|
+
*
|
|
73
|
+
* NOTE: we should try to move to `./package.json[exports]` map with bundling of our own plugins,
|
|
74
|
+
* because these entry files are written in commonjs restricting features e.g. tree-shaking.
|
|
75
|
+
*/
|
|
76
|
+
try {
|
|
77
|
+
const isLocalPluginWithLegacyAdminFile = fs.existsSync(
|
|
78
|
+
resolve(`${plugin.pathToPlugin}/strapi-admin.js`)
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
if (!isLocalPluginWithLegacyAdminFile) {
|
|
82
|
+
const isModulewithLegacyAdminFile = require.resolve(
|
|
83
|
+
`${plugin.pathToPlugin}/strapi-admin.js`
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return isModulewithLegacyAdminFile;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return isLocalPluginWithLegacyAdminFile;
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err.code === 'MODULE_NOT_FOUND') {
|
|
92
|
+
/**
|
|
93
|
+
* the plugin does not contain FE code, so we
|
|
94
|
+
* don't want to import it anyway
|
|
95
|
+
*/
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (Array.isArray(pluginsAllowlist)) {
|
|
104
|
+
return plugins.filter((plugin) => pluginsAllowlist.includes(plugin.pathToPlugin));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return plugins;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
module.exports = { getPlugins };
|