@strapi/plugin-users-permissions 4.0.0-next.6 → 4.0.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/BoundRoute/getMethodColor.js +41 -0
- package/admin/src/components/BoundRoute/index.js +40 -24
- package/admin/src/components/FormModal/Input/index.js +121 -0
- package/admin/src/components/FormModal/index.js +123 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +19 -26
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +118 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +9 -48
- package/admin/src/components/Permissions/index.js +36 -24
- package/admin/src/components/Permissions/init.js +1 -6
- package/admin/src/components/Policies/index.js +46 -47
- package/admin/src/components/UsersPermissions/index.js +29 -26
- package/admin/src/components/UsersPermissions/init.js +1 -2
- package/admin/src/hooks/useFetchRole/index.js +17 -7
- package/admin/src/hooks/useForm/index.js +3 -29
- package/admin/src/hooks/useForm/reducer.js +2 -21
- package/admin/src/hooks/usePlugins/index.js +12 -21
- package/admin/src/hooks/usePlugins/reducer.js +0 -3
- package/admin/src/index.js +29 -34
- package/admin/src/pages/AdvancedSettings/index.js +210 -193
- 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 +22 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +116 -0
- package/admin/src/pages/EmailTemplates/index.js +125 -198
- package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
- package/admin/src/pages/Providers/index.js +208 -216
- package/admin/src/pages/Providers/utils/api.js +21 -0
- package/admin/src/pages/Providers/utils/forms.js +168 -126
- package/admin/src/pages/Roles/CreatePage/index.js +155 -147
- package/admin/src/pages/Roles/EditPage/index.js +162 -134
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
- package/admin/src/pages/Roles/ListPage/index.js +176 -156
- package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
- package/admin/src/pages/Roles/index.js +14 -8
- package/admin/src/permissions.js +12 -14
- package/admin/src/translations/ar.json +0 -8
- package/admin/src/translations/cs.json +0 -8
- package/admin/src/translations/de.json +0 -8
- package/admin/src/translations/dk.json +0 -8
- package/admin/src/translations/en.json +33 -12
- package/admin/src/translations/es.json +0 -8
- package/admin/src/translations/fr.json +0 -8
- package/admin/src/translations/id.json +0 -8
- package/admin/src/translations/it.json +0 -8
- package/admin/src/translations/ja.json +0 -8
- package/admin/src/translations/ko.json +0 -8
- package/admin/src/translations/ms.json +0 -8
- package/admin/src/translations/nl.json +0 -8
- package/admin/src/translations/pl.json +0 -8
- package/admin/src/translations/pt-BR.json +0 -8
- package/admin/src/translations/pt.json +0 -8
- package/admin/src/translations/ru.json +0 -8
- package/admin/src/translations/sk.json +0 -8
- package/admin/src/translations/sv.json +0 -8
- package/admin/src/translations/th.json +0 -8
- package/admin/src/translations/tr.json +0 -8
- package/admin/src/translations/uk.json +0 -8
- package/admin/src/translations/vi.json +0 -8
- package/admin/src/translations/zh-Hans.json +5 -14
- package/admin/src/translations/zh.json +0 -8
- package/admin/src/utils/axiosInstance.js +36 -0
- package/admin/src/utils/formatPluginName.js +26 -0
- package/admin/src/utils/index.js +1 -0
- package/documentation/1.0.0/overrides/users-permissions-Role.json +6 -6
- package/documentation/1.0.0/overrides/users-permissions-User.json +7 -7
- package/package.json +30 -29
- package/{config/functions/bootstrap.js → server/bootstrap/index.js} +26 -33
- package/{config → server/bootstrap}/users-permissions-actions.js +0 -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/{models/User.config.js → server/content-types/user/schema-config.js} +0 -0
- package/server/controllers/auth.js +440 -0
- package/server/controllers/content-manager-user.js +183 -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 +191 -0
- package/server/controllers/validation/auth.js +29 -0
- package/{controllers → server/controllers}/validation/email-template.js +0 -0
- package/server/controllers/validation/user.js +38 -0
- package/server/graphql/index.js +44 -0
- package/server/graphql/mutations/auth/email-confirmation.js +39 -0
- package/server/graphql/mutations/auth/forgot-password.js +38 -0
- package/server/graphql/mutations/auth/login.js +38 -0
- package/server/graphql/mutations/auth/register.js +39 -0
- package/server/graphql/mutations/auth/reset-password.js +41 -0
- package/server/graphql/mutations/crud/role/create-role.js +37 -0
- package/server/graphql/mutations/crud/role/delete-role.js +28 -0
- package/server/graphql/mutations/crud/role/update-role.js +38 -0
- package/server/graphql/mutations/crud/user/create-user.js +48 -0
- package/server/graphql/mutations/crud/user/delete-user.js +42 -0
- package/server/graphql/mutations/crud/user/update-user.js +49 -0
- package/server/graphql/mutations/index.js +42 -0
- package/server/graphql/queries/index.js +13 -0
- package/server/graphql/queries/me.js +17 -0
- package/server/graphql/resolvers-configs.js +37 -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/{config/policies → server/middlewares}/rateLimit.js +4 -8
- package/server/register.js +11 -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 +73 -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 +61 -0
- package/server/routes/index.js +6 -0
- package/server/services/index.js +15 -0
- package/server/services/jwt.js +55 -0
- package/server/services/providers.js +599 -0
- package/server/services/role.js +177 -0
- package/{services → server/services}/user.js +32 -35
- package/server/services/users-permissions.js +233 -0
- package/server/strategies/users-permissions.js +123 -0
- package/{utils → server/utils}/index.d.ts +6 -1
- package/server/utils/index.js +9 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
- package/admin/src/assets/images/logo.svg +0 -1
- package/admin/src/components/BaselineAlignement/index.js +0 -33
- package/admin/src/components/Bloc/index.js +0 -10
- package/admin/src/components/BoundRoute/Components.js +0 -78
- package/admin/src/components/ContainerFluid/index.js +0 -13
- package/admin/src/components/FormBloc/index.js +0 -61
- package/admin/src/components/IntlInput/index.js +0 -38
- package/admin/src/components/ListBaselineAlignment/index.js +0 -8
- package/admin/src/components/ListRow/Components.js +0 -74
- package/admin/src/components/ListRow/index.js +0 -35
- package/admin/src/components/ModalForm/Wrapper.js +0 -12
- package/admin/src/components/ModalForm/index.js +0 -59
- package/admin/src/components/Permissions/ListWrapper.js +0 -9
- package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +0 -7
- package/admin/src/components/Permissions/PermissionRow/RowStyle.js +0 -28
- package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +0 -13
- package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +0 -8
- package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +0 -26
- package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +0 -116
- package/admin/src/components/Policies/Components.js +0 -26
- package/admin/src/components/PrefixedIcon/index.js +0 -27
- package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +0 -7
- package/admin/src/components/Roles/EmptyRole/index.js +0 -27
- package/admin/src/components/Roles/RoleListWrapper/index.js +0 -17
- package/admin/src/components/Roles/RoleRow/RoleDescription.js +0 -9
- package/admin/src/components/Roles/RoleRow/index.js +0 -45
- package/admin/src/components/Roles/index.js +0 -3
- package/admin/src/components/SizedInput/index.js +0 -24
- package/admin/src/pages/AdvancedSettings/reducer.js +0 -65
- package/admin/src/pages/AdvancedSettings/utils/form.js +0 -52
- package/admin/src/pages/EmailTemplates/CustomTextInput.js +0 -105
- package/admin/src/pages/EmailTemplates/Wrapper.js +0 -36
- package/admin/src/pages/EmailTemplates/reducer.js +0 -58
- package/admin/src/pages/EmailTemplates/utils/forms.js +0 -81
- package/admin/src/pages/Roles/ListPage/BaselineAlignment.js +0 -8
- package/config/layout.js +0 -10
- package/config/policies/isAuthenticated.js +0 -9
- package/config/policies/permissions.js +0 -94
- package/config/request.json +0 -6
- package/config/routes.json +0 -381
- package/config/schema.graphql.js +0 -284
- package/config/security.json +0 -5
- package/controllers/auth.js +0 -596
- package/controllers/user/admin.js +0 -230
- package/controllers/user/api.js +0 -174
- package/controllers/user.js +0 -117
- package/controllers/users-permissions.js +0 -271
- package/middlewares/users-permissions/defaults.json +0 -5
- package/middlewares/users-permissions/index.js +0 -40
- package/models/Permission.js +0 -7
- package/models/Permission.settings.json +0 -45
- package/models/Role.js +0 -7
- package/models/Role.settings.json +0 -43
- package/models/User.js +0 -7
- package/models/User.settings.json +0 -63
- package/services/jwt.js +0 -65
- package/services/providers.js +0 -598
- package/services/users-permissions.js +0 -429
- package/utils/index.js +0 -11
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { NotFoundError } = require('@strapi/utils').errors;
|
|
5
|
+
const { getService } = require('../utils');
|
|
6
|
+
|
|
7
|
+
module.exports = ({ strapi }) => ({
|
|
8
|
+
async createRole(params) {
|
|
9
|
+
if (!params.type) {
|
|
10
|
+
params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const role = await strapi
|
|
14
|
+
.query('plugin::users-permissions.role')
|
|
15
|
+
.create({ data: _.omit(params, ['users', 'permissions']) });
|
|
16
|
+
|
|
17
|
+
const createPromises = _.flatMap(params.permissions, (type, typeName) => {
|
|
18
|
+
return _.flatMap(type.controllers, (controller, controllerName) => {
|
|
19
|
+
return _.reduce(
|
|
20
|
+
controller,
|
|
21
|
+
(acc, action, actionName) => {
|
|
22
|
+
const { enabled /* policy */ } = action;
|
|
23
|
+
|
|
24
|
+
if (enabled) {
|
|
25
|
+
const actionID = `${typeName}.${controllerName}.${actionName}`;
|
|
26
|
+
|
|
27
|
+
acc.push(
|
|
28
|
+
strapi
|
|
29
|
+
.query('plugin::users-permissions.permission')
|
|
30
|
+
.create({ data: { action: actionID, role: role.id } })
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return acc;
|
|
35
|
+
},
|
|
36
|
+
[]
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await Promise.all(createPromises);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
async getRole(roleID) {
|
|
45
|
+
const role = await strapi
|
|
46
|
+
.query('plugin::users-permissions.role')
|
|
47
|
+
.findOne({ where: { id: roleID }, populate: ['permissions'] });
|
|
48
|
+
|
|
49
|
+
if (!role) {
|
|
50
|
+
throw new NotFoundError('Role not found');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const allActions = getService('users-permissions').getActions();
|
|
54
|
+
|
|
55
|
+
// Group by `type`.
|
|
56
|
+
role.permissions.forEach(permission => {
|
|
57
|
+
const [type, controller, action] = permission.action.split('.');
|
|
58
|
+
|
|
59
|
+
_.set(allActions, `${type}.controllers.${controller}.${action}`, {
|
|
60
|
+
enabled: true,
|
|
61
|
+
policy: '',
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...role,
|
|
67
|
+
permissions: allActions,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
async getRoles() {
|
|
72
|
+
const roles = await strapi.query('plugin::users-permissions.role').findMany({ sort: ['name'] });
|
|
73
|
+
|
|
74
|
+
for (const role of roles) {
|
|
75
|
+
role.nb_users = await strapi
|
|
76
|
+
.query('plugin::users-permissions.user')
|
|
77
|
+
.count({ where: { role: { id: role.id } } });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return roles;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
async updateRole(roleID, data) {
|
|
84
|
+
const role = await strapi
|
|
85
|
+
.query('plugin::users-permissions.role')
|
|
86
|
+
.findOne({ where: { id: roleID }, populate: ['permissions'] });
|
|
87
|
+
|
|
88
|
+
if (!role) {
|
|
89
|
+
throw new NotFoundError('Role not found');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await strapi.query('plugin::users-permissions.role').update({
|
|
93
|
+
where: { id: roleID },
|
|
94
|
+
data: _.pick(data, ['name', 'description']),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const { permissions } = data;
|
|
98
|
+
|
|
99
|
+
const newActions = _.flatMap(permissions, (type, typeName) => {
|
|
100
|
+
return _.flatMap(type.controllers, (controller, controllerName) => {
|
|
101
|
+
return _.reduce(
|
|
102
|
+
controller,
|
|
103
|
+
(acc, action, actionName) => {
|
|
104
|
+
const { enabled /* policy */ } = action;
|
|
105
|
+
|
|
106
|
+
if (enabled) {
|
|
107
|
+
acc.push(`${typeName}.${controllerName}.${actionName}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return acc;
|
|
111
|
+
},
|
|
112
|
+
[]
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const oldActions = role.permissions.map(({ action }) => action);
|
|
118
|
+
|
|
119
|
+
const toDelete = role.permissions.reduce((acc, permission) => {
|
|
120
|
+
if (!newActions.includes(permission.action)) {
|
|
121
|
+
acc.push(permission);
|
|
122
|
+
}
|
|
123
|
+
return acc;
|
|
124
|
+
}, []);
|
|
125
|
+
|
|
126
|
+
const toCreate = newActions
|
|
127
|
+
.filter(action => !oldActions.includes(action))
|
|
128
|
+
.map(action => ({ action, role: role.id }));
|
|
129
|
+
|
|
130
|
+
await Promise.all(
|
|
131
|
+
toDelete.map(permission =>
|
|
132
|
+
strapi
|
|
133
|
+
.query('plugin::users-permissions.permission')
|
|
134
|
+
.delete({ where: { id: permission.id } })
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
await Promise.all(
|
|
139
|
+
toCreate.map(permissionInfo =>
|
|
140
|
+
strapi.query('plugin::users-permissions.permission').create({ data: permissionInfo })
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
async deleteRole(roleID, publicRoleID) {
|
|
146
|
+
const role = await strapi
|
|
147
|
+
.query('plugin::users-permissions.role')
|
|
148
|
+
.findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
|
|
149
|
+
|
|
150
|
+
if (!role) {
|
|
151
|
+
throw new NotFoundError('Role not found');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Move users to guest role.
|
|
155
|
+
await Promise.all(
|
|
156
|
+
role.users.map(user => {
|
|
157
|
+
return strapi.query('plugin::users-permissions.user').update({
|
|
158
|
+
where: { id: user.id },
|
|
159
|
+
data: { role: publicRoleID },
|
|
160
|
+
});
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Remove permissions related to this role.
|
|
165
|
+
// TODO: use delete many
|
|
166
|
+
await Promise.all(
|
|
167
|
+
role.permissions.map(permission => {
|
|
168
|
+
return strapi.query('plugin::users-permissions.permission').delete({
|
|
169
|
+
where: { id: permission.id },
|
|
170
|
+
});
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Delete the role.
|
|
175
|
+
await strapi.query('plugin::users-permissions.role').delete({ where: { id: roleID } });
|
|
176
|
+
},
|
|
177
|
+
});
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
const crypto = require('crypto');
|
|
10
10
|
const bcrypt = require('bcryptjs');
|
|
11
11
|
|
|
12
|
-
const {
|
|
12
|
+
const { getAbsoluteServerUrl, sanitize } = require('@strapi/utils');
|
|
13
13
|
const { getService } = require('../utils');
|
|
14
14
|
|
|
15
|
-
module.exports = {
|
|
15
|
+
module.exports = ({ strapi }) => ({
|
|
16
16
|
/**
|
|
17
17
|
* Promise to count users
|
|
18
18
|
*
|
|
@@ -20,7 +20,7 @@ module.exports = {
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
count(params) {
|
|
23
|
-
return strapi.query('
|
|
23
|
+
return strapi.query('plugin::users-permissions.user').count({ where: params });
|
|
24
24
|
},
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -39,7 +39,7 @@ module.exports = {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
return strapi
|
|
42
|
-
.query('
|
|
42
|
+
.query('plugin::users-permissions.user')
|
|
43
43
|
.create({ data: values, populate: ['role'] });
|
|
44
44
|
},
|
|
45
45
|
|
|
@@ -53,7 +53,7 @@ module.exports = {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
return strapi
|
|
56
|
-
.query('
|
|
56
|
+
.query('plugin::users-permissions.user')
|
|
57
57
|
.update({ where: params, data: values, populate: ['role'] });
|
|
58
58
|
},
|
|
59
59
|
|
|
@@ -62,7 +62,7 @@ module.exports = {
|
|
|
62
62
|
* @return {Promise}
|
|
63
63
|
*/
|
|
64
64
|
fetch(params, populate) {
|
|
65
|
-
return strapi.query('
|
|
65
|
+
return strapi.query('plugin::users-permissions.user').findOne({ where: params, populate });
|
|
66
66
|
},
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -71,7 +71,7 @@ module.exports = {
|
|
|
71
71
|
*/
|
|
72
72
|
fetchAuthenticatedUser(id) {
|
|
73
73
|
return strapi
|
|
74
|
-
.query('
|
|
74
|
+
.query('plugin::users-permissions.user')
|
|
75
75
|
.findOne({ where: { id }, populate: ['role'] });
|
|
76
76
|
},
|
|
77
77
|
|
|
@@ -80,7 +80,7 @@ module.exports = {
|
|
|
80
80
|
* @return {Promise}
|
|
81
81
|
*/
|
|
82
82
|
fetchAll(params, populate) {
|
|
83
|
-
return strapi.query('
|
|
83
|
+
return strapi.query('plugin::users-permissions.user').findMany({ where: params, populate });
|
|
84
84
|
},
|
|
85
85
|
|
|
86
86
|
hashPassword(user = {}) {
|
|
@@ -111,11 +111,7 @@ module.exports = {
|
|
|
111
111
|
* @return {Promise}
|
|
112
112
|
*/
|
|
113
113
|
async remove(params) {
|
|
114
|
-
return strapi.query('
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
async removeAll(params) {
|
|
118
|
-
return strapi.query('plugins::users-permissions.user').delete({ where: params });
|
|
114
|
+
return strapi.query('plugin::users-permissions.user').delete({ where: params });
|
|
119
115
|
},
|
|
120
116
|
|
|
121
117
|
validatePassword(password, hash) {
|
|
@@ -124,19 +120,15 @@ module.exports = {
|
|
|
124
120
|
|
|
125
121
|
async sendConfirmationEmail(user) {
|
|
126
122
|
const userPermissionService = getService('users-permissions');
|
|
127
|
-
const pluginStore = await strapi.store({
|
|
128
|
-
|
|
129
|
-
type: 'plugin',
|
|
130
|
-
name: 'users-permissions',
|
|
131
|
-
});
|
|
123
|
+
const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });
|
|
124
|
+
const userSchema = strapi.getModel('plugin::users-permissions.user');
|
|
132
125
|
|
|
133
126
|
const settings = await pluginStore
|
|
134
127
|
.get({ key: 'email' })
|
|
135
128
|
.then(storeEmail => storeEmail['email_confirmation'].options);
|
|
136
129
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
});
|
|
130
|
+
// Sanitize the template's user information
|
|
131
|
+
const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(userSchema, user);
|
|
140
132
|
|
|
141
133
|
const confirmationToken = crypto.randomBytes(20).toString('hex');
|
|
142
134
|
|
|
@@ -144,23 +136,28 @@ module.exports = {
|
|
|
144
136
|
|
|
145
137
|
settings.message = await userPermissionService.template(settings.message, {
|
|
146
138
|
URL: `${getAbsoluteServerUrl(strapi.config)}/auth/email-confirmation`,
|
|
147
|
-
USER:
|
|
139
|
+
USER: sanitizedUserInfo,
|
|
148
140
|
CODE: confirmationToken,
|
|
149
141
|
});
|
|
150
142
|
|
|
151
|
-
settings.object = await userPermissionService.template(settings.object, {
|
|
143
|
+
settings.object = await userPermissionService.template(settings.object, {
|
|
144
|
+
USER: sanitizedUserInfo,
|
|
145
|
+
});
|
|
152
146
|
|
|
153
147
|
// Send an email to the user.
|
|
154
|
-
await strapi
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
148
|
+
await strapi
|
|
149
|
+
.plugin('email')
|
|
150
|
+
.service('email')
|
|
151
|
+
.send({
|
|
152
|
+
to: user.email,
|
|
153
|
+
from:
|
|
154
|
+
settings.from.email && settings.from.name
|
|
155
|
+
? `${settings.from.name} <${settings.from.email}>`
|
|
156
|
+
: undefined,
|
|
157
|
+
replyTo: settings.response_email,
|
|
158
|
+
subject: settings.object,
|
|
159
|
+
text: settings.message,
|
|
160
|
+
html: settings.message,
|
|
161
|
+
});
|
|
165
162
|
},
|
|
166
|
-
};
|
|
163
|
+
});
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { filter, map, pipe, prop } = require('lodash/fp');
|
|
5
|
+
|
|
6
|
+
const { getService } = require('../utils');
|
|
7
|
+
|
|
8
|
+
const DEFAULT_PERMISSIONS = [
|
|
9
|
+
{ action: 'plugin::users-permissions.auth.admincallback', roleType: 'public' },
|
|
10
|
+
{ action: 'plugin::users-permissions.auth.adminregister', roleType: 'public' },
|
|
11
|
+
{ action: 'plugin::users-permissions.auth.callback', roleType: 'public' },
|
|
12
|
+
{ action: 'plugin::users-permissions.auth.connect', roleType: null },
|
|
13
|
+
{ action: 'plugin::users-permissions.auth.forgotpassword', roleType: 'public' },
|
|
14
|
+
{ action: 'plugin::users-permissions.auth.resetpassword', roleType: 'public' },
|
|
15
|
+
{ action: 'plugin::users-permissions.auth.register', roleType: 'public' },
|
|
16
|
+
{ action: 'plugin::users-permissions.auth.emailconfirmation', roleType: 'public' },
|
|
17
|
+
{ action: 'plugin::users-permissions.user.me', roleType: null },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const transformRoutePrefixFor = pluginName => route => {
|
|
21
|
+
const prefix = route.config && route.config.prefix;
|
|
22
|
+
const path = prefix !== undefined ? `${prefix}${route.path}` : `/${pluginName}${route.path}`;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
...route,
|
|
26
|
+
path,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports = ({ strapi }) => ({
|
|
31
|
+
getActions({ defaultEnable = false } = {}) {
|
|
32
|
+
const actionMap = {};
|
|
33
|
+
|
|
34
|
+
const isContentApi = action => {
|
|
35
|
+
if (!_.has(action, Symbol.for('__type__'))) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return action[Symbol.for('__type__')].includes('content-api');
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
43
|
+
const controllers = _.reduce(
|
|
44
|
+
api.controllers,
|
|
45
|
+
(acc, controller, controllerName) => {
|
|
46
|
+
const contentApiActions = _.pickBy(controller, isContentApi);
|
|
47
|
+
|
|
48
|
+
if (_.isEmpty(contentApiActions)) {
|
|
49
|
+
return acc;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
acc[controllerName] = _.mapValues(contentApiActions, () => {
|
|
53
|
+
return {
|
|
54
|
+
enabled: defaultEnable,
|
|
55
|
+
policy: '',
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return acc;
|
|
60
|
+
},
|
|
61
|
+
{}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!_.isEmpty(controllers)) {
|
|
65
|
+
actionMap[`api::${apiName}`] = { controllers };
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
70
|
+
const controllers = _.reduce(
|
|
71
|
+
plugin.controllers,
|
|
72
|
+
(acc, controller, controllerName) => {
|
|
73
|
+
const contentApiActions = _.pickBy(controller, isContentApi);
|
|
74
|
+
|
|
75
|
+
if (_.isEmpty(contentApiActions)) {
|
|
76
|
+
return acc;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
acc[controllerName] = _.mapValues(contentApiActions, () => {
|
|
80
|
+
return {
|
|
81
|
+
enabled: defaultEnable,
|
|
82
|
+
policy: '',
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return acc;
|
|
87
|
+
},
|
|
88
|
+
{}
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!_.isEmpty(controllers)) {
|
|
92
|
+
actionMap[`plugin::${pluginName}`] = { controllers };
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return actionMap;
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
async getRoutes() {
|
|
100
|
+
const routesMap = {};
|
|
101
|
+
|
|
102
|
+
_.forEach(strapi.api, (api, apiName) => {
|
|
103
|
+
const routes = _.flatMap(api.routes, route => {
|
|
104
|
+
if (_.has(route, 'routes')) {
|
|
105
|
+
return route.routes;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return route;
|
|
109
|
+
}).filter(route => route.info.type === 'content-api');
|
|
110
|
+
|
|
111
|
+
if (routes.length === 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
routesMap[`api::${apiName}`] = routes.map(route => ({
|
|
116
|
+
...route,
|
|
117
|
+
path: `/api${route.path}`,
|
|
118
|
+
}));
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
_.forEach(strapi.plugins, (plugin, pluginName) => {
|
|
122
|
+
const transformPrefix = transformRoutePrefixFor(pluginName);
|
|
123
|
+
|
|
124
|
+
const routes = _.flatMap(plugin.routes, route => {
|
|
125
|
+
if (_.has(route, 'routes')) {
|
|
126
|
+
return route.routes.map(transformPrefix);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return transformPrefix(route);
|
|
130
|
+
}).filter(route => route.info.type === 'content-api');
|
|
131
|
+
|
|
132
|
+
if (routes.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
routesMap[`plugin::${pluginName}`] = routes.map(route => ({
|
|
137
|
+
...route,
|
|
138
|
+
path: `/api${route.path}`,
|
|
139
|
+
}));
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
return routesMap;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
async syncPermissions() {
|
|
146
|
+
const roles = await strapi.query('plugin::users-permissions.role').findMany();
|
|
147
|
+
const dbPermissions = await strapi.query('plugin::users-permissions.permission').findMany();
|
|
148
|
+
|
|
149
|
+
const permissionsFoundInDB = _.uniq(_.map(dbPermissions, 'action'));
|
|
150
|
+
|
|
151
|
+
const appActions = _.flatMap(strapi.api, (api, apiName) => {
|
|
152
|
+
return _.flatMap(api.controllers, (controller, controllerName) => {
|
|
153
|
+
return _.keys(controller).map(actionName => {
|
|
154
|
+
return `api::${apiName}.${controllerName}.${actionName}`;
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const pluginsActions = _.flatMap(strapi.plugins, (plugin, pluginName) => {
|
|
160
|
+
return _.flatMap(plugin.controllers, (controller, controllerName) => {
|
|
161
|
+
return _.keys(controller).map(actionName => {
|
|
162
|
+
return `plugin::${pluginName}.${controllerName}.${actionName}`;
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const allActions = [...appActions, ...pluginsActions];
|
|
168
|
+
|
|
169
|
+
const toDelete = _.difference(permissionsFoundInDB, allActions);
|
|
170
|
+
|
|
171
|
+
await Promise.all(
|
|
172
|
+
toDelete.map(action => {
|
|
173
|
+
return strapi.query('plugin::users-permissions.permission').delete({ where: { action } });
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (permissionsFoundInDB.length === 0) {
|
|
178
|
+
// create default permissions
|
|
179
|
+
for (const role of roles) {
|
|
180
|
+
const toCreate = pipe(
|
|
181
|
+
filter(({ roleType }) => roleType === role.type || roleType === null),
|
|
182
|
+
map(prop('action'))
|
|
183
|
+
)(DEFAULT_PERMISSIONS);
|
|
184
|
+
|
|
185
|
+
await Promise.all(
|
|
186
|
+
toCreate.map(action => {
|
|
187
|
+
return strapi.query('plugin::users-permissions.permission').create({
|
|
188
|
+
data: {
|
|
189
|
+
action,
|
|
190
|
+
role: role.id,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
async initialize() {
|
|
200
|
+
const roleCount = await strapi.query('plugin::users-permissions.role').count();
|
|
201
|
+
|
|
202
|
+
if (roleCount === 0) {
|
|
203
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
204
|
+
data: {
|
|
205
|
+
name: 'Authenticated',
|
|
206
|
+
description: 'Default role given to authenticated user.',
|
|
207
|
+
type: 'authenticated',
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
await strapi.query('plugin::users-permissions.role').create({
|
|
212
|
+
data: {
|
|
213
|
+
name: 'Public',
|
|
214
|
+
description: 'Default role given to unauthenticated user.',
|
|
215
|
+
type: 'public',
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return getService('users-permissions').syncPermissions();
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
async updateUserRole(user, role) {
|
|
224
|
+
return strapi
|
|
225
|
+
.query('plugin::users-permissions.user')
|
|
226
|
+
.update({ where: { id: user.id }, data: { role } });
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
template(layout, data) {
|
|
230
|
+
const compiledObject = _.template(layout);
|
|
231
|
+
return compiledObject(data);
|
|
232
|
+
},
|
|
233
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { castArray, map } = 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
|
+
if (id === undefined) {
|
|
20
|
+
return { authenticated: false };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// fetch authenticated user
|
|
24
|
+
const user = await getService('user').fetchAuthenticatedUser(id);
|
|
25
|
+
|
|
26
|
+
if (!user) {
|
|
27
|
+
return { error: 'Invalid credentials' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const advancedSettings = await getAdvancedSettings();
|
|
31
|
+
|
|
32
|
+
if (advancedSettings.email_confirmation && !user.confirmed) {
|
|
33
|
+
return { error: 'Invalid credentials' };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (user.blocked) {
|
|
37
|
+
return { error: 'Invalid credentials' };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
ctx.state.user = user;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
authenticated: true,
|
|
44
|
+
credentials: user,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const publicPermissions = await strapi.query('plugin::users-permissions.permission').findMany({
|
|
49
|
+
where: {
|
|
50
|
+
role: { type: 'public' },
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (publicPermissions.length === 0) {
|
|
55
|
+
return { authenticated: false };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
authenticated: true,
|
|
60
|
+
credentials: null,
|
|
61
|
+
};
|
|
62
|
+
} catch (err) {
|
|
63
|
+
return { authenticated: false };
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const verify = async (auth, config) => {
|
|
68
|
+
const { credentials: user } = auth;
|
|
69
|
+
|
|
70
|
+
// public accesss
|
|
71
|
+
if (!user) {
|
|
72
|
+
// test against public role
|
|
73
|
+
const publicPermissions = await strapi.query('plugin::users-permissions.permission').findMany({
|
|
74
|
+
where: {
|
|
75
|
+
role: { type: 'public' },
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const allowedActions = map('action', publicPermissions);
|
|
80
|
+
|
|
81
|
+
// A non authenticated user cannot access routes that do not have a scope
|
|
82
|
+
if (!config.scope) {
|
|
83
|
+
throw new UnauthorizedError();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
|
|
87
|
+
|
|
88
|
+
if (!isAllowed) {
|
|
89
|
+
throw new ForbiddenError();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const permissions = await strapi.query('plugin::users-permissions.permission').findMany({
|
|
96
|
+
where: { role: user.role.id },
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const allowedActions = map('action', permissions);
|
|
100
|
+
|
|
101
|
+
// An authenticated user can access non scoped routes
|
|
102
|
+
if (!config.scope) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const isAllowed = castArray(config.scope).every(scope => allowedActions.includes(scope));
|
|
107
|
+
|
|
108
|
+
if (!isAllowed) {
|
|
109
|
+
throw new ForbiddenError();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// TODO: if we need to keep policies for u&p execution
|
|
113
|
+
// Execute the policies.
|
|
114
|
+
// if (permission.policy) {
|
|
115
|
+
// return await strapi.plugin('users-permissions').policy(permission.policy)(ctx, next);
|
|
116
|
+
// }
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
name: 'users-permissions',
|
|
121
|
+
authenticate,
|
|
122
|
+
verify,
|
|
123
|
+
};
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as usersPermissions from '../services/users-permissions';
|
|
2
2
|
import * as user from '../services/user';
|
|
3
|
+
import * as role from '../services/role';
|
|
3
4
|
import * as jwt from '../services/jwt';
|
|
5
|
+
import * as providers from '../services/providers';
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
type S = {
|
|
6
9
|
['users-permissions']: typeof usersPermissions;
|
|
10
|
+
['role']: typeof role;
|
|
7
11
|
user: typeof user;
|
|
8
12
|
jwt: typeof jwt;
|
|
13
|
+
providers: typeof providers;
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
export function getService<T extends keyof S>(name: T): S[T]
|
|
16
|
+
export function getService<T extends keyof S>(name: T): ReturnType<S[T]>;
|