@strapi/plugin-users-permissions 4.1.1 → 4.2.0-alpha.O
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/components/BoundRoute/index.js +2 -2
- package/admin/src/components/FormModal/Input/index.js +1 -1
- package/admin/src/components/FormModal/index.js +1 -1
- package/admin/src/components/Permissions/index.js +2 -2
- package/admin/src/components/Policies/index.js +2 -2
- package/admin/src/components/UsersPermissions/index.js +2 -2
- package/admin/src/pages/AdvancedSettings/index.js +1 -1
- package/admin/src/pages/AdvancedSettings/utils/schema.js +1 -1
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +17 -12
- package/admin/src/pages/Roles/CreatePage/index.js +2 -2
- package/admin/src/pages/Roles/EditPage/index.js +2 -2
- package/admin/src/translations/en.json +1 -1
- package/package.json +4 -4
- package/server/bootstrap/grant-config.js +123 -0
- package/server/bootstrap/index.js +2 -121
- package/server/middlewares/rateLimit.js +2 -1
- package/server/services/providers-list.js +473 -0
- package/server/services/providers.js +2 -467
|
@@ -6,17 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
// Public node modules.
|
|
8
8
|
const _ = require('lodash');
|
|
9
|
-
const jwt = require('jsonwebtoken');
|
|
10
9
|
const urlJoin = require('url-join');
|
|
11
10
|
|
|
12
11
|
const { getAbsoluteServerUrl } = require('@strapi/utils');
|
|
13
12
|
|
|
14
13
|
module.exports = ({ strapi }) => {
|
|
15
14
|
// lazy load heavy dependencies
|
|
16
|
-
const
|
|
17
|
-
// Purest strategies.
|
|
18
|
-
const purest = require('purest')({ request });
|
|
19
|
-
const purestConfig = require('@purest/providers');
|
|
15
|
+
const providerRequest = require('./providers-list');
|
|
20
16
|
|
|
21
17
|
/**
|
|
22
18
|
* Helper to get profiles
|
|
@@ -32,468 +28,7 @@ module.exports = ({ strapi }) => {
|
|
|
32
28
|
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
33
29
|
.get();
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
case 'discord': {
|
|
37
|
-
const discord = purest({
|
|
38
|
-
provider: 'discord',
|
|
39
|
-
config: {
|
|
40
|
-
discord: {
|
|
41
|
-
'https://discordapp.com/api/': {
|
|
42
|
-
__domain: {
|
|
43
|
-
auth: {
|
|
44
|
-
auth: { bearer: '[0]' },
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
'{endpoint}': {
|
|
48
|
-
__path: {
|
|
49
|
-
alias: '__default',
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
discord
|
|
57
|
-
.query()
|
|
58
|
-
.get('users/@me')
|
|
59
|
-
.auth(access_token)
|
|
60
|
-
.request((err, res, body) => {
|
|
61
|
-
if (err) {
|
|
62
|
-
callback(err);
|
|
63
|
-
} else {
|
|
64
|
-
// Combine username and discriminator because discord username is not unique
|
|
65
|
-
var username = `${body.username}#${body.discriminator}`;
|
|
66
|
-
callback(null, {
|
|
67
|
-
username,
|
|
68
|
-
email: body.email,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
case 'cognito': {
|
|
75
|
-
// get the id_token
|
|
76
|
-
const idToken = query.id_token;
|
|
77
|
-
// decode the jwt token
|
|
78
|
-
const tokenPayload = jwt.decode(idToken);
|
|
79
|
-
if (!tokenPayload) {
|
|
80
|
-
callback(new Error('unable to decode jwt token'));
|
|
81
|
-
} else {
|
|
82
|
-
callback(null, {
|
|
83
|
-
username: tokenPayload['cognito:username'],
|
|
84
|
-
email: tokenPayload.email,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
case 'facebook': {
|
|
90
|
-
const facebook = purest({
|
|
91
|
-
provider: 'facebook',
|
|
92
|
-
config: purestConfig,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
facebook
|
|
96
|
-
.query()
|
|
97
|
-
.get('me?fields=name,email')
|
|
98
|
-
.auth(access_token)
|
|
99
|
-
.request((err, res, body) => {
|
|
100
|
-
if (err) {
|
|
101
|
-
callback(err);
|
|
102
|
-
} else {
|
|
103
|
-
callback(null, {
|
|
104
|
-
username: body.name,
|
|
105
|
-
email: body.email,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
case 'google': {
|
|
112
|
-
const google = purest({ provider: 'google', config: purestConfig });
|
|
113
|
-
|
|
114
|
-
google
|
|
115
|
-
.query('oauth')
|
|
116
|
-
.get('tokeninfo')
|
|
117
|
-
.qs({ access_token })
|
|
118
|
-
.request((err, res, body) => {
|
|
119
|
-
if (err) {
|
|
120
|
-
callback(err);
|
|
121
|
-
} else {
|
|
122
|
-
callback(null, {
|
|
123
|
-
username: body.email.split('@')[0],
|
|
124
|
-
email: body.email,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
case 'github': {
|
|
131
|
-
const github = purest({
|
|
132
|
-
provider: 'github',
|
|
133
|
-
config: purestConfig,
|
|
134
|
-
defaults: {
|
|
135
|
-
headers: {
|
|
136
|
-
'user-agent': 'strapi',
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
github
|
|
142
|
-
.query()
|
|
143
|
-
.get('user')
|
|
144
|
-
.auth(access_token)
|
|
145
|
-
.request((err, res, userbody) => {
|
|
146
|
-
if (err) {
|
|
147
|
-
return callback(err);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// This is the public email on the github profile
|
|
151
|
-
if (userbody.email) {
|
|
152
|
-
return callback(null, {
|
|
153
|
-
username: userbody.login,
|
|
154
|
-
email: userbody.email,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Get the email with Github's user/emails API
|
|
159
|
-
github
|
|
160
|
-
.query()
|
|
161
|
-
.get('user/emails')
|
|
162
|
-
.auth(access_token)
|
|
163
|
-
.request((err, res, emailsbody) => {
|
|
164
|
-
if (err) {
|
|
165
|
-
return callback(err);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return callback(null, {
|
|
169
|
-
username: userbody.login,
|
|
170
|
-
email: Array.isArray(emailsbody)
|
|
171
|
-
? emailsbody.find(email => email.primary === true).email
|
|
172
|
-
: null,
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
case 'microsoft': {
|
|
179
|
-
const microsoft = purest({
|
|
180
|
-
provider: 'microsoft',
|
|
181
|
-
config: purestConfig,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
microsoft
|
|
185
|
-
.query()
|
|
186
|
-
.get('me')
|
|
187
|
-
.auth(access_token)
|
|
188
|
-
.request((err, res, body) => {
|
|
189
|
-
if (err) {
|
|
190
|
-
callback(err);
|
|
191
|
-
} else {
|
|
192
|
-
callback(null, {
|
|
193
|
-
username: body.userPrincipalName,
|
|
194
|
-
email: body.userPrincipalName,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
case 'twitter': {
|
|
201
|
-
const twitter = purest({
|
|
202
|
-
provider: 'twitter',
|
|
203
|
-
config: purestConfig,
|
|
204
|
-
key: providers.twitter.key,
|
|
205
|
-
secret: providers.twitter.secret,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
twitter
|
|
209
|
-
.query()
|
|
210
|
-
.get('account/verify_credentials')
|
|
211
|
-
.auth(access_token, query.access_secret)
|
|
212
|
-
.qs({ screen_name: query['raw[screen_name]'], include_email: 'true' })
|
|
213
|
-
.request((err, res, body) => {
|
|
214
|
-
if (err) {
|
|
215
|
-
callback(err);
|
|
216
|
-
} else {
|
|
217
|
-
callback(null, {
|
|
218
|
-
username: body.screen_name,
|
|
219
|
-
email: body.email,
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
case 'instagram': {
|
|
226
|
-
const instagram = purest({
|
|
227
|
-
provider: 'instagram',
|
|
228
|
-
key: providers.instagram.key,
|
|
229
|
-
secret: providers.instagram.secret,
|
|
230
|
-
config: purestConfig,
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
instagram
|
|
234
|
-
.query()
|
|
235
|
-
.get('me')
|
|
236
|
-
.qs({ access_token, fields: 'id,username' })
|
|
237
|
-
.request((err, res, body) => {
|
|
238
|
-
if (err) {
|
|
239
|
-
callback(err);
|
|
240
|
-
} else {
|
|
241
|
-
callback(null, {
|
|
242
|
-
username: body.username,
|
|
243
|
-
email: `${body.username}@strapi.io`, // dummy email as Instagram does not provide user email
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
case 'vk': {
|
|
250
|
-
const vk = purest({
|
|
251
|
-
provider: 'vk',
|
|
252
|
-
config: purestConfig,
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
vk.query()
|
|
256
|
-
.get('users.get')
|
|
257
|
-
.qs({ access_token, id: query.raw.user_id, v: '5.122' })
|
|
258
|
-
.request((err, res, body) => {
|
|
259
|
-
if (err) {
|
|
260
|
-
callback(err);
|
|
261
|
-
} else {
|
|
262
|
-
callback(null, {
|
|
263
|
-
username: `${body.response[0].last_name} ${body.response[0].first_name}`,
|
|
264
|
-
email: query.raw.email,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
case 'twitch': {
|
|
271
|
-
const twitch = purest({
|
|
272
|
-
provider: 'twitch',
|
|
273
|
-
config: {
|
|
274
|
-
twitch: {
|
|
275
|
-
'https://api.twitch.tv': {
|
|
276
|
-
__domain: {
|
|
277
|
-
auth: {
|
|
278
|
-
headers: {
|
|
279
|
-
Authorization: 'Bearer [0]',
|
|
280
|
-
'Client-ID': '[1]',
|
|
281
|
-
},
|
|
282
|
-
},
|
|
283
|
-
},
|
|
284
|
-
'helix/{endpoint}': {
|
|
285
|
-
__path: {
|
|
286
|
-
alias: '__default',
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
'oauth2/{endpoint}': {
|
|
290
|
-
__path: {
|
|
291
|
-
alias: 'oauth',
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
},
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
twitch
|
|
300
|
-
.get('users')
|
|
301
|
-
.auth(access_token, providers.twitch.key)
|
|
302
|
-
.request((err, res, body) => {
|
|
303
|
-
if (err) {
|
|
304
|
-
callback(err);
|
|
305
|
-
} else {
|
|
306
|
-
callback(null, {
|
|
307
|
-
username: body.data[0].login,
|
|
308
|
-
email: body.data[0].email,
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
314
|
-
case 'linkedin': {
|
|
315
|
-
const linkedIn = purest({
|
|
316
|
-
provider: 'linkedin',
|
|
317
|
-
config: {
|
|
318
|
-
linkedin: {
|
|
319
|
-
'https://api.linkedin.com': {
|
|
320
|
-
__domain: {
|
|
321
|
-
auth: [{ auth: { bearer: '[0]' } }],
|
|
322
|
-
},
|
|
323
|
-
'[version]/{endpoint}': {
|
|
324
|
-
__path: {
|
|
325
|
-
alias: '__default',
|
|
326
|
-
version: 'v2',
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
},
|
|
330
|
-
},
|
|
331
|
-
},
|
|
332
|
-
});
|
|
333
|
-
try {
|
|
334
|
-
const getDetailsRequest = () => {
|
|
335
|
-
return new Promise((resolve, reject) => {
|
|
336
|
-
linkedIn
|
|
337
|
-
.query()
|
|
338
|
-
.get('me')
|
|
339
|
-
.auth(access_token)
|
|
340
|
-
.request((err, res, body) => {
|
|
341
|
-
if (err) {
|
|
342
|
-
return reject(err);
|
|
343
|
-
}
|
|
344
|
-
resolve(body);
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
const getEmailRequest = () => {
|
|
350
|
-
return new Promise((resolve, reject) => {
|
|
351
|
-
linkedIn
|
|
352
|
-
.query()
|
|
353
|
-
.get('emailAddress?q=members&projection=(elements*(handle~))')
|
|
354
|
-
.auth(access_token)
|
|
355
|
-
.request((err, res, body) => {
|
|
356
|
-
if (err) {
|
|
357
|
-
return reject(err);
|
|
358
|
-
}
|
|
359
|
-
resolve(body);
|
|
360
|
-
});
|
|
361
|
-
});
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
const { localizedFirstName } = await getDetailsRequest();
|
|
365
|
-
const { elements } = await getEmailRequest();
|
|
366
|
-
const email = elements[0]['handle~'];
|
|
367
|
-
|
|
368
|
-
callback(null, {
|
|
369
|
-
username: localizedFirstName,
|
|
370
|
-
email: email.emailAddress,
|
|
371
|
-
});
|
|
372
|
-
} catch (err) {
|
|
373
|
-
callback(err);
|
|
374
|
-
}
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
case 'reddit': {
|
|
378
|
-
const reddit = purest({
|
|
379
|
-
provider: 'reddit',
|
|
380
|
-
config: purestConfig,
|
|
381
|
-
defaults: {
|
|
382
|
-
headers: {
|
|
383
|
-
'user-agent': 'strapi',
|
|
384
|
-
},
|
|
385
|
-
},
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
reddit
|
|
389
|
-
.query('auth')
|
|
390
|
-
.get('me')
|
|
391
|
-
.auth(access_token)
|
|
392
|
-
.request((err, res, body) => {
|
|
393
|
-
if (err) {
|
|
394
|
-
callback(err);
|
|
395
|
-
} else {
|
|
396
|
-
callback(null, {
|
|
397
|
-
username: body.name,
|
|
398
|
-
email: `${body.name}@strapi.io`, // dummy email as Reddit does not provide user email
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
case 'auth0': {
|
|
405
|
-
const purestAuth0Conf = {};
|
|
406
|
-
purestAuth0Conf[`https://${providers.auth0.subdomain}.auth0.com`] = {
|
|
407
|
-
__domain: {
|
|
408
|
-
auth: {
|
|
409
|
-
auth: { bearer: '[0]' },
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
'{endpoint}': {
|
|
413
|
-
__path: {
|
|
414
|
-
alias: '__default',
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
};
|
|
418
|
-
const auth0 = purest({
|
|
419
|
-
provider: 'auth0',
|
|
420
|
-
config: {
|
|
421
|
-
auth0: purestAuth0Conf,
|
|
422
|
-
},
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
auth0
|
|
426
|
-
.get('userinfo')
|
|
427
|
-
.auth(access_token)
|
|
428
|
-
.request((err, res, body) => {
|
|
429
|
-
if (err) {
|
|
430
|
-
callback(err);
|
|
431
|
-
} else {
|
|
432
|
-
const username =
|
|
433
|
-
body.username || body.nickname || body.name || body.email.split('@')[0];
|
|
434
|
-
const email = body.email || `${username.replace(/\s+/g, '.')}@strapi.io`;
|
|
435
|
-
|
|
436
|
-
callback(null, {
|
|
437
|
-
username,
|
|
438
|
-
email,
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
case 'cas': {
|
|
445
|
-
const provider_url = 'https://' + _.get(providers.cas, 'subdomain');
|
|
446
|
-
const cas = purest({
|
|
447
|
-
provider: 'cas',
|
|
448
|
-
config: {
|
|
449
|
-
cas: {
|
|
450
|
-
[provider_url]: {
|
|
451
|
-
__domain: {
|
|
452
|
-
auth: {
|
|
453
|
-
auth: { bearer: '[0]' },
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
'{endpoint}': {
|
|
457
|
-
__path: {
|
|
458
|
-
alias: '__default',
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
},
|
|
462
|
-
},
|
|
463
|
-
},
|
|
464
|
-
});
|
|
465
|
-
cas
|
|
466
|
-
.query()
|
|
467
|
-
.get('oidc/profile')
|
|
468
|
-
.auth(access_token)
|
|
469
|
-
.request((err, res, body) => {
|
|
470
|
-
if (err) {
|
|
471
|
-
callback(err);
|
|
472
|
-
} else {
|
|
473
|
-
// CAS attribute may be in body.attributes or "FLAT", depending on CAS config
|
|
474
|
-
const username = body.attributes
|
|
475
|
-
? body.attributes.strapiusername || body.id || body.sub
|
|
476
|
-
: body.strapiusername || body.id || body.sub;
|
|
477
|
-
const email = body.attributes
|
|
478
|
-
? body.attributes.strapiemail || body.attributes.email
|
|
479
|
-
: body.strapiemail || body.email;
|
|
480
|
-
if (!username || !email) {
|
|
481
|
-
strapi.log.warn(
|
|
482
|
-
'CAS Response Body did not contain required attributes: ' + JSON.stringify(body)
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
callback(null, {
|
|
486
|
-
username,
|
|
487
|
-
email,
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
493
|
-
default:
|
|
494
|
-
callback(new Error('Unknown provider.'));
|
|
495
|
-
break;
|
|
496
|
-
}
|
|
31
|
+
await providerRequest({ provider, query, callback, access_token, providers });
|
|
497
32
|
};
|
|
498
33
|
|
|
499
34
|
/**
|