@strapi/plugin-users-permissions 0.0.0-next.e21fe90bf2ab9906267ea6e6ca620bdcc729906c → 0.0.0-next.e326c69a49373b420f6566c30aca26f4b6274c6a
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/pages/Providers/index.jsx +74 -76
- package/admin/src/pages/Roles/pages/CreatePage.jsx +3 -12
- package/admin/src/pages/Roles/pages/EditPage.jsx +3 -12
- package/admin/src/pages/Roles/pages/ListPage/index.jsx +91 -93
- package/admin/src/utils/formatPluginName.js +1 -1
- package/dist/admin/pages/Providers/index.js +84 -88
- package/dist/admin/pages/Providers/index.js.map +1 -1
- package/dist/admin/pages/Providers/index.mjs +84 -88
- package/dist/admin/pages/Providers/index.mjs.map +1 -1
- package/dist/admin/pages/Roles/pages/CreatePage.js +1 -1
- package/dist/admin/pages/Roles/pages/CreatePage.js.map +1 -1
- package/dist/admin/pages/Roles/pages/CreatePage.mjs +2 -2
- package/dist/admin/pages/Roles/pages/CreatePage.mjs.map +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.js +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.js.map +1 -1
- package/dist/admin/pages/Roles/pages/EditPage.mjs +2 -2
- package/dist/admin/pages/Roles/pages/EditPage.mjs.map +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.js +95 -99
- package/dist/admin/pages/Roles/pages/ListPage/index.js.map +1 -1
- package/dist/admin/pages/Roles/pages/ListPage/index.mjs +95 -99
- package/dist/admin/pages/Roles/pages/ListPage/index.mjs.map +1 -1
- package/dist/admin/utils/formatPluginName.js +1 -1
- package/dist/admin/utils/formatPluginName.js.map +1 -1
- package/dist/admin/utils/formatPluginName.mjs +1 -1
- package/dist/admin/utils/formatPluginName.mjs.map +1 -1
- package/dist/server/bootstrap/index.js +28 -7
- package/dist/server/bootstrap/index.js.map +1 -1
- package/dist/server/bootstrap/index.mjs +28 -7
- package/dist/server/bootstrap/index.mjs.map +1 -1
- package/dist/server/config.js +16 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +16 -0
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/controllers/auth.js +198 -3
- package/dist/server/controllers/auth.js.map +1 -1
- package/dist/server/controllers/auth.mjs +198 -3
- package/dist/server/controllers/auth.mjs.map +1 -1
- package/dist/server/controllers/content-manager-user.js +3 -3
- package/dist/server/controllers/content-manager-user.js.map +1 -1
- package/dist/server/controllers/content-manager-user.mjs +3 -3
- package/dist/server/controllers/content-manager-user.mjs.map +1 -1
- package/dist/server/controllers/validation/user.js +6 -1
- package/dist/server/controllers/validation/user.js.map +1 -1
- package/dist/server/controllers/validation/user.mjs +6 -1
- package/dist/server/controllers/validation/user.mjs.map +1 -1
- package/dist/server/routes/content-api/auth.js +155 -91
- package/dist/server/routes/content-api/auth.js.map +1 -1
- package/dist/server/routes/content-api/auth.mjs +155 -91
- package/dist/server/routes/content-api/auth.mjs.map +1 -1
- package/dist/server/routes/content-api/index.js +11 -9
- package/dist/server/routes/content-api/index.js.map +1 -1
- package/dist/server/routes/content-api/index.mjs +11 -9
- package/dist/server/routes/content-api/index.mjs.map +1 -1
- package/dist/server/routes/content-api/permissions.js +14 -7
- package/dist/server/routes/content-api/permissions.js.map +1 -1
- package/dist/server/routes/content-api/permissions.mjs +14 -7
- package/dist/server/routes/content-api/permissions.mjs.map +1 -1
- package/dist/server/routes/content-api/role.js +61 -27
- package/dist/server/routes/content-api/role.js.map +1 -1
- package/dist/server/routes/content-api/role.mjs +61 -27
- package/dist/server/routes/content-api/role.mjs.map +1 -1
- package/dist/server/routes/content-api/user.js +119 -57
- package/dist/server/routes/content-api/user.js.map +1 -1
- package/dist/server/routes/content-api/user.mjs +119 -57
- package/dist/server/routes/content-api/user.mjs.map +1 -1
- package/dist/server/routes/content-api/validation.js +217 -0
- package/dist/server/routes/content-api/validation.js.map +1 -0
- package/dist/server/routes/content-api/validation.mjs +215 -0
- package/dist/server/routes/content-api/validation.mjs.map +1 -0
- package/dist/server/services/constants.js +19 -0
- package/dist/server/services/constants.js.map +1 -0
- package/dist/server/services/constants.mjs +17 -0
- package/dist/server/services/constants.mjs.map +1 -0
- package/dist/server/services/jwt.js +45 -2
- package/dist/server/services/jwt.js.map +1 -1
- package/dist/server/services/jwt.mjs +45 -2
- package/dist/server/services/jwt.mjs.map +1 -1
- package/dist/server/services/user.js +29 -20
- package/dist/server/services/user.js.map +1 -1
- package/dist/server/services/user.mjs +29 -20
- package/dist/server/services/user.mjs.map +1 -1
- package/dist/server/services/users-permissions.js +4 -3
- package/dist/server/services/users-permissions.js.map +1 -1
- package/dist/server/services/users-permissions.mjs +4 -3
- package/dist/server/services/users-permissions.mjs.map +1 -1
- package/package.json +8 -7
- package/server/bootstrap/index.js +31 -0
- package/server/config.js +22 -0
- package/server/controllers/auth.js +232 -8
- package/server/controllers/content-manager-user.js +3 -4
- package/server/controllers/validation/user.js +12 -1
- package/server/routes/content-api/auth.js +119 -71
- package/server/routes/content-api/index.js +11 -4
- package/server/routes/content-api/permissions.js +14 -7
- package/server/routes/content-api/role.js +57 -27
- package/server/routes/content-api/user.js +108 -51
- package/server/routes/content-api/validation.js +250 -0
- package/server/services/constants.js +9 -0
- package/server/services/jwt.js +50 -2
- package/server/services/user.js +11 -0
- package/server/services/users-permissions.js +4 -2
package/server/config.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const {
|
|
4
|
+
DEFAULT_ACCESS_TOKEN_LIFESPAN,
|
|
5
|
+
DEFAULT_MAX_REFRESH_TOKEN_LIFESPAN,
|
|
6
|
+
DEFAULT_IDLE_REFRESH_TOKEN_LIFESPAN,
|
|
7
|
+
DEFAULT_MAX_SESSION_LIFESPAN,
|
|
8
|
+
DEFAULT_IDLE_SESSION_LIFESPAN,
|
|
9
|
+
} = require('./services/constants');
|
|
10
|
+
|
|
3
11
|
module.exports = {
|
|
4
12
|
default: ({ env }) => ({
|
|
5
13
|
jwtSecret: env('JWT_SECRET'),
|
|
6
14
|
jwt: {
|
|
7
15
|
expiresIn: '30d',
|
|
8
16
|
},
|
|
17
|
+
/**
|
|
18
|
+
* JWT management mode for the Content API authentication
|
|
19
|
+
* - "legacy-support": use plugin JWTs (backward compatible)
|
|
20
|
+
* - "refresh": use SessionManager (access/refresh tokens)
|
|
21
|
+
*/
|
|
22
|
+
jwtManagement: 'legacy-support',
|
|
23
|
+
sessions: {
|
|
24
|
+
accessTokenLifespan: DEFAULT_ACCESS_TOKEN_LIFESPAN,
|
|
25
|
+
maxRefreshTokenLifespan: DEFAULT_MAX_REFRESH_TOKEN_LIFESPAN,
|
|
26
|
+
idleRefreshTokenLifespan: DEFAULT_IDLE_REFRESH_TOKEN_LIFESPAN,
|
|
27
|
+
maxSessionLifespan: DEFAULT_MAX_SESSION_LIFESPAN,
|
|
28
|
+
idleSessionLifespan: DEFAULT_IDLE_SESSION_LIFESPAN,
|
|
29
|
+
httpOnly: false,
|
|
30
|
+
},
|
|
9
31
|
ratelimit: {
|
|
10
32
|
interval: 60000,
|
|
11
33
|
max: 10,
|
|
@@ -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,45 @@ 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 cookieOptions = {
|
|
115
|
+
httpOnly: true,
|
|
116
|
+
secure: Boolean(upSessions.cookie?.secure),
|
|
117
|
+
sameSite: upSessions.cookie?.sameSite ?? 'lax',
|
|
118
|
+
path: upSessions.cookie?.path ?? '/',
|
|
119
|
+
domain: upSessions.cookie?.domain,
|
|
120
|
+
overwrite: true,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
ctx.cookies.set(cookieName, refresh.token, cookieOptions);
|
|
124
|
+
return ctx.send({ jwt: access.token, user: await sanitizeUser(user, ctx) });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return ctx.send({
|
|
128
|
+
jwt: access.token,
|
|
129
|
+
refreshToken: refresh.token,
|
|
130
|
+
user: await sanitizeUser(user, ctx),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
89
134
|
return ctx.send({
|
|
90
135
|
jwt: getService('jwt').issue({ id: user.id }),
|
|
91
136
|
user: await sanitizeUser(user, ctx),
|
|
@@ -100,6 +145,43 @@ module.exports = ({ strapi }) => ({
|
|
|
100
145
|
throw new ForbiddenError('Your account has been blocked by an administrator');
|
|
101
146
|
}
|
|
102
147
|
|
|
148
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
149
|
+
if (mode === 'refresh') {
|
|
150
|
+
const deviceId = extractDeviceId(ctx.request.body);
|
|
151
|
+
|
|
152
|
+
const refresh = await strapi
|
|
153
|
+
.sessionManager('users-permissions')
|
|
154
|
+
.generateRefreshToken(String(user.id), deviceId, { type: 'refresh' });
|
|
155
|
+
|
|
156
|
+
const access = await strapi
|
|
157
|
+
.sessionManager('users-permissions')
|
|
158
|
+
.generateAccessToken(refresh.token);
|
|
159
|
+
if ('error' in access) {
|
|
160
|
+
throw new ApplicationError('Invalid credentials');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const upSessions = strapi.config.get('plugin::users-permissions.sessions');
|
|
164
|
+
const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
|
|
165
|
+
if (upSessions?.httpOnly || requestHttpOnly) {
|
|
166
|
+
const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
|
|
167
|
+
const cookieOptions = {
|
|
168
|
+
httpOnly: true,
|
|
169
|
+
secure: Boolean(upSessions.cookie?.secure),
|
|
170
|
+
sameSite: upSessions.cookie?.sameSite ?? 'lax',
|
|
171
|
+
path: upSessions.cookie?.path ?? '/',
|
|
172
|
+
domain: upSessions.cookie?.domain,
|
|
173
|
+
overwrite: true,
|
|
174
|
+
};
|
|
175
|
+
ctx.cookies.set(cookieName, refresh.token, cookieOptions);
|
|
176
|
+
return ctx.send({ jwt: access.token, user: await sanitizeUser(user, ctx) });
|
|
177
|
+
}
|
|
178
|
+
return ctx.send({
|
|
179
|
+
jwt: access.token,
|
|
180
|
+
refreshToken: refresh.token,
|
|
181
|
+
user: await sanitizeUser(user, ctx),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
103
185
|
return ctx.send({
|
|
104
186
|
jwt: getService('jwt').issue({ id: user.id }),
|
|
105
187
|
user: await sanitizeUser(user, ctx),
|
|
@@ -137,7 +219,37 @@ module.exports = ({ strapi }) => ({
|
|
|
137
219
|
|
|
138
220
|
await getService('user').edit(user.id, { password });
|
|
139
221
|
|
|
140
|
-
|
|
222
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
223
|
+
if (mode === 'refresh') {
|
|
224
|
+
const deviceId = extractDeviceId(ctx.request.body);
|
|
225
|
+
|
|
226
|
+
if (deviceId) {
|
|
227
|
+
// Invalidate sessions: specific device if deviceId provided
|
|
228
|
+
await strapi
|
|
229
|
+
.sessionManager('users-permissions')
|
|
230
|
+
.invalidateRefreshToken(String(user.id), deviceId);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const newDeviceId = deviceId || crypto.randomUUID();
|
|
234
|
+
const refresh = await strapi
|
|
235
|
+
.sessionManager('users-permissions')
|
|
236
|
+
.generateRefreshToken(String(user.id), newDeviceId, { type: 'refresh' });
|
|
237
|
+
|
|
238
|
+
const access = await strapi
|
|
239
|
+
.sessionManager('users-permissions')
|
|
240
|
+
.generateAccessToken(refresh.token);
|
|
241
|
+
if ('error' in access) {
|
|
242
|
+
throw new ApplicationError('Invalid credentials');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return ctx.send({
|
|
246
|
+
jwt: access.token,
|
|
247
|
+
refreshToken: refresh.token,
|
|
248
|
+
user: await sanitizeUser(user, ctx),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return ctx.send({
|
|
141
253
|
jwt: getService('jwt').issue({ id: user.id }),
|
|
142
254
|
user: await sanitizeUser(user, ctx),
|
|
143
255
|
});
|
|
@@ -168,13 +280,111 @@ module.exports = ({ strapi }) => ({
|
|
|
168
280
|
password,
|
|
169
281
|
});
|
|
170
282
|
|
|
171
|
-
|
|
172
|
-
|
|
283
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
284
|
+
if (mode === 'refresh') {
|
|
285
|
+
const deviceId = extractDeviceId(ctx.request.body);
|
|
286
|
+
|
|
287
|
+
if (deviceId) {
|
|
288
|
+
// Invalidate sessions: specific device if deviceId provided
|
|
289
|
+
await strapi
|
|
290
|
+
.sessionManager('users-permissions')
|
|
291
|
+
.invalidateRefreshToken(String(user.id), deviceId);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const newDeviceId = deviceId || crypto.randomUUID();
|
|
295
|
+
const refresh = await strapi
|
|
296
|
+
.sessionManager('users-permissions')
|
|
297
|
+
.generateRefreshToken(String(user.id), newDeviceId, { type: 'refresh' });
|
|
298
|
+
|
|
299
|
+
const access = await strapi
|
|
300
|
+
.sessionManager('users-permissions')
|
|
301
|
+
.generateAccessToken(refresh.token);
|
|
302
|
+
if ('error' in access) {
|
|
303
|
+
throw new ApplicationError('Invalid credentials');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return ctx.send({
|
|
307
|
+
jwt: access.token,
|
|
308
|
+
refreshToken: refresh.token,
|
|
309
|
+
user: await sanitizeUser(user, ctx),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return ctx.send({
|
|
173
314
|
jwt: getService('jwt').issue({ id: user.id }),
|
|
174
315
|
user: await sanitizeUser(user, ctx),
|
|
175
316
|
});
|
|
176
317
|
},
|
|
318
|
+
async refresh(ctx) {
|
|
319
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
320
|
+
if (mode !== 'refresh') {
|
|
321
|
+
return ctx.notFound();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const { refreshToken } = ctx.request.body || {};
|
|
325
|
+
if (!refreshToken || typeof refreshToken !== 'string') {
|
|
326
|
+
return ctx.badRequest('Missing refresh token');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const rotation = await strapi
|
|
330
|
+
.sessionManager('users-permissions')
|
|
331
|
+
.rotateRefreshToken(refreshToken);
|
|
332
|
+
if ('error' in rotation) {
|
|
333
|
+
return ctx.unauthorized('Invalid refresh token');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const result = await strapi
|
|
337
|
+
.sessionManager('users-permissions')
|
|
338
|
+
.generateAccessToken(rotation.token);
|
|
339
|
+
if ('error' in result) {
|
|
340
|
+
return ctx.unauthorized('Invalid refresh token');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const upSessions = strapi.config.get('plugin::users-permissions.sessions');
|
|
344
|
+
const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
|
|
345
|
+
if (upSessions?.httpOnly || requestHttpOnly) {
|
|
346
|
+
const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
|
|
347
|
+
const cookieOptions = {
|
|
348
|
+
httpOnly: true,
|
|
349
|
+
secure: Boolean(upSessions.cookie?.secure),
|
|
350
|
+
sameSite: upSessions.cookie?.sameSite ?? 'lax',
|
|
351
|
+
path: upSessions.cookie?.path ?? '/',
|
|
352
|
+
domain: upSessions.cookie?.domain,
|
|
353
|
+
overwrite: true,
|
|
354
|
+
};
|
|
355
|
+
ctx.cookies.set(cookieName, rotation.token, cookieOptions);
|
|
356
|
+
return ctx.send({ jwt: result.token });
|
|
357
|
+
}
|
|
358
|
+
return ctx.send({ jwt: result.token, refreshToken: rotation.token });
|
|
359
|
+
},
|
|
360
|
+
async logout(ctx) {
|
|
361
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
362
|
+
if (mode !== 'refresh') {
|
|
363
|
+
return ctx.notFound();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Invalidate all sessions for the authenticated user, or by deviceId if provided
|
|
367
|
+
if (!ctx.state.user) {
|
|
368
|
+
return ctx.unauthorized('Missing authentication');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const deviceId = extractDeviceId(ctx.request.body);
|
|
372
|
+
try {
|
|
373
|
+
await strapi
|
|
374
|
+
.sessionManager('users-permissions')
|
|
375
|
+
.invalidateRefreshToken(String(ctx.state.user.id), deviceId);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
strapi.log.error('UP logout failed', err);
|
|
378
|
+
}
|
|
177
379
|
|
|
380
|
+
const upSessions = strapi.config.get('plugin::users-permissions.sessions');
|
|
381
|
+
const requestHttpOnly = ctx.request.header['x-strapi-refresh-cookie'] === 'httpOnly';
|
|
382
|
+
if (upSessions?.httpOnly || requestHttpOnly) {
|
|
383
|
+
const cookieName = upSessions.cookie?.name || 'strapi_up_refresh';
|
|
384
|
+
ctx.cookies.set(cookieName, '', { expires: new Date(0) });
|
|
385
|
+
}
|
|
386
|
+
return ctx.send({ ok: true });
|
|
387
|
+
},
|
|
178
388
|
async connect(ctx, next) {
|
|
179
389
|
const grant = require('grant').koa();
|
|
180
390
|
|
|
@@ -387,12 +597,26 @@ module.exports = ({ strapi }) => ({
|
|
|
387
597
|
return ctx.send({ user: sanitizedUser });
|
|
388
598
|
}
|
|
389
599
|
|
|
390
|
-
const
|
|
600
|
+
const mode = strapi.config.get('plugin::users-permissions.jwtManagement', 'legacy-support');
|
|
601
|
+
if (mode === 'refresh') {
|
|
602
|
+
const deviceId = extractDeviceId(ctx.request.body) || crypto.randomUUID();
|
|
391
603
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
604
|
+
const refresh = await strapi
|
|
605
|
+
.sessionManager('users-permissions')
|
|
606
|
+
.generateRefreshToken(String(user.id), deviceId, { type: 'refresh' });
|
|
607
|
+
|
|
608
|
+
const access = await strapi
|
|
609
|
+
.sessionManager('users-permissions')
|
|
610
|
+
.generateAccessToken(refresh.token);
|
|
611
|
+
if ('error' in access) {
|
|
612
|
+
throw new ApplicationError('Invalid credentials');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return ctx.send({ jwt: access.token, refreshToken: refresh.token, user: sanitizedUser });
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const jwt = getService('jwt').issue(_.pick(user, ['id']));
|
|
619
|
+
return ctx.send({ jwt, user: sanitizedUser });
|
|
396
620
|
},
|
|
397
621
|
|
|
398
622
|
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,
|
|
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') &&
|
|
137
|
-
|
|
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
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
config: {
|
|
70
|
-
prefix: '',
|
|
117
|
+
{
|
|
118
|
+
method: 'POST',
|
|
119
|
+
path: '/auth/refresh',
|
|
120
|
+
handler: 'auth.refresh',
|
|
121
|
+
config: { prefix: '' },
|
|
71
122
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
};
|