@strapi/plugin-users-permissions 0.0.0-next.e50ef5e2ea57ecf3da5bcf308508b51ee3c0deca → 0.0.0-next.e5b87a54008c9de2b3286a4774635dcf69895d9b

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.
Files changed (149) hide show
  1. package/admin/src/components/Permissions/PermissionRow/SubCategory.jsx +8 -1
  2. package/admin/src/components/Policies/index.jsx +1 -0
  3. package/admin/src/components/UsersPermissions/index.jsx +1 -0
  4. package/admin/src/pages/AdvancedSettings/index.jsx +1 -0
  5. package/admin/src/pages/EmailTemplates/components/EmailForm.jsx +2 -1
  6. package/admin/src/pages/Providers/index.jsx +74 -76
  7. package/admin/src/pages/Roles/pages/CreatePage.jsx +26 -8
  8. package/admin/src/pages/Roles/pages/EditPage.jsx +13 -7
  9. package/admin/src/pages/Roles/pages/ListPage/index.jsx +92 -93
  10. package/admin/src/translations/de.json +27 -2
  11. package/admin/src/translations/en.json +1 -0
  12. package/dist/admin/components/FormModal/Input/index.js.map +1 -1
  13. package/dist/admin/components/FormModal/Input/index.mjs.map +1 -1
  14. package/dist/admin/components/Permissions/PermissionRow/SubCategory.js +3 -1
  15. package/dist/admin/components/Permissions/PermissionRow/SubCategory.js.map +1 -1
  16. package/dist/admin/components/Permissions/PermissionRow/SubCategory.mjs +3 -1
  17. package/dist/admin/components/Permissions/PermissionRow/SubCategory.mjs.map +1 -1
  18. package/dist/admin/components/Permissions/PermissionRow/index.js.map +1 -1
  19. package/dist/admin/components/Permissions/PermissionRow/index.mjs.map +1 -1
  20. package/dist/admin/components/Policies/index.js +1 -0
  21. package/dist/admin/components/Policies/index.js.map +1 -1
  22. package/dist/admin/components/Policies/index.mjs +1 -0
  23. package/dist/admin/components/Policies/index.mjs.map +1 -1
  24. package/dist/admin/components/UsersPermissions/index.js +1 -0
  25. package/dist/admin/components/UsersPermissions/index.js.map +1 -1
  26. package/dist/admin/components/UsersPermissions/index.mjs +1 -0
  27. package/dist/admin/components/UsersPermissions/index.mjs.map +1 -1
  28. package/dist/admin/pages/AdvancedSettings/index.js +1 -0
  29. package/dist/admin/pages/AdvancedSettings/index.js.map +1 -1
  30. package/dist/admin/pages/AdvancedSettings/index.mjs +1 -0
  31. package/dist/admin/pages/AdvancedSettings/index.mjs.map +1 -1
  32. package/dist/admin/pages/EmailTemplates/components/EmailForm.js +2 -1
  33. package/dist/admin/pages/EmailTemplates/components/EmailForm.js.map +1 -1
  34. package/dist/admin/pages/EmailTemplates/components/EmailForm.mjs +2 -1
  35. package/dist/admin/pages/EmailTemplates/components/EmailForm.mjs.map +1 -1
  36. package/dist/admin/pages/Providers/index.js +84 -88
  37. package/dist/admin/pages/Providers/index.js.map +1 -1
  38. package/dist/admin/pages/Providers/index.mjs +84 -88
  39. package/dist/admin/pages/Providers/index.mjs.map +1 -1
  40. package/dist/admin/pages/Roles/pages/CreatePage.js +15 -1
  41. package/dist/admin/pages/Roles/pages/CreatePage.js.map +1 -1
  42. package/dist/admin/pages/Roles/pages/CreatePage.mjs +17 -3
  43. package/dist/admin/pages/Roles/pages/CreatePage.mjs.map +1 -1
  44. package/dist/admin/pages/Roles/pages/EditPage.js +14 -3
  45. package/dist/admin/pages/Roles/pages/EditPage.js.map +1 -1
  46. package/dist/admin/pages/Roles/pages/EditPage.mjs +15 -4
  47. package/dist/admin/pages/Roles/pages/EditPage.mjs.map +1 -1
  48. package/dist/admin/pages/Roles/pages/ListPage/components/TableBody.js.map +1 -1
  49. package/dist/admin/pages/Roles/pages/ListPage/components/TableBody.mjs.map +1 -1
  50. package/dist/admin/pages/Roles/pages/ListPage/index.js +96 -99
  51. package/dist/admin/pages/Roles/pages/ListPage/index.js.map +1 -1
  52. package/dist/admin/pages/Roles/pages/ListPage/index.mjs +96 -99
  53. package/dist/admin/pages/Roles/pages/ListPage/index.mjs.map +1 -1
  54. package/dist/admin/translations/de.json.js +27 -2
  55. package/dist/admin/translations/de.json.js.map +1 -1
  56. package/dist/admin/translations/de.json.mjs +27 -2
  57. package/dist/admin/translations/de.json.mjs.map +1 -1
  58. package/dist/admin/translations/en.json.js +1 -0
  59. package/dist/admin/translations/en.json.js.map +1 -1
  60. package/dist/admin/translations/en.json.mjs +1 -0
  61. package/dist/admin/translations/en.json.mjs.map +1 -1
  62. package/dist/admin/utils/getTrad.js.map +1 -1
  63. package/dist/admin/utils/getTrad.mjs.map +1 -1
  64. package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
  65. package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
  66. package/dist/server/bootstrap/index.js +28 -7
  67. package/dist/server/bootstrap/index.js.map +1 -1
  68. package/dist/server/bootstrap/index.mjs +28 -7
  69. package/dist/server/bootstrap/index.mjs.map +1 -1
  70. package/dist/server/config.js +16 -0
  71. package/dist/server/config.js.map +1 -1
  72. package/dist/server/config.mjs +16 -0
  73. package/dist/server/config.mjs.map +1 -1
  74. package/dist/server/controllers/auth.js +204 -3
  75. package/dist/server/controllers/auth.js.map +1 -1
  76. package/dist/server/controllers/auth.mjs +204 -3
  77. package/dist/server/controllers/auth.mjs.map +1 -1
  78. package/dist/server/controllers/content-manager-user.js +3 -3
  79. package/dist/server/controllers/content-manager-user.js.map +1 -1
  80. package/dist/server/controllers/content-manager-user.mjs +3 -3
  81. package/dist/server/controllers/content-manager-user.mjs.map +1 -1
  82. package/dist/server/controllers/validation/user.js +6 -1
  83. package/dist/server/controllers/validation/user.js.map +1 -1
  84. package/dist/server/controllers/validation/user.mjs +6 -1
  85. package/dist/server/controllers/validation/user.mjs.map +1 -1
  86. package/dist/server/graphql/resolvers-configs.js.map +1 -1
  87. package/dist/server/graphql/resolvers-configs.mjs.map +1 -1
  88. package/dist/server/middlewares/rateLimit.js.map +1 -1
  89. package/dist/server/middlewares/rateLimit.mjs.map +1 -1
  90. package/dist/server/routes/content-api/auth.js +155 -91
  91. package/dist/server/routes/content-api/auth.js.map +1 -1
  92. package/dist/server/routes/content-api/auth.mjs +155 -91
  93. package/dist/server/routes/content-api/auth.mjs.map +1 -1
  94. package/dist/server/routes/content-api/index.js +11 -9
  95. package/dist/server/routes/content-api/index.js.map +1 -1
  96. package/dist/server/routes/content-api/index.mjs +11 -9
  97. package/dist/server/routes/content-api/index.mjs.map +1 -1
  98. package/dist/server/routes/content-api/permissions.js +14 -7
  99. package/dist/server/routes/content-api/permissions.js.map +1 -1
  100. package/dist/server/routes/content-api/permissions.mjs +14 -7
  101. package/dist/server/routes/content-api/permissions.mjs.map +1 -1
  102. package/dist/server/routes/content-api/role.js +61 -27
  103. package/dist/server/routes/content-api/role.js.map +1 -1
  104. package/dist/server/routes/content-api/role.mjs +61 -27
  105. package/dist/server/routes/content-api/role.mjs.map +1 -1
  106. package/dist/server/routes/content-api/user.js +119 -57
  107. package/dist/server/routes/content-api/user.js.map +1 -1
  108. package/dist/server/routes/content-api/user.mjs +119 -57
  109. package/dist/server/routes/content-api/user.mjs.map +1 -1
  110. package/dist/server/routes/content-api/validation.js +217 -0
  111. package/dist/server/routes/content-api/validation.js.map +1 -0
  112. package/dist/server/routes/content-api/validation.mjs +215 -0
  113. package/dist/server/routes/content-api/validation.mjs.map +1 -0
  114. package/dist/server/services/constants.js +19 -0
  115. package/dist/server/services/constants.js.map +1 -0
  116. package/dist/server/services/constants.mjs +17 -0
  117. package/dist/server/services/constants.mjs.map +1 -0
  118. package/dist/server/services/jwt.js +45 -2
  119. package/dist/server/services/jwt.js.map +1 -1
  120. package/dist/server/services/jwt.mjs +45 -2
  121. package/dist/server/services/jwt.mjs.map +1 -1
  122. package/dist/server/services/providers-registry.js.map +1 -1
  123. package/dist/server/services/providers-registry.mjs.map +1 -1
  124. package/dist/server/services/role.js.map +1 -1
  125. package/dist/server/services/role.mjs.map +1 -1
  126. package/dist/server/services/user.js +29 -20
  127. package/dist/server/services/user.js.map +1 -1
  128. package/dist/server/services/user.mjs +29 -20
  129. package/dist/server/services/user.mjs.map +1 -1
  130. package/dist/server/services/users-permissions.js +12 -3
  131. package/dist/server/services/users-permissions.js.map +1 -1
  132. package/dist/server/services/users-permissions.mjs +12 -3
  133. package/dist/server/services/users-permissions.mjs.map +1 -1
  134. package/package.json +13 -12
  135. package/server/bootstrap/index.js +31 -0
  136. package/server/config.js +22 -0
  137. package/server/controllers/auth.js +246 -8
  138. package/server/controllers/content-manager-user.js +3 -4
  139. package/server/controllers/validation/user.js +12 -1
  140. package/server/routes/content-api/auth.js +119 -71
  141. package/server/routes/content-api/index.js +11 -4
  142. package/server/routes/content-api/permissions.js +14 -7
  143. package/server/routes/content-api/role.js +57 -27
  144. package/server/routes/content-api/user.js +108 -51
  145. package/server/routes/content-api/validation.js +250 -0
  146. package/server/services/constants.js +9 -0
  147. package/server/services/jwt.js +50 -2
  148. package/server/services/user.js +11 -0
  149. package/server/services/users-permissions.js +6 -2
@@ -31,6 +31,12 @@ const sanitizeUser = (user, ctx) => {
31
31
  return strapi.contentAPI.sanitize.output(user, userSchema, { auth });
32
32
  };
33
33
 
34
+ const extractDeviceId = (requestBody) => {
35
+ const { deviceId } = requestBody || {};
36
+
37
+ return typeof deviceId === 'string' && deviceId.length > 0 ? deviceId : undefined;
38
+ };
39
+
34
40
  module.exports = ({ strapi }) => ({
35
41
  async callback(ctx) {
36
42
  const provider = ctx.params.provider || 'local';
@@ -86,6 +92,51 @@ module.exports = ({ strapi }) => ({
86
92
  throw new ApplicationError('Your account has been blocked by an administrator');
87
93
  }
88
94
 
95
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
96
+ if (mode === 'refresh') {
97
+ const deviceId = extractDeviceId(ctx.request.body);
98
+
99
+ const refresh = await strapi
100
+ .sessionManager('users-permissions')
101
+ .generateRefreshToken(String(user.id), deviceId, { type: 'refresh' });
102
+
103
+ const access = await strapi
104
+ .sessionManager('users-permissions')
105
+ .generateAccessToken(refresh.token);
106
+ if ('error' in access) {
107
+ throw new ApplicationError('Invalid credentials');
108
+ }
109
+
110
+ const upSessions = strapi.config.get('plugin::users-permissions.sessions');
111
+ const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
112
+ if (upSessions?.httpOnly || requestHttpOnly) {
113
+ const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
114
+ const isProduction = process.env.NODE_ENV === 'production';
115
+ const isSecure =
116
+ typeof upSessions.cookie?.secure === 'boolean'
117
+ ? upSessions.cookie?.secure
118
+ : isProduction;
119
+
120
+ const cookieOptions = {
121
+ httpOnly: true,
122
+ secure: isSecure,
123
+ sameSite: upSessions.cookie?.sameSite ?? 'lax',
124
+ path: upSessions.cookie?.path ?? '/',
125
+ domain: upSessions.cookie?.domain,
126
+ overwrite: true,
127
+ };
128
+
129
+ ctx.cookies.set(cookieName, refresh.token, cookieOptions);
130
+ return ctx.send({ jwt: access.token, user: await sanitizeUser(user, ctx) });
131
+ }
132
+
133
+ return ctx.send({
134
+ jwt: access.token,
135
+ refreshToken: refresh.token,
136
+ user: await sanitizeUser(user, ctx),
137
+ });
138
+ }
139
+
89
140
  return ctx.send({
90
141
  jwt: getService('jwt').issue({ id: user.id }),
91
142
  user: await sanitizeUser(user, ctx),
@@ -100,6 +151,49 @@ module.exports = ({ strapi }) => ({
100
151
  throw new ForbiddenError('Your account has been blocked by an administrator');
101
152
  }
102
153
 
154
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
155
+ if (mode === 'refresh') {
156
+ const deviceId = extractDeviceId(ctx.request.body);
157
+
158
+ const refresh = await strapi
159
+ .sessionManager('users-permissions')
160
+ .generateRefreshToken(String(user.id), deviceId, { type: 'refresh' });
161
+
162
+ const access = await strapi
163
+ .sessionManager('users-permissions')
164
+ .generateAccessToken(refresh.token);
165
+ if ('error' in access) {
166
+ throw new ApplicationError('Invalid credentials');
167
+ }
168
+
169
+ const upSessions = strapi.config.get('plugin::users-permissions.sessions');
170
+ const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
171
+ if (upSessions?.httpOnly || requestHttpOnly) {
172
+ const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
173
+ const isProduction = process.env.NODE_ENV === 'production';
174
+ const isSecure =
175
+ typeof upSessions.cookie?.secure === 'boolean'
176
+ ? upSessions.cookie?.secure
177
+ : isProduction;
178
+
179
+ const cookieOptions = {
180
+ httpOnly: true,
181
+ secure: isSecure,
182
+ sameSite: upSessions.cookie?.sameSite ?? 'lax',
183
+ path: upSessions.cookie?.path ?? '/',
184
+ domain: upSessions.cookie?.domain,
185
+ overwrite: true,
186
+ };
187
+ ctx.cookies.set(cookieName, refresh.token, cookieOptions);
188
+ return ctx.send({ jwt: access.token, user: await sanitizeUser(user, ctx) });
189
+ }
190
+ return ctx.send({
191
+ jwt: access.token,
192
+ refreshToken: refresh.token,
193
+ user: await sanitizeUser(user, ctx),
194
+ });
195
+ }
196
+
103
197
  return ctx.send({
104
198
  jwt: getService('jwt').issue({ id: user.id }),
105
199
  user: await sanitizeUser(user, ctx),
@@ -137,7 +231,33 @@ module.exports = ({ strapi }) => ({
137
231
 
138
232
  await getService('user').edit(user.id, { password });
139
233
 
140
- ctx.send({
234
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
235
+ if (mode === 'refresh') {
236
+ const deviceId = extractDeviceId(ctx.request.body);
237
+
238
+ // Invalidate all sessions when password changes for security
239
+ await strapi.sessionManager('users-permissions').invalidateRefreshToken(String(user.id));
240
+
241
+ const newDeviceId = deviceId || crypto.randomUUID();
242
+ const refresh = await strapi
243
+ .sessionManager('users-permissions')
244
+ .generateRefreshToken(String(user.id), newDeviceId, { type: 'refresh' });
245
+
246
+ const access = await strapi
247
+ .sessionManager('users-permissions')
248
+ .generateAccessToken(refresh.token);
249
+ if ('error' in access) {
250
+ throw new ApplicationError('Invalid credentials');
251
+ }
252
+
253
+ return ctx.send({
254
+ jwt: access.token,
255
+ refreshToken: refresh.token,
256
+ user: await sanitizeUser(user, ctx),
257
+ });
258
+ }
259
+
260
+ return ctx.send({
141
261
  jwt: getService('jwt').issue({ id: user.id }),
142
262
  user: await sanitizeUser(user, ctx),
143
263
  });
@@ -168,13 +288,117 @@ module.exports = ({ strapi }) => ({
168
288
  password,
169
289
  });
170
290
 
171
- // Update the user.
172
- ctx.send({
291
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
292
+ if (mode === 'refresh') {
293
+ const deviceId = extractDeviceId(ctx.request.body);
294
+
295
+ // Invalidate all sessions when password is reset for security
296
+ await strapi.sessionManager('users-permissions').invalidateRefreshToken(String(user.id));
297
+
298
+ const newDeviceId = deviceId || crypto.randomUUID();
299
+ const refresh = await strapi
300
+ .sessionManager('users-permissions')
301
+ .generateRefreshToken(String(user.id), newDeviceId, { type: 'refresh' });
302
+
303
+ const access = await strapi
304
+ .sessionManager('users-permissions')
305
+ .generateAccessToken(refresh.token);
306
+ if ('error' in access) {
307
+ throw new ApplicationError('Invalid credentials');
308
+ }
309
+
310
+ return ctx.send({
311
+ jwt: access.token,
312
+ refreshToken: refresh.token,
313
+ user: await sanitizeUser(user, ctx),
314
+ });
315
+ }
316
+
317
+ return ctx.send({
173
318
  jwt: getService('jwt').issue({ id: user.id }),
174
319
  user: await sanitizeUser(user, ctx),
175
320
  });
176
321
  },
322
+ async refresh(ctx) {
323
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
324
+ if (mode !== 'refresh') {
325
+ return ctx.notFound();
326
+ }
327
+
328
+ const upSessions = strapi.config.get('plugin::users-permissions.sessions');
329
+ const cookieName = upSessions?.cookie?.name || 'strapi_up_refresh';
330
+
331
+ // Check for refresh token in cookie first (if httpOnly is configured), then in body
332
+ let refreshToken = ctx.cookies.get(cookieName);
333
+ if (!refreshToken) {
334
+ refreshToken = ctx.request.body?.refreshToken;
335
+ }
336
+
337
+ if (!refreshToken || typeof refreshToken !== 'string') {
338
+ return ctx.badRequest('Missing refresh token');
339
+ }
340
+
341
+ const rotation = await strapi
342
+ .sessionManager('users-permissions')
343
+ .rotateRefreshToken(refreshToken);
344
+ if ('error' in rotation) {
345
+ return ctx.unauthorized('Invalid refresh token');
346
+ }
177
347
 
348
+ const result = await strapi
349
+ .sessionManager('users-permissions')
350
+ .generateAccessToken(rotation.token);
351
+ if ('error' in result) {
352
+ return ctx.unauthorized('Invalid refresh token');
353
+ }
354
+
355
+ const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
356
+ if (upSessions?.httpOnly || requestHttpOnly) {
357
+ const isProduction = process.env.NODE_ENV === 'production';
358
+ const isSecure =
359
+ typeof upSessions.cookie?.secure === 'boolean' ? upSessions.cookie?.secure : isProduction;
360
+
361
+ const cookieOptions = {
362
+ httpOnly: true,
363
+ secure: isSecure,
364
+ sameSite: upSessions.cookie?.sameSite ?? 'lax',
365
+ path: upSessions.cookie?.path ?? '/',
366
+ domain: upSessions.cookie?.domain,
367
+ overwrite: true,
368
+ };
369
+ ctx.cookies.set(cookieName, rotation.token, cookieOptions);
370
+ return ctx.send({ jwt: result.token });
371
+ }
372
+ return ctx.send({ jwt: result.token, refreshToken: rotation.token });
373
+ },
374
+ async logout(ctx) {
375
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
376
+ if (mode !== 'refresh') {
377
+ return ctx.notFound();
378
+ }
379
+
380
+ // Invalidate all sessions for the authenticated user, or by deviceId if provided
381
+ if (!ctx.state.user) {
382
+ return ctx.unauthorized('Missing authentication');
383
+ }
384
+
385
+ const deviceId = extractDeviceId(ctx.request.body);
386
+ try {
387
+ await strapi
388
+ .sessionManager('users-permissions')
389
+ .invalidateRefreshToken(String(ctx.state.user.id), deviceId);
390
+ } catch (err) {
391
+ strapi.log.error('UP logout failed', err);
392
+ }
393
+
394
+ const upSessions = strapi.config.get('plugin::users-permissions.sessions');
395
+ const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
396
+ if (upSessions?.httpOnly || requestHttpOnly) {
397
+ const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
398
+ ctx.cookies.set(cookieName, '', { expires: new Date(0) });
399
+ }
400
+ return ctx.send({ ok: true });
401
+ },
178
402
  async connect(ctx, next) {
179
403
  const grant = require('grant').koa();
180
404
 
@@ -387,12 +611,26 @@ module.exports = ({ strapi }) => ({
387
611
  return ctx.send({ user: sanitizedUser });
388
612
  }
389
613
 
390
- const jwt = getService('jwt').issue(_.pick(user, ['id']));
614
+ const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
615
+ if (mode === 'refresh') {
616
+ const deviceId = extractDeviceId(ctx.request.body) || crypto.randomUUID();
391
617
 
392
- return ctx.send({
393
- jwt,
394
- user: sanitizedUser,
395
- });
618
+ const refresh = await strapi
619
+ .sessionManager('users-permissions')
620
+ .generateRefreshToken(String(user.id), deviceId, { type: 'refresh' });
621
+
622
+ const access = await strapi
623
+ .sessionManager('users-permissions')
624
+ .generateAccessToken(refresh.token);
625
+ if ('error' in access) {
626
+ throw new ApplicationError('Invalid credentials');
627
+ }
628
+
629
+ return ctx.send({ jwt: access.token, refreshToken: refresh.token, user: sanitizedUser });
630
+ }
631
+
632
+ const jwt = getService('jwt').issue(_.pick(user, ['id']));
633
+ return ctx.send({ jwt, user: sanitizedUser });
396
634
  },
397
635
 
398
636
  async emailConfirmation(ctx, next, returnUser) {
@@ -2,8 +2,7 @@
2
2
 
3
3
  const _ = require('lodash');
4
4
  const { contentTypes: contentTypesUtils } = require('@strapi/utils');
5
- const { ApplicationError, ValidationError, NotFoundError, ForbiddenError } =
6
- require('@strapi/utils').errors;
5
+ const { ApplicationError, NotFoundError, ForbiddenError } = require('@strapi/utils').errors;
7
6
  const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
8
7
 
9
8
  const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
@@ -133,8 +132,8 @@ module.exports = {
133
132
 
134
133
  await validateUpdateUserBody(ctx.request.body);
135
134
 
136
- if (_.has(body, 'password') && !password && user.provider === 'local') {
137
- throw new ValidationError('password.notNull');
135
+ if (_.has(body, 'password') && (password == null || password === '')) {
136
+ delete body.password;
138
137
  }
139
138
 
140
139
  if (_.has(body, 'username')) {
@@ -29,7 +29,18 @@ const createUserBodySchema = yup.object().shape({
29
29
  const updateUserBodySchema = yup.object().shape({
30
30
  email: yup.string().email().min(1),
31
31
  username: yup.string().min(1),
32
- password: yup.string().min(1),
32
+ password: yup
33
+ .mixed()
34
+ .test(
35
+ 'password-validation',
36
+ 'Password must be at least 1 character',
37
+ function validatePassword(value) {
38
+ if (value == null || value === '') {
39
+ return true;
40
+ }
41
+ return typeof value === 'string' && value.length >= 1;
42
+ }
43
+ ),
33
44
  role: yup.lazy((value) =>
34
45
  typeof value === 'object'
35
46
  ? yup.object().shape({
@@ -1,82 +1,130 @@
1
1
  'use strict';
2
2
 
3
- module.exports = [
4
- {
5
- method: 'GET',
6
- path: '/connect/(.*)',
7
- handler: 'auth.connect',
8
- config: {
9
- middlewares: ['plugin::users-permissions.rateLimit'],
10
- prefix: '',
3
+ const { UsersPermissionsRouteValidator } = require('./validation');
4
+
5
+ module.exports = (strapi) => {
6
+ const validator = new UsersPermissionsRouteValidator(strapi);
7
+
8
+ return [
9
+ {
10
+ method: 'GET',
11
+ path: '/connect/(.*)',
12
+ handler: 'auth.connect',
13
+ config: {
14
+ middlewares: ['plugin::users-permissions.rateLimit'],
15
+ prefix: '',
16
+ },
17
+ },
18
+ {
19
+ method: 'POST',
20
+ path: '/auth/local',
21
+ handler: 'auth.callback',
22
+ config: {
23
+ middlewares: ['plugin::users-permissions.rateLimit'],
24
+ prefix: '',
25
+ },
26
+ request: {
27
+ body: { 'application/json': validator.loginBodySchema },
28
+ },
29
+ response: validator.authResponseSchema,
30
+ },
31
+ {
32
+ method: 'POST',
33
+ path: '/auth/local/register',
34
+ handler: 'auth.register',
35
+ config: {
36
+ middlewares: ['plugin::users-permissions.rateLimit'],
37
+ prefix: '',
38
+ },
39
+ request: {
40
+ body: { 'application/json': validator.registerBodySchema },
41
+ },
42
+ response: validator.authRegisterResponseSchema,
11
43
  },
12
- },
13
- {
14
- method: 'POST',
15
- path: '/auth/local',
16
- handler: 'auth.callback',
17
- config: {
18
- middlewares: ['plugin::users-permissions.rateLimit'],
19
- prefix: '',
44
+ {
45
+ method: 'GET',
46
+ path: '/auth/:provider/callback',
47
+ handler: 'auth.callback',
48
+ config: {
49
+ prefix: '',
50
+ },
51
+ request: {
52
+ params: {
53
+ provider: validator.providerParam,
54
+ },
55
+ },
56
+ response: validator.authResponseSchema,
20
57
  },
21
- },
22
- {
23
- method: 'POST',
24
- path: '/auth/local/register',
25
- handler: 'auth.register',
26
- config: {
27
- middlewares: ['plugin::users-permissions.rateLimit'],
28
- prefix: '',
58
+ {
59
+ method: 'POST',
60
+ path: '/auth/forgot-password',
61
+ handler: 'auth.forgotPassword',
62
+ config: {
63
+ middlewares: ['plugin::users-permissions.rateLimit'],
64
+ prefix: '',
65
+ },
66
+ request: {
67
+ body: { 'application/json': validator.forgotPasswordBodySchema },
68
+ },
69
+ response: validator.forgotPasswordResponseSchema,
29
70
  },
30
- },
31
- {
32
- method: 'GET',
33
- path: '/auth/:provider/callback',
34
- handler: 'auth.callback',
35
- config: {
36
- prefix: '',
71
+ {
72
+ method: 'POST',
73
+ path: '/auth/reset-password',
74
+ handler: 'auth.resetPassword',
75
+ config: {
76
+ middlewares: ['plugin::users-permissions.rateLimit'],
77
+ prefix: '',
78
+ },
79
+ request: {
80
+ body: { 'application/json': validator.resetPasswordBodySchema },
81
+ },
82
+ response: validator.authResponseSchema,
37
83
  },
38
- },
39
- {
40
- method: 'POST',
41
- path: '/auth/forgot-password',
42
- handler: 'auth.forgotPassword',
43
- config: {
44
- middlewares: ['plugin::users-permissions.rateLimit'],
45
- prefix: '',
84
+ {
85
+ method: 'GET',
86
+ path: '/auth/email-confirmation',
87
+ handler: 'auth.emailConfirmation',
88
+ config: {
89
+ prefix: '',
90
+ },
46
91
  },
47
- },
48
- {
49
- method: 'POST',
50
- path: '/auth/reset-password',
51
- handler: 'auth.resetPassword',
52
- config: {
53
- middlewares: ['plugin::users-permissions.rateLimit'],
54
- prefix: '',
92
+ {
93
+ method: 'POST',
94
+ path: '/auth/send-email-confirmation',
95
+ handler: 'auth.sendEmailConfirmation',
96
+ config: {
97
+ prefix: '',
98
+ },
99
+ request: {
100
+ body: { 'application/json': validator.sendEmailConfirmationBodySchema },
101
+ },
102
+ response: validator.sendEmailConfirmationResponseSchema,
55
103
  },
56
- },
57
- {
58
- method: 'GET',
59
- path: '/auth/email-confirmation',
60
- handler: 'auth.emailConfirmation',
61
- config: {
62
- prefix: '',
104
+ {
105
+ method: 'POST',
106
+ path: '/auth/change-password',
107
+ handler: 'auth.changePassword',
108
+ config: {
109
+ middlewares: ['plugin::users-permissions.rateLimit'],
110
+ prefix: '',
111
+ },
112
+ request: {
113
+ body: { 'application/json': validator.changePasswordBodySchema },
114
+ },
115
+ response: validator.authResponseSchema,
63
116
  },
64
- },
65
- {
66
- method: 'POST',
67
- path: '/auth/send-email-confirmation',
68
- handler: 'auth.sendEmailConfirmation',
69
- config: {
70
- prefix: '',
117
+ {
118
+ method: 'POST',
119
+ path: '/auth/refresh',
120
+ handler: 'auth.refresh',
121
+ config: { prefix: '' },
71
122
  },
72
- },
73
- {
74
- method: 'POST',
75
- path: '/auth/change-password',
76
- handler: 'auth.changePassword',
77
- config: {
78
- middlewares: ['plugin::users-permissions.rateLimit'],
79
- prefix: '',
123
+ {
124
+ method: 'POST',
125
+ path: '/auth/logout',
126
+ handler: 'auth.logout',
127
+ config: { prefix: '' },
80
128
  },
81
- },
82
- ];
129
+ ];
130
+ };
@@ -1,11 +1,18 @@
1
1
  'use strict';
2
2
 
3
+ const { createContentApiRoutesFactory } = require('@strapi/utils');
3
4
  const authRoutes = require('./auth');
4
5
  const userRoutes = require('./user');
5
6
  const roleRoutes = require('./role');
6
7
  const permissionsRoutes = require('./permissions');
7
8
 
8
- module.exports = {
9
- type: 'content-api',
10
- routes: [...authRoutes, ...userRoutes, ...roleRoutes, ...permissionsRoutes],
11
- };
9
+ const createContentApiRoutes = createContentApiRoutesFactory(() => {
10
+ return [
11
+ ...authRoutes(strapi),
12
+ ...userRoutes(strapi),
13
+ ...roleRoutes(strapi),
14
+ ...permissionsRoutes(strapi),
15
+ ];
16
+ });
17
+
18
+ module.exports = createContentApiRoutes;
@@ -1,9 +1,16 @@
1
1
  'use strict';
2
2
 
3
- module.exports = [
4
- {
5
- method: 'GET',
6
- path: '/permissions',
7
- handler: 'permissions.getPermissions',
8
- },
9
- ];
3
+ const { UsersPermissionsRouteValidator } = require('./validation');
4
+
5
+ module.exports = (strapi) => {
6
+ const validator = new UsersPermissionsRouteValidator(strapi);
7
+
8
+ return [
9
+ {
10
+ method: 'GET',
11
+ path: '/permissions',
12
+ handler: 'permissions.getPermissions',
13
+ response: validator.permissionsResponseSchema,
14
+ },
15
+ ];
16
+ };
@@ -1,29 +1,59 @@
1
1
  'use strict';
2
2
 
3
- module.exports = [
4
- {
5
- method: 'GET',
6
- path: '/roles/:id',
7
- handler: 'role.findOne',
8
- },
9
- {
10
- method: 'GET',
11
- path: '/roles',
12
- handler: 'role.find',
13
- },
14
- {
15
- method: 'POST',
16
- path: '/roles',
17
- handler: 'role.createRole',
18
- },
19
- {
20
- method: 'PUT',
21
- path: '/roles/:role',
22
- handler: 'role.updateRole',
23
- },
24
- {
25
- method: 'DELETE',
26
- path: '/roles/:role',
27
- handler: 'role.deleteRole',
28
- },
29
- ];
3
+ const { UsersPermissionsRouteValidator } = require('./validation');
4
+
5
+ module.exports = (strapi) => {
6
+ const validator = new UsersPermissionsRouteValidator(strapi);
7
+
8
+ return [
9
+ {
10
+ method: 'GET',
11
+ path: '/roles/:id',
12
+ handler: 'role.findOne',
13
+ request: {
14
+ params: {
15
+ id: validator.roleIdParam,
16
+ },
17
+ },
18
+ response: validator.roleResponseSchema,
19
+ },
20
+ {
21
+ method: 'GET',
22
+ path: '/roles',
23
+ handler: 'role.find',
24
+ response: validator.rolesResponseSchema,
25
+ },
26
+ {
27
+ method: 'POST',
28
+ path: '/roles',
29
+ handler: 'role.createRole',
30
+ request: {
31
+ body: { 'application/json': validator.createRoleBodySchema },
32
+ },
33
+ response: validator.roleSuccessResponseSchema,
34
+ },
35
+ {
36
+ method: 'PUT',
37
+ path: '/roles/:role',
38
+ handler: 'role.updateRole',
39
+ request: {
40
+ params: {
41
+ role: validator.roleIdParam,
42
+ },
43
+ body: { 'application/json': validator.updateRoleBodySchema },
44
+ },
45
+ response: validator.roleSuccessResponseSchema,
46
+ },
47
+ {
48
+ method: 'DELETE',
49
+ path: '/roles/:role',
50
+ handler: 'role.deleteRole',
51
+ request: {
52
+ params: {
53
+ role: validator.roleIdParam,
54
+ },
55
+ },
56
+ response: validator.roleSuccessResponseSchema,
57
+ },
58
+ ];
59
+ };