@strapi/plugin-users-permissions 0.0.0-00a3f69152eb918683ed5c05bfed9c45495c0a87
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 +1 -0
- package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
- package/admin/src/components/BoundRoute/index.js +72 -0
- package/admin/src/components/FormModal/Input/index.js +121 -0
- package/admin/src/components/FormModal/index.js +121 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +30 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +114 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +53 -0
- package/admin/src/components/Permissions/index.js +56 -0
- package/admin/src/components/Permissions/init.js +9 -0
- package/admin/src/components/Permissions/reducer.js +27 -0
- package/admin/src/components/Policies/index.js +60 -0
- package/admin/src/components/UsersPermissions/index.js +94 -0
- package/admin/src/components/UsersPermissions/init.js +10 -0
- package/admin/src/components/UsersPermissions/reducer.js +60 -0
- package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
- package/admin/src/hooks/index.js +5 -0
- package/admin/src/hooks/useFetchRole/index.js +64 -0
- package/admin/src/hooks/useFetchRole/reducer.js +31 -0
- package/admin/src/hooks/useForm/index.js +70 -0
- package/admin/src/hooks/useForm/reducer.js +40 -0
- package/admin/src/hooks/usePlugins/index.js +65 -0
- package/admin/src/hooks/usePlugins/init.js +5 -0
- package/admin/src/hooks/usePlugins/reducer.js +34 -0
- package/admin/src/hooks/useRolesList/index.js +63 -0
- package/admin/src/hooks/useRolesList/init.js +5 -0
- package/admin/src/hooks/useRolesList/reducer.js +31 -0
- package/admin/src/index.js +123 -0
- package/admin/src/pages/AdvancedSettings/index.js +238 -0
- package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
- package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
- package/admin/src/pages/AdvancedSettings/utils/schema.js +19 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +121 -0
- package/admin/src/pages/EmailTemplates/index.js +162 -0
- package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
- package/admin/src/pages/EmailTemplates/utils/schema.js +22 -0
- package/admin/src/pages/Providers/index.js +274 -0
- package/admin/src/pages/Providers/reducer.js +54 -0
- package/admin/src/pages/Providers/utils/api.js +21 -0
- package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
- package/admin/src/pages/Providers/utils/forms.js +244 -0
- package/admin/src/pages/Roles/CreatePage/index.js +177 -0
- package/admin/src/pages/Roles/CreatePage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/EditPage/index.js +190 -0
- package/admin/src/pages/Roles/EditPage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
- package/admin/src/pages/Roles/ListPage/index.js +216 -0
- package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
- package/admin/src/pages/Roles/ProtectedCreatePage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedEditPage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedListPage/index.js +15 -0
- package/admin/src/pages/Roles/index.js +27 -0
- package/admin/src/permissions.js +31 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/translations/ar.json +40 -0
- package/admin/src/translations/cs.json +46 -0
- package/admin/src/translations/de.json +58 -0
- package/admin/src/translations/dk.json +83 -0
- package/admin/src/translations/en.json +83 -0
- package/admin/src/translations/es.json +83 -0
- package/admin/src/translations/fr.json +46 -0
- package/admin/src/translations/id.json +58 -0
- package/admin/src/translations/it.json +58 -0
- package/admin/src/translations/ja.json +44 -0
- package/admin/src/translations/ko.json +83 -0
- package/admin/src/translations/ms.json +45 -0
- package/admin/src/translations/nl.json +44 -0
- package/admin/src/translations/pl.json +83 -0
- package/admin/src/translations/pt-BR.json +40 -0
- package/admin/src/translations/pt.json +44 -0
- package/admin/src/translations/ru.json +58 -0
- package/admin/src/translations/sk.json +46 -0
- package/admin/src/translations/sv.json +83 -0
- package/admin/src/translations/th.json +56 -0
- package/admin/src/translations/tr.json +44 -0
- package/admin/src/translations/uk.json +45 -0
- package/admin/src/translations/vi.json +46 -0
- package/admin/src/translations/zh-Hans.json +62 -0
- package/admin/src/translations/zh.json +83 -0
- package/admin/src/utils/axiosInstance.js +36 -0
- package/admin/src/utils/cleanPermissions.js +25 -0
- package/admin/src/utils/formatPluginName.js +26 -0
- package/admin/src/utils/formatPolicies.js +8 -0
- package/admin/src/utils/getRequestURL.js +5 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/admin/src/utils/index.js +5 -0
- package/documentation/content-api.yaml +870 -0
- package/jest.config.front.js +10 -0
- package/package.json +68 -0
- package/server/bootstrap/grant-config.js +123 -0
- package/server/bootstrap/index.js +133 -0
- package/server/bootstrap/users-permissions-actions.js +80 -0
- package/server/config.js +23 -0
- package/server/content-types/index.js +11 -0
- package/server/content-types/permission/index.js +34 -0
- package/server/content-types/role/index.js +51 -0
- package/server/content-types/user/index.js +72 -0
- package/server/content-types/user/schema-config.js +15 -0
- package/server/controllers/auth.js +410 -0
- package/server/controllers/content-manager-user.js +175 -0
- package/server/controllers/index.js +17 -0
- package/server/controllers/permissions.js +26 -0
- package/server/controllers/role.js +77 -0
- package/server/controllers/settings.js +85 -0
- package/server/controllers/user.js +198 -0
- package/server/controllers/validation/auth.js +57 -0
- package/server/controllers/validation/email-template.js +50 -0
- package/server/controllers/validation/user.js +59 -0
- package/server/graphql/index.js +44 -0
- package/server/graphql/mutations/auth/change-password.js +38 -0
- package/server/graphql/mutations/auth/email-confirmation.js +39 -0
- package/server/graphql/mutations/auth/forgot-password.js +35 -0
- package/server/graphql/mutations/auth/login.js +35 -0
- package/server/graphql/mutations/auth/register.js +36 -0
- package/server/graphql/mutations/auth/reset-password.js +38 -0
- package/server/graphql/mutations/crud/role/create-role.js +34 -0
- package/server/graphql/mutations/crud/role/delete-role.js +25 -0
- package/server/graphql/mutations/crud/role/update-role.js +35 -0
- package/server/graphql/mutations/crud/user/create-user.js +45 -0
- package/server/graphql/mutations/crud/user/delete-user.js +39 -0
- package/server/graphql/mutations/crud/user/update-user.js +46 -0
- package/server/graphql/mutations/index.js +43 -0
- package/server/graphql/queries/index.js +13 -0
- package/server/graphql/queries/me.js +17 -0
- package/server/graphql/resolvers-configs.js +42 -0
- package/server/graphql/types/create-role-payload.js +11 -0
- package/server/graphql/types/delete-role-payload.js +11 -0
- package/server/graphql/types/index.js +21 -0
- package/server/graphql/types/login-input.js +13 -0
- package/server/graphql/types/login-payload.js +12 -0
- package/server/graphql/types/me-role.js +14 -0
- package/server/graphql/types/me.js +16 -0
- package/server/graphql/types/password-payload.js +11 -0
- package/server/graphql/types/register-input.js +13 -0
- package/server/graphql/types/update-role-payload.js +11 -0
- package/server/graphql/utils.js +27 -0
- package/server/index.js +21 -0
- package/server/middlewares/index.js +7 -0
- package/server/middlewares/rateLimit.js +27 -0
- package/server/register.js +23 -0
- package/server/routes/admin/index.js +10 -0
- package/server/routes/admin/permissions.js +20 -0
- package/server/routes/admin/role.js +79 -0
- package/server/routes/admin/settings.js +95 -0
- package/server/routes/content-api/auth.js +82 -0
- package/server/routes/content-api/index.js +11 -0
- package/server/routes/content-api/permissions.js +9 -0
- package/server/routes/content-api/role.js +29 -0
- package/server/routes/content-api/user.js +60 -0
- package/server/routes/index.js +6 -0
- package/server/services/index.js +19 -0
- package/server/services/jwt.js +55 -0
- package/server/services/permission.js +45 -0
- package/server/services/providers-registry.js +292 -0
- package/server/services/providers.js +115 -0
- package/server/services/role.js +177 -0
- package/server/services/user.js +140 -0
- package/server/services/users-permissions.js +236 -0
- package/server/strategies/users-permissions.js +114 -0
- package/server/utils/index.d.ts +18 -0
- package/server/utils/index.js +12 -0
- package/server/utils/sanitize/index.js +9 -0
- package/server/utils/sanitize/sanitizers.js +19 -0
- package/server/utils/sanitize/visitors/index.js +5 -0
- package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +11 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* User.js service
|
|
5
|
+
*
|
|
6
|
+
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
const bcrypt = require('bcryptjs');
|
|
11
|
+
const urlJoin = require('url-join');
|
|
12
|
+
|
|
13
|
+
const { getAbsoluteAdminUrl, getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
|
|
14
|
+
const { getService } = require('../utils');
|
|
15
|
+
|
|
16
|
+
module.exports = ({ strapi }) => ({
|
|
17
|
+
/**
|
|
18
|
+
* Promise to count users
|
|
19
|
+
*
|
|
20
|
+
* @return {Promise}
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
count(params) {
|
|
24
|
+
return strapi.query('plugin::users-permissions.user').count({ where: params });
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Promise to search count users
|
|
29
|
+
*
|
|
30
|
+
* @return {Promise}
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Promise to add a/an user.
|
|
35
|
+
* @return {Promise}
|
|
36
|
+
*/
|
|
37
|
+
async add(values) {
|
|
38
|
+
return strapi.entityService.create('plugin::users-permissions.user', {
|
|
39
|
+
data: values,
|
|
40
|
+
populate: ['role'],
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Promise to edit a/an user.
|
|
46
|
+
* @param {string} userId
|
|
47
|
+
* @param {object} params
|
|
48
|
+
* @return {Promise}
|
|
49
|
+
*/
|
|
50
|
+
async edit(userId, params = {}) {
|
|
51
|
+
return strapi.entityService.update('plugin::users-permissions.user', userId, {
|
|
52
|
+
data: params,
|
|
53
|
+
populate: ['role'],
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Promise to fetch a/an user.
|
|
59
|
+
* @return {Promise}
|
|
60
|
+
*/
|
|
61
|
+
fetch(id, params) {
|
|
62
|
+
return strapi.entityService.findOne('plugin::users-permissions.user', id, params);
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Promise to fetch authenticated user.
|
|
67
|
+
* @return {Promise}
|
|
68
|
+
*/
|
|
69
|
+
fetchAuthenticatedUser(id) {
|
|
70
|
+
return strapi
|
|
71
|
+
.query('plugin::users-permissions.user')
|
|
72
|
+
.findOne({ where: { id }, populate: ['role'] });
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Promise to fetch all users.
|
|
77
|
+
* @return {Promise}
|
|
78
|
+
*/
|
|
79
|
+
fetchAll(params) {
|
|
80
|
+
return strapi.entityService.findMany('plugin::users-permissions.user', params);
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Promise to remove a/an user.
|
|
85
|
+
* @return {Promise}
|
|
86
|
+
*/
|
|
87
|
+
async remove(params) {
|
|
88
|
+
return strapi.query('plugin::users-permissions.user').delete({ where: params });
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
validatePassword(password, hash) {
|
|
92
|
+
return bcrypt.compare(password, hash);
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
async sendConfirmationEmail(user) {
|
|
96
|
+
const userPermissionService = getService('users-permissions');
|
|
97
|
+
const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
|
|
98
|
+
const userSchema = strapi.getModel('plugin::users-permissions.user');
|
|
99
|
+
|
|
100
|
+
const settings = await pluginStore
|
|
101
|
+
.get({ key: 'email' })
|
|
102
|
+
.then((storeEmail) => storeEmail.email_confirmation.options);
|
|
103
|
+
|
|
104
|
+
// Sanitize the template's user information
|
|
105
|
+
const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(userSchema, user);
|
|
106
|
+
|
|
107
|
+
const confirmationToken = crypto.randomBytes(20).toString('hex');
|
|
108
|
+
|
|
109
|
+
await this.edit(user.id, { confirmationToken });
|
|
110
|
+
|
|
111
|
+
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
112
|
+
settings.message = await userPermissionService.template(settings.message, {
|
|
113
|
+
URL: urlJoin(getAbsoluteServerUrl(strapi.config), apiPrefix, '/auth/email-confirmation'),
|
|
114
|
+
SERVER_URL: getAbsoluteServerUrl(strapi.config),
|
|
115
|
+
ADMIN_URL: getAbsoluteAdminUrl(strapi.config),
|
|
116
|
+
USER: sanitizedUserInfo,
|
|
117
|
+
CODE: confirmationToken,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
settings.object = await userPermissionService.template(settings.object, {
|
|
121
|
+
USER: sanitizedUserInfo,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Send an email to the user.
|
|
125
|
+
await strapi
|
|
126
|
+
.plugin('email')
|
|
127
|
+
.service('email')
|
|
128
|
+
.send({
|
|
129
|
+
to: user.email,
|
|
130
|
+
from:
|
|
131
|
+
settings.from.email && settings.from.name
|
|
132
|
+
? `${settings.from.name} <${settings.from.email}>`
|
|
133
|
+
: undefined,
|
|
134
|
+
replyTo: settings.response_email,
|
|
135
|
+
subject: settings.object,
|
|
136
|
+
text: settings.message,
|
|
137
|
+
html: settings.message,
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
});
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { filter, map, pipe, prop } = require('lodash/fp');
|
|
5
|
+
const urlJoin = require('url-join');
|
|
6
|
+
|
|
7
|
+
const { getService } = require('../utils');
|
|
8
|
+
|
|
9
|
+
const DEFAULT_PERMISSIONS = [
|
|
10
|
+
{ action: 'plugin::users-permissions.auth.callback', roleType: 'public' },
|
|
11
|
+
{ action: 'plugin::users-permissions.auth.connect', roleType: 'public' },
|
|
12
|
+
{ action: 'plugin::users-permissions.auth.forgotPassword', roleType: 'public' },
|
|
13
|
+
{ action: 'plugin::users-permissions.auth.resetPassword', roleType: 'public' },
|
|
14
|
+
{ action: 'plugin::users-permissions.auth.register', roleType: 'public' },
|
|
15
|
+
{ action: 'plugin::users-permissions.auth.emailConfirmation', roleType: 'public' },
|
|
16
|
+
{ action: 'plugin::users-permissions.auth.sendEmailConfirmation', roleType: 'public' },
|
|
17
|
+
{ action: 'plugin::users-permissions.user.me', roleType: 'authenticated' },
|
|
18
|
+
{ action: 'plugin::users-permissions.auth.changePassword', roleType: 'authenticated' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const transformRoutePrefixFor = (pluginName) => (route) => {
|
|
22
|
+
const prefix = route.config && route.config.prefix;
|
|
23
|
+
const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
...route,
|
|
27
|
+
path,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = ({ strapi }) => ({
|
|
32
|
+
getActions({ defaultEnable = false } = {}) {
|
|
33
|
+
const actionMap = {};
|
|
34
|
+
|
|
35
|
+
const isContentApi = (action) => {
|
|
36
|
+
if (!_.has(action, Symbol.for('__type__'))) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return action[Symbol.for('__type__')].includes('content-api');
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
44
|
+
const controllers = _.reduce(
|
|
45
|
+
api.controllers,
|
|
46
|
+
(acc, controller, controllerName) => {
|
|
47
|
+
const contentApiActions = _.pickBy(controller, isContentApi);
|
|
48
|
+
|
|
49
|
+
if (_.isEmpty(contentApiActions)) {
|
|
50
|
+
return acc;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
acc[controllerName] = _.mapValues(contentApiActions, () => {
|
|
54
|
+
return {
|
|
55
|
+
enabled: defaultEnable,
|
|
56
|
+
policy: '',
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return acc;
|
|
61
|
+
},
|
|
62
|
+
{}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (!_.isEmpty(controllers)) {
|
|
66
|
+
actionMap[`api::${apiName}`] = { controllers };
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
71
|
+
const controllers = _.reduce(
|
|
72
|
+
plugin.controllers,
|
|
73
|
+
(acc, controller, controllerName) => {
|
|
74
|
+
const contentApiActions = _.pickBy(controller, isContentApi);
|
|
75
|
+
|
|
76
|
+
if (_.isEmpty(contentApiActions)) {
|
|
77
|
+
return acc;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
acc[controllerName] = _.mapValues(contentApiActions, () => {
|
|
81
|
+
return {
|
|
82
|
+
enabled: defaultEnable,
|
|
83
|
+
policy: '',
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return acc;
|
|
88
|
+
},
|
|
89
|
+
{}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (!_.isEmpty(controllers)) {
|
|
93
|
+
actionMap[`plugin::${pluginName}`] = { controllers };
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return actionMap;
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
async getRoutes() {
|
|
101
|
+
const routesMap = {};
|
|
102
|
+
|
|
103
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
104
|
+
const routes = _.flatMap(api.routes, (route) => {
|
|
105
|
+
if (_.has(route, 'routes')) {
|
|
106
|
+
return route.routes;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return route;
|
|
110
|
+
}).filter((route) => route.info.type === 'content-api');
|
|
111
|
+
|
|
112
|
+
if (routes.length === 0) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
117
|
+
routesMap[`api::${apiName}`] = routes.map((route) => ({
|
|
118
|
+
...route,
|
|
119
|
+
path: urlJoin(apiPrefix, route.path),
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
124
|
+
const transformPrefix = transformRoutePrefixFor(pluginName);
|
|
125
|
+
|
|
126
|
+
const routes = _.flatMap(plugin.routes, (route) => {
|
|
127
|
+
if (_.has(route, 'routes')) {
|
|
128
|
+
return route.routes.map(transformPrefix);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return transformPrefix(route);
|
|
132
|
+
}).filter((route) => route.info.type === 'content-api');
|
|
133
|
+
|
|
134
|
+
if (routes.length === 0) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
139
|
+
routesMap[`plugin::${pluginName}`] = routes.map((route) => ({
|
|
140
|
+
...route,
|
|
141
|
+
path: urlJoin(apiPrefix, route.path),
|
|
142
|
+
}));
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return routesMap;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
async syncPermissions() {
|
|
149
|
+
const roles = await strapi.query('plugin::users-permissions.role').findMany();
|
|
150
|
+
const dbPermissions = await strapi.query('plugin::users-permissions.permission').findMany();
|
|
151
|
+
|
|
152
|
+
const permissionsFoundInDB = _.uniq(_.map(dbPermissions, 'action'));
|
|
153
|
+
|
|
154
|
+
const appActions = _.flatMap(strapi.api, (api, apiName) => {
|
|
155
|
+
return _.flatMap(api.controllers, (controller, controllerName) => {
|
|
156
|
+
return _.keys(controller).map((actionName) => {
|
|
157
|
+
return `api::${apiName}.${controllerName}.${actionName}`;
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const pluginsActions = _.flatMap(strapi.plugins, (plugin, pluginName) => {
|
|
163
|
+
return _.flatMap(plugin.controllers, (controller, controllerName) => {
|
|
164
|
+
return _.keys(controller).map((actionName) => {
|
|
165
|
+
return `plugin::${pluginName}.${controllerName}.${actionName}`;
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const allActions = [...appActions, ...pluginsActions];
|
|
171
|
+
|
|
172
|
+
const toDelete = _.difference(permissionsFoundInDB, allActions);
|
|
173
|
+
|
|
174
|
+
await Promise.all(
|
|
175
|
+
toDelete.map((action) => {
|
|
176
|
+
return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (permissionsFoundInDB.length === 0) {
|
|
181
|
+
// create default permissions
|
|
182
|
+
for (const role of roles) {
|
|
183
|
+
const toCreate = pipe(
|
|
184
|
+
filter(({ roleType }) => roleType === role.type || roleType === null),
|
|
185
|
+
map(prop('action'))
|
|
186
|
+
)(DEFAULT_PERMISSIONS);
|
|
187
|
+
|
|
188
|
+
await Promise.all(
|
|
189
|
+
toCreate.map((action) => {
|
|
190
|
+
return strapi.query('plugin::users-permissions.permission').create({
|
|
191
|
+
data: {
|
|
192
|
+
action,
|
|
193
|
+
role: role.id,
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
async initialize() {
|
|
203
|
+
const roleCount = await strapi.query('plugin::users-permissions.role').count();
|
|
204
|
+
|
|
205
|
+
if (roleCount === 0) {
|
|
206
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
207
|
+
data: {
|
|
208
|
+
name: 'Authenticated',
|
|
209
|
+
description: 'Default role given to authenticated user.',
|
|
210
|
+
type: 'authenticated',
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
215
|
+
data: {
|
|
216
|
+
name: 'Public',
|
|
217
|
+
description: 'Default role given to unauthenticated user.',
|
|
218
|
+
type: 'public',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return getService('users-permissions').syncPermissions();
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
async updateUserRole(user, role) {
|
|
227
|
+
return strapi
|
|
228
|
+
.query('plugin::users-permissions.user')
|
|
229
|
+
.update({ where: { id: user.id }, data: { role } });
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
template(layout, data) {
|
|
233
|
+
const compiledObject = _.template(layout);
|
|
234
|
+
return compiledObject(data);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { castArray, map, every, pipe } = require('lodash/fp');
|
|
4
|
+
const { ForbiddenError, UnauthorizedError } = require('@strapi/utils').errors;
|
|
5
|
+
|
|
6
|
+
const { getService } = require('../utils');
|
|
7
|
+
|
|
8
|
+
const getAdvancedSettings = () => {
|
|
9
|
+
return strapi.store({ type: 'plugin', name: 'users-permissions' }).get({ key: 'advanced' });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const authenticate = async (ctx) => {
|
|
13
|
+
try {
|
|
14
|
+
const token = await getService('jwt').getToken(ctx);
|
|
15
|
+
|
|
16
|
+
if (token) {
|
|
17
|
+
const { id } = token;
|
|
18
|
+
|
|
19
|
+
// Invalid token
|
|
20
|
+
if (id === undefined) {
|
|
21
|
+
return { authenticated: false };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const user = await getService('user').fetchAuthenticatedUser(id);
|
|
25
|
+
|
|
26
|
+
// No user associated to the token
|
|
27
|
+
if (!user) {
|
|
28
|
+
return { error: 'Invalid credentials' };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const advancedSettings = await getAdvancedSettings();
|
|
32
|
+
|
|
33
|
+
// User not confirmed
|
|
34
|
+
if (advancedSettings.email_confirmation && !user.confirmed) {
|
|
35
|
+
return { error: 'Invalid credentials' };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// User blocked
|
|
39
|
+
if (user.blocked) {
|
|
40
|
+
return { error: 'Invalid credentials' };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fetch user's permissions
|
|
44
|
+
const permissions = await Promise.resolve(user.role.id)
|
|
45
|
+
.then(getService('permission').findRolePermissions)
|
|
46
|
+
.then(map(getService('permission').toContentAPIPermission));
|
|
47
|
+
|
|
48
|
+
// Generate an ability (content API engine) based on the given permissions
|
|
49
|
+
const ability = await strapi.contentAPI.permissions.engine.generateAbility(permissions);
|
|
50
|
+
|
|
51
|
+
ctx.state.user = user;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
authenticated: true,
|
|
55
|
+
credentials: user,
|
|
56
|
+
ability,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const publicPermissions = await getService('permission')
|
|
61
|
+
.findPublicPermissions()
|
|
62
|
+
.then(map(getService('permission').toContentAPIPermission));
|
|
63
|
+
|
|
64
|
+
if (publicPermissions.length === 0) {
|
|
65
|
+
return { authenticated: false };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const ability = await strapi.contentAPI.permissions.engine.generateAbility(publicPermissions);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
authenticated: true,
|
|
72
|
+
credentials: null,
|
|
73
|
+
ability,
|
|
74
|
+
};
|
|
75
|
+
} catch (err) {
|
|
76
|
+
return { authenticated: false };
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const verify = async (auth, config) => {
|
|
81
|
+
const { credentials: user, ability } = auth;
|
|
82
|
+
|
|
83
|
+
if (!config.scope) {
|
|
84
|
+
if (!user) {
|
|
85
|
+
// A non authenticated user cannot access routes that do not have a scope
|
|
86
|
+
throw new UnauthorizedError();
|
|
87
|
+
} else {
|
|
88
|
+
// An authenticated user can access non scoped routes
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If no ability have been generated, then consider auth is missing
|
|
94
|
+
if (!ability) {
|
|
95
|
+
throw new UnauthorizedError();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const isAllowed = pipe(
|
|
99
|
+
// Make sure we're dealing with an array
|
|
100
|
+
castArray,
|
|
101
|
+
// Transform the scope array into an action array
|
|
102
|
+
every((scope) => ability.can(scope))
|
|
103
|
+
)(config.scope);
|
|
104
|
+
|
|
105
|
+
if (!isAllowed) {
|
|
106
|
+
throw new ForbiddenError();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
name: 'users-permissions',
|
|
112
|
+
authenticate,
|
|
113
|
+
verify,
|
|
114
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as usersPermissions from '../services/users-permissions';
|
|
2
|
+
import * as user from '../services/user';
|
|
3
|
+
import * as role from '../services/role';
|
|
4
|
+
import * as jwt from '../services/jwt';
|
|
5
|
+
import * as providers from '../services/providers';
|
|
6
|
+
import * as permission from '../services/permission';
|
|
7
|
+
|
|
8
|
+
type S = {
|
|
9
|
+
['users-permissions']: typeof usersPermissions;
|
|
10
|
+
['role']: typeof role;
|
|
11
|
+
user: typeof user;
|
|
12
|
+
jwt: typeof jwt;
|
|
13
|
+
providers: typeof providers;
|
|
14
|
+
['providers-registry']: typeof providers;
|
|
15
|
+
permission: typeof permission;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function getService<T extends keyof S>(name: T): ReturnType<S[T]>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { curry } = require('lodash/fp');
|
|
4
|
+
const { traverseEntity, pipeAsync } = require('@strapi/utils');
|
|
5
|
+
|
|
6
|
+
const { removeUserRelationFromRoleEntities } = require('./visitors');
|
|
7
|
+
|
|
8
|
+
const sanitizeUserRelationFromRoleEntities = curry((schema, entity) => {
|
|
9
|
+
return traverseEntity(removeUserRelationFromRoleEntities, { schema }, entity);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const defaultSanitizeOutput = curry((schema, entity) => {
|
|
13
|
+
return pipeAsync(sanitizeUserRelationFromRoleEntities(schema))(entity);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
sanitizeUserRelationFromRoleEntities,
|
|
18
|
+
defaultSanitizeOutput,
|
|
19
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = ({ schema, key, attribute }, { remove }) => {
|
|
4
|
+
if (
|
|
5
|
+
attribute.type === 'relation' &&
|
|
6
|
+
attribute.target === 'plugin::users-permissions.user' &&
|
|
7
|
+
schema.uid === 'plugin::users-permissions.role'
|
|
8
|
+
) {
|
|
9
|
+
remove(key);
|
|
10
|
+
}
|
|
11
|
+
};
|
package/strapi-admin.js
ADDED
package/strapi-server.js
ADDED