@strapi/plugin-users-permissions 4.1.3 → 4.2.0-alpha.0

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