@strapi/plugin-users-permissions 0.0.0-next.d1dda661d262d4773c59ee693c38542d9b0dc54c → 0.0.0-next.d2d15ef227d67cce89c2673764c0555c841cd29c
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/.eslintignore +1 -2
- package/.eslintrc +17 -0
- package/LICENSE +18 -3
- package/admin/src/components/BoundRoute/{index.js → index.jsx} +2 -2
- package/admin/src/components/FormModal/Input/{index.js → index.jsx} +32 -31
- package/admin/src/components/FormModal/index.jsx +115 -0
- package/admin/src/components/Permissions/PermissionRow/{CheckboxWrapper.js → CheckboxWrapper.jsx} +4 -3
- package/admin/src/components/Permissions/PermissionRow/{SubCategory.js → SubCategory.jsx} +13 -22
- package/admin/src/components/Permissions/index.jsx +47 -0
- package/admin/src/components/Permissions/reducer.js +1 -1
- package/admin/src/components/Policies/{index.js → index.jsx} +7 -5
- package/admin/src/components/UsersPermissions/{index.js → index.jsx} +15 -7
- package/admin/src/components/UsersPermissions/reducer.js +1 -1
- package/admin/src/index.js +19 -47
- package/admin/src/pages/AdvancedSettings/index.jsx +214 -0
- package/admin/src/pages/AdvancedSettings/utils/layout.js +20 -35
- package/admin/src/pages/AdvancedSettings/utils/schema.js +5 -2
- package/admin/src/pages/EmailTemplates/components/EmailForm.jsx +156 -0
- package/admin/src/pages/EmailTemplates/components/{EmailTable.js → EmailTable.jsx} +20 -17
- package/admin/src/pages/EmailTemplates/index.jsx +148 -0
- package/admin/src/pages/EmailTemplates/utils/schema.js +18 -6
- package/admin/src/pages/Providers/index.jsx +262 -0
- package/admin/src/pages/Providers/utils/forms.js +11 -11
- package/admin/src/pages/Roles/constants.js +3 -3
- package/admin/src/{hooks → pages/Roles/hooks}/usePlugins.js +19 -12
- package/admin/src/pages/Roles/index.jsx +24 -0
- package/admin/src/pages/Roles/pages/CreatePage.jsx +194 -0
- package/admin/src/pages/Roles/pages/EditPage.jsx +215 -0
- package/admin/src/pages/Roles/pages/ListPage/components/TableBody.jsx +119 -0
- package/admin/src/pages/Roles/{ListPage/index.js → pages/ListPage/index.jsx} +105 -80
- package/admin/src/translations/en.json +1 -1
- package/admin/src/translations/zh-Hans.json +80 -80
- package/admin/src/utils/index.js +0 -1
- package/admin/src/utils/prefixPluginTranslations.js +13 -0
- package/dist/_chunks/ar-BguGUqwK.js +44 -0
- package/dist/_chunks/ar-BguGUqwK.js.map +1 -0
- package/dist/_chunks/ar-CK8BRRXB.mjs +44 -0
- package/dist/_chunks/ar-CK8BRRXB.mjs.map +1 -0
- package/dist/_chunks/cs-BVigMk0l.mjs +50 -0
- package/dist/_chunks/cs-BVigMk0l.mjs.map +1 -0
- package/dist/_chunks/cs-BW8-K_GY.js +50 -0
- package/dist/_chunks/cs-BW8-K_GY.js.map +1 -0
- package/dist/_chunks/de-BKUdRFI4.mjs +62 -0
- package/dist/_chunks/de-BKUdRFI4.mjs.map +1 -0
- package/dist/_chunks/de-owXpVluI.js +62 -0
- package/dist/_chunks/de-owXpVluI.js.map +1 -0
- package/dist/_chunks/dk-BQiTK50l.mjs +86 -0
- package/dist/_chunks/dk-BQiTK50l.mjs.map +1 -0
- package/dist/_chunks/dk-LXAnbuBk.js +86 -0
- package/dist/_chunks/dk-LXAnbuBk.js.map +1 -0
- package/dist/_chunks/en-DOHtPf-2.mjs +86 -0
- package/dist/_chunks/en-DOHtPf-2.mjs.map +1 -0
- package/dist/_chunks/en-MHo5mcsU.js +86 -0
- package/dist/_chunks/en-MHo5mcsU.js.map +1 -0
- package/dist/_chunks/es-BwLCLXAQ.js +86 -0
- package/dist/_chunks/es-BwLCLXAQ.js.map +1 -0
- package/dist/_chunks/es-DNgOVMjD.mjs +86 -0
- package/dist/_chunks/es-DNgOVMjD.mjs.map +1 -0
- package/dist/_chunks/fr-DkgRugiU.mjs +50 -0
- package/dist/_chunks/fr-DkgRugiU.mjs.map +1 -0
- package/dist/_chunks/fr-DkhpSjjm.js +50 -0
- package/dist/_chunks/fr-DkhpSjjm.js.map +1 -0
- package/dist/_chunks/id-BTemOeTZ.js +62 -0
- package/dist/_chunks/id-BTemOeTZ.js.map +1 -0
- package/dist/_chunks/id-BdEsvnaF.mjs +62 -0
- package/dist/_chunks/id-BdEsvnaF.mjs.map +1 -0
- package/dist/_chunks/index-B9cFxoCN.mjs +615 -0
- package/dist/_chunks/index-B9cFxoCN.mjs.map +1 -0
- package/dist/_chunks/index-BJTnrL31.js +281 -0
- package/dist/_chunks/index-BJTnrL31.js.map +1 -0
- package/dist/_chunks/index-CAgV-G5k.js +1173 -0
- package/dist/_chunks/index-CAgV-G5k.js.map +1 -0
- package/dist/_chunks/index-CI_b1cXd.mjs +1143 -0
- package/dist/_chunks/index-CI_b1cXd.mjs.map +1 -0
- package/dist/_chunks/index-Cb03Ke48.js +366 -0
- package/dist/_chunks/index-Cb03Ke48.js.map +1 -0
- package/dist/_chunks/index-DDglyd0X.mjs +262 -0
- package/dist/_chunks/index-DDglyd0X.mjs.map +1 -0
- package/dist/_chunks/index-DJOPnOVo.mjs +344 -0
- package/dist/_chunks/index-DJOPnOVo.mjs.map +1 -0
- package/dist/_chunks/index-QPUYgtlo-BfJxOAzF.mjs +11845 -0
- package/dist/_chunks/index-QPUYgtlo-BfJxOAzF.mjs.map +1 -0
- package/dist/_chunks/index-QPUYgtlo-QiBdpWEj.js +11869 -0
- package/dist/_chunks/index-QPUYgtlo-QiBdpWEj.js.map +1 -0
- package/dist/_chunks/index-_vrdPeYp.js +248 -0
- package/dist/_chunks/index-_vrdPeYp.js.map +1 -0
- package/dist/_chunks/index-bDCZWhLO.mjs +249 -0
- package/dist/_chunks/index-bDCZWhLO.mjs.map +1 -0
- package/dist/_chunks/index-cL_YxyjM.js +638 -0
- package/dist/_chunks/index-cL_YxyjM.js.map +1 -0
- package/dist/_chunks/it-B-rv0E24.mjs +62 -0
- package/dist/_chunks/it-B-rv0E24.mjs.map +1 -0
- package/dist/_chunks/it-D1rH6V6_.js +62 -0
- package/dist/_chunks/it-D1rH6V6_.js.map +1 -0
- package/dist/_chunks/ja-C8K-VBPD.mjs +48 -0
- package/dist/_chunks/ja-C8K-VBPD.mjs.map +1 -0
- package/dist/_chunks/ja-DqShgTMf.js +48 -0
- package/dist/_chunks/ja-DqShgTMf.js.map +1 -0
- package/dist/_chunks/ko-B9DGEPWH.js +86 -0
- package/dist/_chunks/ko-B9DGEPWH.js.map +1 -0
- package/dist/_chunks/ko-Busb0wIY.mjs +86 -0
- package/dist/_chunks/ko-Busb0wIY.mjs.map +1 -0
- package/dist/_chunks/ms-ByvsQjRt.mjs +49 -0
- package/dist/_chunks/ms-ByvsQjRt.mjs.map +1 -0
- package/dist/_chunks/ms-CPBU3LWf.js +49 -0
- package/dist/_chunks/ms-CPBU3LWf.js.map +1 -0
- package/dist/_chunks/nl-5qO8Rpcy.mjs +48 -0
- package/dist/_chunks/nl-5qO8Rpcy.mjs.map +1 -0
- package/dist/_chunks/nl-CwNB6YoO.js +48 -0
- package/dist/_chunks/nl-CwNB6YoO.js.map +1 -0
- package/dist/_chunks/pl-BdIzifBE.mjs +86 -0
- package/dist/_chunks/pl-BdIzifBE.mjs.map +1 -0
- package/dist/_chunks/pl-Do9UD69f.js +86 -0
- package/dist/_chunks/pl-Do9UD69f.js.map +1 -0
- package/dist/_chunks/pt-BIO24ioG.mjs +48 -0
- package/dist/_chunks/pt-BIO24ioG.mjs.map +1 -0
- package/dist/_chunks/pt-BR-D7dZhxuP.js +44 -0
- package/dist/_chunks/pt-BR-D7dZhxuP.js.map +1 -0
- package/dist/_chunks/pt-BR-f0p23AQZ.mjs +44 -0
- package/dist/_chunks/pt-BR-f0p23AQZ.mjs.map +1 -0
- package/dist/_chunks/pt-fdvyOnUp.js +48 -0
- package/dist/_chunks/pt-fdvyOnUp.js.map +1 -0
- package/dist/_chunks/ru-C94rjPGA.js +86 -0
- package/dist/_chunks/ru-C94rjPGA.js.map +1 -0
- package/dist/_chunks/ru-VWy-IB7K.mjs +86 -0
- package/dist/_chunks/ru-VWy-IB7K.mjs.map +1 -0
- package/dist/_chunks/sk-BABEhykl.js +50 -0
- package/dist/_chunks/sk-BABEhykl.js.map +1 -0
- package/dist/_chunks/sk-B_LIcepm.mjs +50 -0
- package/dist/_chunks/sk-B_LIcepm.mjs.map +1 -0
- package/dist/_chunks/sv-ABLKOokl.mjs +86 -0
- package/dist/_chunks/sv-ABLKOokl.mjs.map +1 -0
- package/dist/_chunks/sv-Be43LhA9.js +86 -0
- package/dist/_chunks/sv-Be43LhA9.js.map +1 -0
- package/dist/_chunks/th-DKyP7ueR.mjs +60 -0
- package/dist/_chunks/th-DKyP7ueR.mjs.map +1 -0
- package/dist/_chunks/th-DgVhVLhL.js +60 -0
- package/dist/_chunks/th-DgVhVLhL.js.map +1 -0
- package/dist/_chunks/tr-B_idhkEs.js +85 -0
- package/dist/_chunks/tr-B_idhkEs.js.map +1 -0
- package/dist/_chunks/tr-qa1Q5UjC.mjs +85 -0
- package/dist/_chunks/tr-qa1Q5UjC.mjs.map +1 -0
- package/dist/_chunks/uk-BmRqbeQc.mjs +49 -0
- package/dist/_chunks/uk-BmRqbeQc.mjs.map +1 -0
- package/dist/_chunks/uk-LHOivnhP.js +49 -0
- package/dist/_chunks/uk-LHOivnhP.js.map +1 -0
- package/dist/_chunks/vi-CdVRdKDw.js +50 -0
- package/dist/_chunks/vi-CdVRdKDw.js.map +1 -0
- package/dist/_chunks/vi-HW-EdMea.mjs +50 -0
- package/dist/_chunks/vi-HW-EdMea.mjs.map +1 -0
- package/dist/_chunks/zh-5hKkVPA4.mjs +86 -0
- package/dist/_chunks/zh-5hKkVPA4.mjs.map +1 -0
- package/dist/_chunks/zh-Cuq8gMnF.js +86 -0
- package/dist/_chunks/zh-Cuq8gMnF.js.map +1 -0
- package/dist/_chunks/zh-Hans-BHilK-yc.mjs +86 -0
- package/dist/_chunks/zh-Hans-BHilK-yc.mjs.map +1 -0
- package/dist/_chunks/zh-Hans-GQDMKtY4.js +86 -0
- package/dist/_chunks/zh-Hans-GQDMKtY4.js.map +1 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/index.mjs +5 -0
- package/dist/admin/index.mjs.map +1 -0
- package/documentation/content-api.yaml +1 -1
- package/jest.config.front.js +1 -1
- package/package.json +47 -28
- package/packup.config.ts +22 -0
- package/server/bootstrap/index.js +18 -15
- package/server/bootstrap/users-permissions-actions.js +6 -0
- package/server/config.js +29 -0
- package/server/content-types/user/index.js +0 -1
- package/server/controllers/auth.js +60 -34
- package/server/controllers/content-manager-user.js +28 -30
- package/server/controllers/role.js +1 -1
- package/server/controllers/user.js +18 -8
- package/server/middlewares/rateLimit.js +41 -21
- package/server/register.js +1 -1
- package/server/services/jwt.js +3 -3
- package/server/services/permission.js +3 -7
- package/server/services/providers-registry.js +469 -261
- package/server/services/providers.js +10 -5
- package/server/services/role.js +15 -13
- package/server/services/user.js +56 -19
- package/server/services/users-permissions.js +15 -13
- package/server/utils/index.d.ts +2 -1
- package/server/utils/sanitize/sanitizers.js +7 -3
- package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +2 -2
- package/.eslintrc.js +0 -14
- package/admin/src/components/FormModal/index.js +0 -126
- package/admin/src/components/Permissions/index.js +0 -57
- package/admin/src/hooks/index.js +0 -5
- package/admin/src/hooks/useFetchRole/index.js +0 -67
- package/admin/src/hooks/useFetchRole/reducer.js +0 -31
- package/admin/src/hooks/useForm/index.js +0 -70
- package/admin/src/hooks/useForm/reducer.js +0 -40
- package/admin/src/hooks/useRolesList/index.js +0 -65
- package/admin/src/hooks/useRolesList/init.js +0 -5
- package/admin/src/hooks/useRolesList/reducer.js +0 -31
- package/admin/src/pages/AdvancedSettings/index.js +0 -243
- package/admin/src/pages/AdvancedSettings/utils/api.js +0 -18
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +0 -176
- package/admin/src/pages/EmailTemplates/index.js +0 -163
- package/admin/src/pages/EmailTemplates/utils/api.js +0 -18
- package/admin/src/pages/Providers/index.js +0 -275
- package/admin/src/pages/Providers/reducer.js +0 -54
- package/admin/src/pages/Providers/utils/api.js +0 -26
- package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
- package/admin/src/pages/Roles/CreatePage.js +0 -185
- package/admin/src/pages/Roles/EditPage.js +0 -197
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +0 -93
- package/admin/src/pages/Roles/ListPage/utils/api.js +0 -32
- package/admin/src/pages/Roles/ProtectedCreatePage.js +0 -15
- package/admin/src/pages/Roles/ProtectedEditPage.js +0 -15
- package/admin/src/pages/Roles/ProtectedListPage.js +0 -17
- package/admin/src/pages/Roles/index.js +0 -30
- package/admin/src/utils/getRequestURL.js +0 -5
- package/server/bootstrap/grant-config.js +0 -131
- package/strapi-admin.js +0 -3
- package/strapi-server.js +0 -3
- /package/admin/src/components/Permissions/PermissionRow/{index.js → index.jsx} +0 -0
- /package/admin/src/contexts/UsersPermissionsContext/{index.js → index.jsx} +0 -0
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
/* eslint-disable no-useless-escape */
|
|
10
10
|
const crypto = require('crypto');
|
|
11
11
|
const _ = require('lodash');
|
|
12
|
+
const { concat, compact, isArray } = require('lodash/fp');
|
|
12
13
|
const utils = require('@strapi/utils');
|
|
13
14
|
const { getService } = require('../utils');
|
|
14
15
|
const {
|
|
@@ -21,14 +22,13 @@ const {
|
|
|
21
22
|
validateChangePasswordBody,
|
|
22
23
|
} = require('./validation/auth');
|
|
23
24
|
|
|
24
|
-
const {
|
|
25
|
-
const { ApplicationError, ValidationError } = utils.errors;
|
|
25
|
+
const { ApplicationError, ValidationError, ForbiddenError } = utils.errors;
|
|
26
26
|
|
|
27
27
|
const sanitizeUser = (user, ctx) => {
|
|
28
28
|
const { auth } = ctx.state;
|
|
29
29
|
const userSchema = strapi.getModel('plugin::users-permissions.user');
|
|
30
30
|
|
|
31
|
-
return
|
|
31
|
+
return strapi.contentAPI.sanitize.output(user, userSchema, { auth });
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
module.exports = {
|
|
@@ -51,7 +51,7 @@ module.exports = {
|
|
|
51
51
|
const { identifier } = params;
|
|
52
52
|
|
|
53
53
|
// Check if the user exists.
|
|
54
|
-
const user = await strapi.query('plugin::users-permissions.user').findOne({
|
|
54
|
+
const user = await strapi.db.query('plugin::users-permissions.user').findOne({
|
|
55
55
|
where: {
|
|
56
56
|
provider,
|
|
57
57
|
$or: [{ email: identifier.toLowerCase() }, { username: identifier }],
|
|
@@ -96,6 +96,10 @@ module.exports = {
|
|
|
96
96
|
try {
|
|
97
97
|
const user = await getService('providers').connect(provider, ctx.query);
|
|
98
98
|
|
|
99
|
+
if (user.blocked) {
|
|
100
|
+
throw new ForbiddenError('Your account has been blocked by an administrator');
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
return ctx.send({
|
|
100
104
|
jwt: getService('jwt').issue({ id: user.id }),
|
|
101
105
|
user: await sanitizeUser(user, ctx),
|
|
@@ -112,10 +116,9 @@ module.exports = {
|
|
|
112
116
|
|
|
113
117
|
const { currentPassword, password } = await validateChangePasswordBody(ctx.request.body);
|
|
114
118
|
|
|
115
|
-
const user = await strapi.
|
|
116
|
-
'plugin::users-permissions.user'
|
|
117
|
-
ctx.state.user.id
|
|
118
|
-
);
|
|
119
|
+
const user = await strapi.db
|
|
120
|
+
.query('plugin::users-permissions.user')
|
|
121
|
+
.findOne({ where: { id: ctx.state.user.id } });
|
|
119
122
|
|
|
120
123
|
const validPassword = await getService('user').validatePassword(currentPassword, user.password);
|
|
121
124
|
|
|
@@ -144,7 +147,7 @@ module.exports = {
|
|
|
144
147
|
throw new ValidationError('Passwords do not match');
|
|
145
148
|
}
|
|
146
149
|
|
|
147
|
-
const user = await strapi
|
|
150
|
+
const user = await strapi.db
|
|
148
151
|
.query('plugin::users-permissions.user')
|
|
149
152
|
.findOne({ where: { resetPasswordToken: code } });
|
|
150
153
|
|
|
@@ -193,10 +196,28 @@ module.exports = {
|
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
// Ability to pass OAuth callback dynamically
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
const queryCustomCallback = _.get(ctx, 'query.callback');
|
|
200
|
+
const dynamicSessionCallback = _.get(ctx, 'session.grant.dynamic.callback');
|
|
201
|
+
|
|
202
|
+
const customCallback = queryCustomCallback ?? dynamicSessionCallback;
|
|
203
|
+
|
|
204
|
+
// The custom callback is validated to make sure it's not redirecting to an unwanted actor.
|
|
205
|
+
if (customCallback !== undefined) {
|
|
206
|
+
try {
|
|
207
|
+
// We're extracting the callback validator from the plugin config since it can be user-customized
|
|
208
|
+
const { validate: validateCallback } = strapi
|
|
209
|
+
.plugin('users-permissions')
|
|
210
|
+
.config('callback');
|
|
211
|
+
|
|
212
|
+
await validateCallback(customCallback, grantConfig[provider]);
|
|
213
|
+
|
|
214
|
+
grantConfig[provider].callback = customCallback;
|
|
215
|
+
} catch (e) {
|
|
216
|
+
throw new ValidationError('Invalid callback URL provided', { callback: customCallback });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Build a valid redirect URI for the current provider
|
|
200
221
|
grantConfig[provider].redirect_uri = getService('providers').buildRedirectUri(provider);
|
|
201
222
|
|
|
202
223
|
return grant(grantConfig)(ctx, next);
|
|
@@ -211,7 +232,7 @@ module.exports = {
|
|
|
211
232
|
const advancedSettings = await pluginStore.get({ key: 'advanced' });
|
|
212
233
|
|
|
213
234
|
// Find the user by email.
|
|
214
|
-
const user = await strapi
|
|
235
|
+
const user = await strapi.db
|
|
215
236
|
.query('plugin::users-permissions.user')
|
|
216
237
|
.findOne({ where: { email: email.toLowerCase() } });
|
|
217
238
|
|
|
@@ -229,8 +250,8 @@ module.exports = {
|
|
|
229
250
|
resetPasswordSettings.message,
|
|
230
251
|
{
|
|
231
252
|
URL: advancedSettings.email_reset_password,
|
|
232
|
-
SERVER_URL:
|
|
233
|
-
ADMIN_URL:
|
|
253
|
+
SERVER_URL: strapi.config.get('server.absoluteUrl'),
|
|
254
|
+
ADMIN_URL: strapi.config.get('admin.absoluteUrl'),
|
|
234
255
|
USER: userInfo,
|
|
235
256
|
TOKEN: resetPasswordToken,
|
|
236
257
|
}
|
|
@@ -273,26 +294,30 @@ module.exports = {
|
|
|
273
294
|
throw new ApplicationError('Register action is currently disabled');
|
|
274
295
|
}
|
|
275
296
|
|
|
297
|
+
const { register } = strapi.config.get('plugin::users-permissions');
|
|
298
|
+
const alwaysAllowedKeys = ['username', 'password', 'email'];
|
|
299
|
+
|
|
300
|
+
// Note that we intentionally do not filter allowedFields to allow a project to explicitly accept private or other Strapi field on registration
|
|
301
|
+
const allowedKeys = compact(
|
|
302
|
+
concat(alwaysAllowedKeys, isArray(register?.allowedFields) ? register.allowedFields : [])
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
// Check if there are any keys in requestBody that are not in allowedKeys
|
|
306
|
+
const invalidKeys = Object.keys(ctx.request.body).filter((key) => !allowedKeys.includes(key));
|
|
307
|
+
|
|
308
|
+
if (invalidKeys.length > 0) {
|
|
309
|
+
// If there are invalid keys, throw an error
|
|
310
|
+
throw new ValidationError(`Invalid parameters: ${invalidKeys.join(', ')}`);
|
|
311
|
+
}
|
|
312
|
+
|
|
276
313
|
const params = {
|
|
277
|
-
..._.
|
|
278
|
-
'confirmed',
|
|
279
|
-
'blocked',
|
|
280
|
-
'confirmationToken',
|
|
281
|
-
'resetPasswordToken',
|
|
282
|
-
'provider',
|
|
283
|
-
'id',
|
|
284
|
-
'createdAt',
|
|
285
|
-
'updatedAt',
|
|
286
|
-
'createdBy',
|
|
287
|
-
'updatedBy',
|
|
288
|
-
'role',
|
|
289
|
-
]),
|
|
314
|
+
..._.pick(ctx.request.body, allowedKeys),
|
|
290
315
|
provider: 'local',
|
|
291
316
|
};
|
|
292
317
|
|
|
293
318
|
await validateRegisterBody(params);
|
|
294
319
|
|
|
295
|
-
const role = await strapi
|
|
320
|
+
const role = await strapi.db
|
|
296
321
|
.query('plugin::users-permissions.role')
|
|
297
322
|
.findOne({ where: { type: settings.default_role } });
|
|
298
323
|
|
|
@@ -311,7 +336,7 @@ module.exports = {
|
|
|
311
336
|
],
|
|
312
337
|
};
|
|
313
338
|
|
|
314
|
-
const conflictingUserCount = await strapi.query('plugin::users-permissions.user').count({
|
|
339
|
+
const conflictingUserCount = await strapi.db.query('plugin::users-permissions.user').count({
|
|
315
340
|
where: { ...identifierFilter, provider },
|
|
316
341
|
});
|
|
317
342
|
|
|
@@ -320,7 +345,7 @@ module.exports = {
|
|
|
320
345
|
}
|
|
321
346
|
|
|
322
347
|
if (settings.unique_email) {
|
|
323
|
-
const conflictingUserCount = await strapi.query('plugin::users-permissions.user').count({
|
|
348
|
+
const conflictingUserCount = await strapi.db.query('plugin::users-permissions.user').count({
|
|
324
349
|
where: { ...identifierFilter },
|
|
325
350
|
});
|
|
326
351
|
|
|
@@ -345,7 +370,8 @@ module.exports = {
|
|
|
345
370
|
try {
|
|
346
371
|
await getService('user').sendConfirmationEmail(sanitizedUser);
|
|
347
372
|
} catch (err) {
|
|
348
|
-
|
|
373
|
+
strapi.log.error(err);
|
|
374
|
+
throw new ApplicationError('Error sending confirmation email');
|
|
349
375
|
}
|
|
350
376
|
|
|
351
377
|
return ctx.send({ user: sanitizedUser });
|
|
@@ -390,7 +416,7 @@ module.exports = {
|
|
|
390
416
|
async sendEmailConfirmation(ctx) {
|
|
391
417
|
const { email } = await validateSendEmailConfirmationBody(ctx.request.body);
|
|
392
418
|
|
|
393
|
-
const user = await strapi.query('plugin::users-permissions.user').findOne({
|
|
419
|
+
const user = await strapi.db.query('plugin::users-permissions.user').findOne({
|
|
394
420
|
where: { email: email.toLowerCase() },
|
|
395
421
|
});
|
|
396
422
|
|
|
@@ -17,24 +17,25 @@ const ACTIONS = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const findEntityAndCheckPermissions = async (ability, action, model, id) => {
|
|
20
|
-
const
|
|
21
|
-
where: { id },
|
|
20
|
+
const doc = await strapi.service('plugin::content-manager.document-manager').findOne(id, model, {
|
|
22
21
|
populate: [`${CREATED_BY_ATTRIBUTE}.roles`],
|
|
23
22
|
});
|
|
24
23
|
|
|
25
|
-
if (_.isNil(
|
|
24
|
+
if (_.isNil(doc)) {
|
|
26
25
|
throw new NotFoundError();
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
const pm = strapi
|
|
28
|
+
const pm = strapi
|
|
29
|
+
.service('admin::permission')
|
|
30
|
+
.createPermissionsManager({ ability, action, model });
|
|
30
31
|
|
|
31
|
-
if (pm.ability.cannot(pm.action, pm.toSubject(
|
|
32
|
+
if (pm.ability.cannot(pm.action, pm.toSubject(doc))) {
|
|
32
33
|
throw new ForbiddenError();
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
+
const docWithoutCreatorRoles = _.omit(doc, `${CREATED_BY_ATTRIBUTE}.roles`);
|
|
36
37
|
|
|
37
|
-
return { pm,
|
|
38
|
+
return { pm, doc: docWithoutCreatorRoles };
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
module.exports = {
|
|
@@ -48,7 +49,7 @@ module.exports = {
|
|
|
48
49
|
|
|
49
50
|
const { email, username } = body;
|
|
50
51
|
|
|
51
|
-
const pm = strapi.admin
|
|
52
|
+
const pm = strapi.service('admin::permission').createPermissionsManager({
|
|
52
53
|
ability: userAbility,
|
|
53
54
|
action: ACTIONS.create,
|
|
54
55
|
model: userModel,
|
|
@@ -66,7 +67,7 @@ module.exports = {
|
|
|
66
67
|
|
|
67
68
|
await validateCreateUserBody(ctx.request.body);
|
|
68
69
|
|
|
69
|
-
const userWithSameUsername = await strapi
|
|
70
|
+
const userWithSameUsername = await strapi.db
|
|
70
71
|
.query('plugin::users-permissions.user')
|
|
71
72
|
.findOne({ where: { username } });
|
|
72
73
|
|
|
@@ -75,7 +76,7 @@ module.exports = {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
if (advanced.unique_email) {
|
|
78
|
-
const userWithSameEmail = await strapi
|
|
79
|
+
const userWithSameEmail = await strapi.db
|
|
79
80
|
.query('plugin::users-permissions.user')
|
|
80
81
|
.findOne({ where: { email: email.toLowerCase() } });
|
|
81
82
|
|
|
@@ -93,18 +94,11 @@ module.exports = {
|
|
|
93
94
|
|
|
94
95
|
user.email = _.toLower(user.email);
|
|
95
96
|
|
|
96
|
-
if (!user.role) {
|
|
97
|
-
const defaultRole = await strapi
|
|
98
|
-
.query('plugin::users-permissions.role')
|
|
99
|
-
.findOne({ where: { type: advanced.default_role } });
|
|
100
|
-
|
|
101
|
-
user.role = defaultRole.id;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
97
|
try {
|
|
105
98
|
const data = await strapi
|
|
106
|
-
.service('plugin::content-manager.
|
|
107
|
-
.create(
|
|
99
|
+
.service('plugin::content-manager.document-manager')
|
|
100
|
+
.create(userModel, { data: user });
|
|
101
|
+
|
|
108
102
|
const sanitizedData = await pm.sanitizeOutput(data, { action: ACTIONS.read });
|
|
109
103
|
|
|
110
104
|
ctx.created(sanitizedData);
|
|
@@ -118,7 +112,7 @@ module.exports = {
|
|
|
118
112
|
*/
|
|
119
113
|
|
|
120
114
|
async update(ctx) {
|
|
121
|
-
const { id } = ctx.params;
|
|
115
|
+
const { id: documentId } = ctx.params;
|
|
122
116
|
const { body } = ctx.request;
|
|
123
117
|
const { user: admin, userAbility } = ctx.state;
|
|
124
118
|
|
|
@@ -128,13 +122,14 @@ module.exports = {
|
|
|
128
122
|
|
|
129
123
|
const { email, username, password } = body;
|
|
130
124
|
|
|
131
|
-
const { pm,
|
|
125
|
+
const { pm, doc } = await findEntityAndCheckPermissions(
|
|
132
126
|
userAbility,
|
|
133
127
|
ACTIONS.edit,
|
|
134
128
|
userModel,
|
|
135
|
-
|
|
129
|
+
documentId
|
|
136
130
|
);
|
|
137
|
-
|
|
131
|
+
|
|
132
|
+
const user = doc;
|
|
138
133
|
|
|
139
134
|
await validateUpdateUserBody(ctx.request.body);
|
|
140
135
|
|
|
@@ -143,23 +138,24 @@ module.exports = {
|
|
|
143
138
|
}
|
|
144
139
|
|
|
145
140
|
if (_.has(body, 'username')) {
|
|
146
|
-
const userWithSameUsername = await strapi
|
|
141
|
+
const userWithSameUsername = await strapi.db
|
|
147
142
|
.query('plugin::users-permissions.user')
|
|
148
143
|
.findOne({ where: { username } });
|
|
149
144
|
|
|
150
|
-
if (userWithSameUsername && _.toString(userWithSameUsername.id) !== _.toString(id)) {
|
|
145
|
+
if (userWithSameUsername && _.toString(userWithSameUsername.id) !== _.toString(user.id)) {
|
|
151
146
|
throw new ApplicationError('Username already taken');
|
|
152
147
|
}
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
if (_.has(body, 'email') && advancedConfigs.unique_email) {
|
|
156
|
-
const userWithSameEmail = await strapi
|
|
151
|
+
const userWithSameEmail = await strapi.db
|
|
157
152
|
.query('plugin::users-permissions.user')
|
|
158
153
|
.findOne({ where: { email: _.toLower(email) } });
|
|
159
154
|
|
|
160
|
-
if (userWithSameEmail && _.toString(userWithSameEmail.id) !== _.toString(id)) {
|
|
155
|
+
if (userWithSameEmail && _.toString(userWithSameEmail.id) !== _.toString(user.id)) {
|
|
161
156
|
throw new ApplicationError('Email already taken');
|
|
162
157
|
}
|
|
158
|
+
|
|
163
159
|
body.email = _.toLower(body.email);
|
|
164
160
|
}
|
|
165
161
|
|
|
@@ -167,8 +163,10 @@ module.exports = {
|
|
|
167
163
|
const updateData = _.omit({ ...sanitizedData, updatedBy: admin.id }, 'createdBy');
|
|
168
164
|
|
|
169
165
|
const data = await strapi
|
|
170
|
-
.service('plugin::content-manager.
|
|
171
|
-
.update(
|
|
166
|
+
.service('plugin::content-manager.document-manager')
|
|
167
|
+
.update(documentId, userModel, {
|
|
168
|
+
data: updateData,
|
|
169
|
+
});
|
|
172
170
|
|
|
173
171
|
ctx.body = await pm.sanitizeOutput(data, { action: ACTIONS.read });
|
|
174
172
|
},
|
|
@@ -11,21 +11,27 @@ const utils = require('@strapi/utils');
|
|
|
11
11
|
const { getService } = require('../utils');
|
|
12
12
|
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
|
|
13
13
|
|
|
14
|
-
const { sanitize } = utils;
|
|
15
14
|
const { ApplicationError, ValidationError, NotFoundError } = utils.errors;
|
|
16
15
|
|
|
17
16
|
const sanitizeOutput = async (user, ctx) => {
|
|
18
17
|
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
19
18
|
const { auth } = ctx.state;
|
|
20
19
|
|
|
21
|
-
return
|
|
20
|
+
return strapi.contentAPI.sanitize.output(user, schema, { auth });
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const validateQuery = async (query, ctx) => {
|
|
24
|
+
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
25
|
+
const { auth } = ctx.state;
|
|
26
|
+
|
|
27
|
+
return strapi.contentAPI.validate.query(query, schema, { auth });
|
|
22
28
|
};
|
|
23
29
|
|
|
24
30
|
const sanitizeQuery = async (query, ctx) => {
|
|
25
31
|
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
26
32
|
const { auth } = ctx.state;
|
|
27
33
|
|
|
28
|
-
return
|
|
34
|
+
return strapi.contentAPI.sanitize.query(query, schema, { auth });
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
module.exports = {
|
|
@@ -42,7 +48,7 @@ module.exports = {
|
|
|
42
48
|
|
|
43
49
|
const { email, username, role } = ctx.request.body;
|
|
44
50
|
|
|
45
|
-
const userWithSameUsername = await strapi
|
|
51
|
+
const userWithSameUsername = await strapi.db
|
|
46
52
|
.query('plugin::users-permissions.user')
|
|
47
53
|
.findOne({ where: { username } });
|
|
48
54
|
|
|
@@ -51,7 +57,7 @@ module.exports = {
|
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
if (advanced.unique_email) {
|
|
54
|
-
const userWithSameEmail = await strapi
|
|
60
|
+
const userWithSameEmail = await strapi.db
|
|
55
61
|
.query('plugin::users-permissions.user')
|
|
56
62
|
.findOne({ where: { email: email.toLowerCase() } });
|
|
57
63
|
|
|
@@ -67,7 +73,7 @@ module.exports = {
|
|
|
67
73
|
};
|
|
68
74
|
|
|
69
75
|
if (!role) {
|
|
70
|
-
const defaultRole = await strapi
|
|
76
|
+
const defaultRole = await strapi.db
|
|
71
77
|
.query('plugin::users-permissions.role')
|
|
72
78
|
.findOne({ where: { type: advanced.default_role } });
|
|
73
79
|
|
|
@@ -108,7 +114,7 @@ module.exports = {
|
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
if (_.has(ctx.request.body, 'username')) {
|
|
111
|
-
const userWithSameUsername = await strapi
|
|
117
|
+
const userWithSameUsername = await strapi.db
|
|
112
118
|
.query('plugin::users-permissions.user')
|
|
113
119
|
.findOne({ where: { username } });
|
|
114
120
|
|
|
@@ -118,7 +124,7 @@ module.exports = {
|
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
|
|
121
|
-
const userWithSameEmail = await strapi
|
|
127
|
+
const userWithSameEmail = await strapi.db
|
|
122
128
|
.query('plugin::users-permissions.user')
|
|
123
129
|
.findOne({ where: { email: email.toLowerCase() } });
|
|
124
130
|
|
|
@@ -143,6 +149,7 @@ module.exports = {
|
|
|
143
149
|
* @return {Object|Array}
|
|
144
150
|
*/
|
|
145
151
|
async find(ctx) {
|
|
152
|
+
await validateQuery(ctx.query, ctx);
|
|
146
153
|
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
147
154
|
const users = await getService('user').fetchAll(sanitizedQuery);
|
|
148
155
|
|
|
@@ -155,6 +162,7 @@ module.exports = {
|
|
|
155
162
|
*/
|
|
156
163
|
async findOne(ctx) {
|
|
157
164
|
const { id } = ctx.params;
|
|
165
|
+
await validateQuery(ctx.query, ctx);
|
|
158
166
|
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
159
167
|
|
|
160
168
|
let data = await getService('user').fetch(id, sanitizedQuery);
|
|
@@ -171,6 +179,7 @@ module.exports = {
|
|
|
171
179
|
* @return {Number}
|
|
172
180
|
*/
|
|
173
181
|
async count(ctx) {
|
|
182
|
+
await validateQuery(ctx.query, ctx);
|
|
174
183
|
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
175
184
|
|
|
176
185
|
ctx.body = await getService('user').count(sanitizedQuery);
|
|
@@ -201,6 +210,7 @@ module.exports = {
|
|
|
201
210
|
return ctx.unauthorized();
|
|
202
211
|
}
|
|
203
212
|
|
|
213
|
+
await validateQuery(query, ctx);
|
|
204
214
|
const sanitizedQuery = await sanitizeQuery(query, ctx);
|
|
205
215
|
const user = await getService('user').fetch(authUser.id, sanitizedQuery);
|
|
206
216
|
|
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const utils = require('@strapi/utils');
|
|
5
|
+
const { isString, has, toLower } = require('lodash/fp');
|
|
6
|
+
|
|
7
|
+
const { RateLimitError } = utils.errors;
|
|
8
|
+
|
|
3
9
|
module.exports =
|
|
4
10
|
(config, { strapi }) =>
|
|
5
11
|
async (ctx, next) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
let rateLimitConfig = strapi.config.get('plugin::users-permissions.ratelimit');
|
|
13
|
+
|
|
14
|
+
if (!rateLimitConfig) {
|
|
15
|
+
rateLimitConfig = {
|
|
16
|
+
enabled: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!has('enabled', rateLimitConfig)) {
|
|
21
|
+
rateLimitConfig.enabled = true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (rateLimitConfig.enabled === true) {
|
|
25
|
+
const rateLimit = require('koa2-ratelimit').RateLimit;
|
|
26
|
+
|
|
27
|
+
const userIdentifier = toLower(ctx.request.body.email) || 'unknownIdentifier';
|
|
28
|
+
const requestPath = isString(ctx.request.path)
|
|
29
|
+
? toLower(path.normalize(ctx.request.path))
|
|
30
|
+
: 'invalidPath';
|
|
31
|
+
|
|
32
|
+
const loadConfig = {
|
|
33
|
+
interval: { min: 5 },
|
|
34
|
+
max: 5,
|
|
35
|
+
prefixKey: `${userIdentifier}:${requestPath}:${ctx.request.ip}`,
|
|
36
|
+
handler() {
|
|
37
|
+
throw new RateLimitError();
|
|
38
|
+
},
|
|
39
|
+
...rateLimitConfig,
|
|
40
|
+
...config,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return rateLimit.middleware(loadConfig)(ctx, next);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return next();
|
|
27
47
|
};
|
package/server/register.js
CHANGED
|
@@ -7,7 +7,7 @@ const authStrategy = require('./strategies/users-permissions');
|
|
|
7
7
|
const sanitizers = require('./utils/sanitize/sanitizers');
|
|
8
8
|
|
|
9
9
|
module.exports = ({ strapi }) => {
|
|
10
|
-
strapi.
|
|
10
|
+
strapi.get('auth').register('content-api', authStrategy);
|
|
11
11
|
strapi.sanitizers.add('content-api.output', sanitizers.defaultSanitizeOutput);
|
|
12
12
|
|
|
13
13
|
if (strapi.plugin('graphql')) {
|
package/server/services/jwt.js
CHANGED
|
@@ -29,10 +29,10 @@ module.exports = ({ strapi }) => ({
|
|
|
29
29
|
},
|
|
30
30
|
|
|
31
31
|
issue(payload, jwtOptions = {}) {
|
|
32
|
-
_.defaults(jwtOptions, strapi.config.get('plugin
|
|
32
|
+
_.defaults(jwtOptions, strapi.config.get('plugin::users-permissions.jwt'));
|
|
33
33
|
return jwt.sign(
|
|
34
34
|
_.clone(payload.toJSON ? payload.toJSON() : payload),
|
|
35
|
-
strapi.config.get('plugin
|
|
35
|
+
strapi.config.get('plugin::users-permissions.jwtSecret'),
|
|
36
36
|
jwtOptions
|
|
37
37
|
);
|
|
38
38
|
},
|
|
@@ -41,7 +41,7 @@ module.exports = ({ strapi }) => ({
|
|
|
41
41
|
return new Promise((resolve, reject) => {
|
|
42
42
|
jwt.verify(
|
|
43
43
|
token,
|
|
44
|
-
strapi.config.get('plugin
|
|
44
|
+
strapi.config.get('plugin::users-permissions.jwtSecret'),
|
|
45
45
|
{},
|
|
46
46
|
(err, tokenPayload = {}) => {
|
|
47
47
|
if (err) {
|
|
@@ -11,11 +11,7 @@ module.exports = ({ strapi }) => ({
|
|
|
11
11
|
* @return {object[]}
|
|
12
12
|
*/
|
|
13
13
|
async findRolePermissions(roleID) {
|
|
14
|
-
return strapi.
|
|
15
|
-
'plugin::users-permissions.role',
|
|
16
|
-
{ id: roleID },
|
|
17
|
-
'permissions'
|
|
18
|
-
);
|
|
14
|
+
return strapi.db.query('plugin::users-permissions.role').load({ id: roleID }, 'permissions');
|
|
19
15
|
},
|
|
20
16
|
|
|
21
17
|
/**
|
|
@@ -24,8 +20,8 @@ module.exports = ({ strapi }) => ({
|
|
|
24
20
|
* @return {object[]}
|
|
25
21
|
*/
|
|
26
22
|
async findPublicPermissions() {
|
|
27
|
-
return strapi.
|
|
28
|
-
|
|
23
|
+
return strapi.db.query('plugin::users-permissions.permission').findMany({
|
|
24
|
+
where: PUBLIC_ROLE_FILTER,
|
|
29
25
|
});
|
|
30
26
|
},
|
|
31
27
|
|