@akemona-org/strapi-plugin-users-permissions 3.7.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.
Files changed (143) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/assets/images/logo.svg +1 -0
  4. package/admin/src/components/BaselineAlignement/index.js +33 -0
  5. package/admin/src/components/Bloc/index.js +10 -0
  6. package/admin/src/components/BoundRoute/Components.js +78 -0
  7. package/admin/src/components/BoundRoute/index.js +56 -0
  8. package/admin/src/components/ContainerFluid/index.js +13 -0
  9. package/admin/src/components/FormBloc/index.js +61 -0
  10. package/admin/src/components/IntlInput/index.js +38 -0
  11. package/admin/src/components/ListBaselineAlignment/index.js +8 -0
  12. package/admin/src/components/ListRow/Components.js +74 -0
  13. package/admin/src/components/ListRow/index.js +35 -0
  14. package/admin/src/components/ModalForm/Wrapper.js +12 -0
  15. package/admin/src/components/ModalForm/index.js +59 -0
  16. package/admin/src/components/Permissions/ListWrapper.js +9 -0
  17. package/admin/src/components/Permissions/PermissionRow/BaselineAlignment.js +7 -0
  18. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +37 -0
  19. package/admin/src/components/Permissions/PermissionRow/RowStyle.js +28 -0
  20. package/admin/src/components/Permissions/PermissionRow/SubCategory/ConditionsButtonWrapper.js +13 -0
  21. package/admin/src/components/Permissions/PermissionRow/SubCategory/PolicyWrapper.js +8 -0
  22. package/admin/src/components/Permissions/PermissionRow/SubCategory/SubCategoryWrapper.js +26 -0
  23. package/admin/src/components/Permissions/PermissionRow/SubCategory/index.js +116 -0
  24. package/admin/src/components/Permissions/PermissionRow/index.js +92 -0
  25. package/admin/src/components/Permissions/index.js +44 -0
  26. package/admin/src/components/Permissions/init.js +14 -0
  27. package/admin/src/components/Permissions/reducer.js +27 -0
  28. package/admin/src/components/Policies/Components.js +26 -0
  29. package/admin/src/components/Policies/index.js +61 -0
  30. package/admin/src/components/PrefixedIcon/index.js +27 -0
  31. package/admin/src/components/Roles/EmptyRole/BaselineAlignment.js +7 -0
  32. package/admin/src/components/Roles/EmptyRole/index.js +27 -0
  33. package/admin/src/components/Roles/RoleListWrapper/index.js +17 -0
  34. package/admin/src/components/Roles/RoleRow/RoleDescription.js +9 -0
  35. package/admin/src/components/Roles/RoleRow/index.js +45 -0
  36. package/admin/src/components/Roles/index.js +3 -0
  37. package/admin/src/components/SizedInput/index.js +24 -0
  38. package/admin/src/components/UsersPermissions/index.js +91 -0
  39. package/admin/src/components/UsersPermissions/init.js +11 -0
  40. package/admin/src/components/UsersPermissions/reducer.js +60 -0
  41. package/admin/src/containers/AdvancedSettings/index.js +218 -0
  42. package/admin/src/containers/AdvancedSettings/reducer.js +65 -0
  43. package/admin/src/containers/AdvancedSettings/utils/form.js +52 -0
  44. package/admin/src/containers/EmailTemplates/CustomTextInput.js +105 -0
  45. package/admin/src/containers/EmailTemplates/Wrapper.js +36 -0
  46. package/admin/src/containers/EmailTemplates/index.js +222 -0
  47. package/admin/src/containers/EmailTemplates/reducer.js +58 -0
  48. package/admin/src/containers/EmailTemplates/utils/forms.js +81 -0
  49. package/admin/src/containers/EmailTemplates/utils/schema.js +25 -0
  50. package/admin/src/containers/Providers/index.js +283 -0
  51. package/admin/src/containers/Providers/reducer.js +54 -0
  52. package/admin/src/containers/Providers/utils/createProvidersArray.js +21 -0
  53. package/admin/src/containers/Providers/utils/forms.js +205 -0
  54. package/admin/src/containers/Roles/CreatePage/index.js +167 -0
  55. package/admin/src/containers/Roles/CreatePage/utils/schema.js +9 -0
  56. package/admin/src/containers/Roles/EditPage/index.js +161 -0
  57. package/admin/src/containers/Roles/EditPage/utils/schema.js +9 -0
  58. package/admin/src/containers/Roles/ListPage/BaselineAlignment.js +8 -0
  59. package/admin/src/containers/Roles/ListPage/index.js +188 -0
  60. package/admin/src/containers/Roles/ProtectedCreatePage/index.js +12 -0
  61. package/admin/src/containers/Roles/ProtectedEditPage/index.js +12 -0
  62. package/admin/src/containers/Roles/ProtectedListPage/index.js +15 -0
  63. package/admin/src/containers/Roles/index.js +35 -0
  64. package/admin/src/contexts/EditPage/index.js +26 -0
  65. package/admin/src/contexts/HomePage/index.js +27 -0
  66. package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
  67. package/admin/src/hooks/index.js +5 -0
  68. package/admin/src/hooks/useFetchRole/index.js +55 -0
  69. package/admin/src/hooks/useFetchRole/reducer.js +31 -0
  70. package/admin/src/hooks/useForm/index.js +96 -0
  71. package/admin/src/hooks/useForm/reducer.js +59 -0
  72. package/admin/src/hooks/usePlugins/index.js +73 -0
  73. package/admin/src/hooks/usePlugins/init.js +5 -0
  74. package/admin/src/hooks/usePlugins/reducer.js +37 -0
  75. package/admin/src/hooks/useRolesList/index.js +62 -0
  76. package/admin/src/hooks/useRolesList/init.js +5 -0
  77. package/admin/src/hooks/useRolesList/reducer.js +31 -0
  78. package/admin/src/index.js +109 -0
  79. package/admin/src/permissions.js +33 -0
  80. package/admin/src/pluginId.js +5 -0
  81. package/admin/src/translations/ar.json +49 -0
  82. package/admin/src/translations/cs.json +55 -0
  83. package/admin/src/translations/de.json +68 -0
  84. package/admin/src/translations/dk.json +116 -0
  85. package/admin/src/translations/en.json +104 -0
  86. package/admin/src/translations/es.json +70 -0
  87. package/admin/src/translations/fr.json +55 -0
  88. package/admin/src/translations/id.json +69 -0
  89. package/admin/src/translations/index.js +55 -0
  90. package/admin/src/translations/it.json +68 -0
  91. package/admin/src/translations/ja.json +53 -0
  92. package/admin/src/translations/ko.json +55 -0
  93. package/admin/src/translations/ms.json +54 -0
  94. package/admin/src/translations/nl.json +53 -0
  95. package/admin/src/translations/pl.json +55 -0
  96. package/admin/src/translations/pt-BR.json +49 -0
  97. package/admin/src/translations/pt.json +53 -0
  98. package/admin/src/translations/ru.json +68 -0
  99. package/admin/src/translations/sk.json +57 -0
  100. package/admin/src/translations/sv.json +68 -0
  101. package/admin/src/translations/th.json +66 -0
  102. package/admin/src/translations/tr.json +53 -0
  103. package/admin/src/translations/uk.json +54 -0
  104. package/admin/src/translations/vi.json +55 -0
  105. package/admin/src/translations/zh-Hans.json +104 -0
  106. package/admin/src/translations/zh.json +53 -0
  107. package/admin/src/utils/cleanPermissions.js +25 -0
  108. package/admin/src/utils/formatPolicies.js +8 -0
  109. package/admin/src/utils/getRequestURL.js +5 -0
  110. package/admin/src/utils/getTrad.js +5 -0
  111. package/admin/src/utils/index.js +4 -0
  112. package/config/functions/bootstrap.js +234 -0
  113. package/config/layout.js +10 -0
  114. package/config/policies/isAuthenticated.js +9 -0
  115. package/config/policies/permissions.js +93 -0
  116. package/config/policies/rateLimit.js +33 -0
  117. package/config/request.json +6 -0
  118. package/config/routes.json +397 -0
  119. package/config/schema.graphql.js +280 -0
  120. package/config/security.json +5 -0
  121. package/config/users-permissions-actions.js +80 -0
  122. package/controllers/Auth.js +612 -0
  123. package/controllers/User.js +125 -0
  124. package/controllers/UsersPermissions.js +291 -0
  125. package/controllers/user/admin.js +224 -0
  126. package/controllers/user/api.js +173 -0
  127. package/controllers/validation/email-template.js +40 -0
  128. package/documentation/1.0.0/overrides/users-permissions-Role.json +281 -0
  129. package/documentation/1.0.0/overrides/users-permissions-User.json +325 -0
  130. package/middlewares/users-permissions/defaults.json +5 -0
  131. package/middlewares/users-permissions/index.js +40 -0
  132. package/models/Permission.js +7 -0
  133. package/models/Permission.settings.json +43 -0
  134. package/models/Role.js +7 -0
  135. package/models/Role.settings.json +42 -0
  136. package/models/User.config.js +15 -0
  137. package/models/User.js +7 -0
  138. package/models/User.settings.json +62 -0
  139. package/package.json +70 -0
  140. package/services/Jwt.js +65 -0
  141. package/services/Providers.js +596 -0
  142. package/services/User.js +167 -0
  143. package/services/UsersPermissions.js +416 -0
@@ -0,0 +1,596 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies.
5
+ */
6
+
7
+ // Public node modules.
8
+ const _ = require('lodash');
9
+ const request = require('request');
10
+
11
+ // Purest strategies.
12
+ const purest = require('purest')({ request });
13
+ const purestConfig = require('@purest/providers');
14
+ const { getAbsoluteServerUrl } = require('@akemona-org/strapi-utils');
15
+ const jwt = require('jsonwebtoken');
16
+
17
+ /**
18
+ * Connect thanks to a third-party provider.
19
+ *
20
+ *
21
+ * @param {String} provider
22
+ * @param {String} access_token
23
+ *
24
+ * @return {*}
25
+ */
26
+
27
+ const connect = (provider, query) => {
28
+ const access_token = query.access_token || query.code || query.oauth_token;
29
+
30
+ return new Promise((resolve, reject) => {
31
+ if (!access_token) {
32
+ return reject([null, { message: 'No access_token.' }]);
33
+ }
34
+
35
+ // Get the profile.
36
+ getProfile(provider, query, async (err, profile) => {
37
+ if (err) {
38
+ return reject([null, err]);
39
+ }
40
+
41
+ // We need at least the mail.
42
+ if (!profile.email) {
43
+ return reject([null, { message: 'Email was not available.' }]);
44
+ }
45
+
46
+ try {
47
+ const users = await strapi.query('user', 'users-permissions').find({
48
+ email: profile.email,
49
+ });
50
+
51
+ const advanced = await strapi
52
+ .store({
53
+ environment: '',
54
+ type: 'plugin',
55
+ name: 'users-permissions',
56
+ key: 'advanced',
57
+ })
58
+ .get();
59
+
60
+ const user = _.find(users, { provider });
61
+
62
+ if (_.isEmpty(user) && !advanced.allow_register) {
63
+ return resolve([
64
+ null,
65
+ [{ messages: [{ id: 'Auth.advanced.allow_register' }] }],
66
+ 'Register action is actually not available.',
67
+ ]);
68
+ }
69
+
70
+ if (!_.isEmpty(user)) {
71
+ return resolve([user, null]);
72
+ }
73
+
74
+ if (
75
+ !_.isEmpty(_.find(users, (user) => user.provider !== provider)) &&
76
+ advanced.unique_email
77
+ ) {
78
+ return resolve([
79
+ null,
80
+ [{ messages: [{ id: 'Auth.form.error.email.taken' }] }],
81
+ 'Email is already taken.',
82
+ ]);
83
+ }
84
+
85
+ // Retrieve default role.
86
+ const defaultRole = await strapi
87
+ .query('role', 'users-permissions')
88
+ .findOne({ type: advanced.default_role }, []);
89
+
90
+ // Create the new user.
91
+ const params = _.assign(profile, {
92
+ provider: provider,
93
+ role: defaultRole.id,
94
+ confirmed: true,
95
+ });
96
+
97
+ const createdUser = await strapi.query('user', 'users-permissions').create(params);
98
+
99
+ return resolve([createdUser, null]);
100
+ } catch (err) {
101
+ reject([null, err]);
102
+ }
103
+ });
104
+ });
105
+ };
106
+
107
+ /**
108
+ * Helper to get profiles
109
+ *
110
+ * @param {String} provider
111
+ * @param {Function} callback
112
+ */
113
+
114
+ const getProfile = async (provider, query, callback) => {
115
+ const access_token = query.access_token || query.code || query.oauth_token;
116
+
117
+ const grant = await strapi
118
+ .store({
119
+ environment: '',
120
+ type: 'plugin',
121
+ name: 'users-permissions',
122
+ key: 'grant',
123
+ })
124
+ .get();
125
+
126
+ switch (provider) {
127
+ case 'discord': {
128
+ const discord = purest({
129
+ provider: 'discord',
130
+ config: {
131
+ discord: {
132
+ 'https://discordapp.com/api/': {
133
+ __domain: {
134
+ auth: {
135
+ auth: { bearer: '[0]' },
136
+ },
137
+ },
138
+ '{endpoint}': {
139
+ __path: {
140
+ alias: '__default',
141
+ },
142
+ },
143
+ },
144
+ },
145
+ },
146
+ });
147
+ discord
148
+ .query()
149
+ .get('users/@me')
150
+ .auth(access_token)
151
+ .request((err, res, body) => {
152
+ if (err) {
153
+ callback(err);
154
+ } else {
155
+ // Combine username and discriminator because discord username is not unique
156
+ var username = `${body.username}#${body.discriminator}`;
157
+ callback(null, {
158
+ username: username,
159
+ email: body.email,
160
+ });
161
+ }
162
+ });
163
+ break;
164
+ }
165
+ case 'cognito': {
166
+ // get the id_token
167
+ const idToken = query.id_token;
168
+ // decode the jwt token
169
+ const tokenPayload = jwt.decode(idToken);
170
+ if (!tokenPayload) {
171
+ callback(new Error('unable to decode jwt token'));
172
+ } else {
173
+ callback(null, {
174
+ username: tokenPayload['cognito:username'],
175
+ email: tokenPayload.email,
176
+ });
177
+ }
178
+ break;
179
+ }
180
+ case 'facebook': {
181
+ const facebook = purest({
182
+ provider: 'facebook',
183
+ config: purestConfig,
184
+ });
185
+
186
+ facebook
187
+ .query()
188
+ .get('me?fields=name,email')
189
+ .auth(access_token)
190
+ .request((err, res, body) => {
191
+ if (err) {
192
+ callback(err);
193
+ } else {
194
+ callback(null, {
195
+ username: body.name,
196
+ email: body.email,
197
+ });
198
+ }
199
+ });
200
+ break;
201
+ }
202
+ case 'google': {
203
+ const google = purest({ provider: 'google', config: purestConfig });
204
+
205
+ google
206
+ .query('oauth')
207
+ .get('tokeninfo')
208
+ .qs({ access_token })
209
+ .request((err, res, body) => {
210
+ if (err) {
211
+ callback(err);
212
+ } else {
213
+ callback(null, {
214
+ username: body.email.split('@')[0],
215
+ email: body.email,
216
+ });
217
+ }
218
+ });
219
+ break;
220
+ }
221
+ case 'github': {
222
+ const github = purest({
223
+ provider: 'github',
224
+ config: purestConfig,
225
+ defaults: {
226
+ headers: {
227
+ 'user-agent': 'strapi',
228
+ },
229
+ },
230
+ });
231
+
232
+ github
233
+ .query()
234
+ .get('user')
235
+ .auth(access_token)
236
+ .request((err, res, userbody) => {
237
+ if (err) {
238
+ return callback(err);
239
+ }
240
+
241
+ // This is the public email on the github profile
242
+ if (userbody.email) {
243
+ return callback(null, {
244
+ username: userbody.login,
245
+ email: userbody.email,
246
+ });
247
+ }
248
+
249
+ // Get the email with Github's user/emails API
250
+ github
251
+ .query()
252
+ .get('user/emails')
253
+ .auth(access_token)
254
+ .request((err, res, emailsbody) => {
255
+ if (err) {
256
+ return callback(err);
257
+ }
258
+
259
+ return callback(null, {
260
+ username: userbody.login,
261
+ email: Array.isArray(emailsbody)
262
+ ? emailsbody.find((email) => email.primary === true).email
263
+ : null,
264
+ });
265
+ });
266
+ });
267
+ break;
268
+ }
269
+ case 'microsoft': {
270
+ const microsoft = purest({
271
+ provider: 'microsoft',
272
+ config: purestConfig,
273
+ });
274
+
275
+ microsoft
276
+ .query()
277
+ .get('me')
278
+ .auth(access_token)
279
+ .request((err, res, body) => {
280
+ if (err) {
281
+ callback(err);
282
+ } else {
283
+ callback(null, {
284
+ username: body.userPrincipalName,
285
+ email: body.userPrincipalName,
286
+ });
287
+ }
288
+ });
289
+ break;
290
+ }
291
+ case 'twitter': {
292
+ const twitter = purest({
293
+ provider: 'twitter',
294
+ config: purestConfig,
295
+ key: grant.twitter.key,
296
+ secret: grant.twitter.secret,
297
+ });
298
+
299
+ twitter
300
+ .query()
301
+ .get('account/verify_credentials')
302
+ .auth(access_token, query.access_secret)
303
+ .qs({ screen_name: query['raw[screen_name]'], include_email: 'true' })
304
+ .request((err, res, body) => {
305
+ if (err) {
306
+ callback(err);
307
+ } else {
308
+ callback(null, {
309
+ username: body.screen_name,
310
+ email: body.email,
311
+ });
312
+ }
313
+ });
314
+ break;
315
+ }
316
+ case 'instagram': {
317
+ const instagram = purest({
318
+ provider: 'instagram',
319
+ key: grant.instagram.key,
320
+ secret: grant.instagram.secret,
321
+ config: purestConfig,
322
+ });
323
+
324
+ instagram
325
+ .query()
326
+ .get('me')
327
+ .qs({ access_token, fields: 'id,username' })
328
+ .request((err, res, body) => {
329
+ if (err) {
330
+ callback(err);
331
+ } else {
332
+ callback(null, {
333
+ username: body.username,
334
+ email: `${body.username}@strapi.io`, // dummy email as Instagram does not provide user email
335
+ });
336
+ }
337
+ });
338
+ break;
339
+ }
340
+ case 'vk': {
341
+ const vk = purest({
342
+ provider: 'vk',
343
+ config: purestConfig,
344
+ });
345
+
346
+ vk.query()
347
+ .get('users.get')
348
+ .qs({ access_token, id: query.raw.user_id, v: '5.122' })
349
+ .request((err, res, body) => {
350
+ if (err) {
351
+ callback(err);
352
+ } else {
353
+ callback(null, {
354
+ username: `${body.response[0].last_name} ${body.response[0].first_name}`,
355
+ email: query.raw.email,
356
+ });
357
+ }
358
+ });
359
+ break;
360
+ }
361
+ case 'twitch': {
362
+ const twitch = purest({
363
+ provider: 'twitch',
364
+ config: {
365
+ twitch: {
366
+ 'https://api.twitch.tv': {
367
+ __domain: {
368
+ auth: {
369
+ headers: {
370
+ Authorization: 'Bearer [0]',
371
+ 'Client-ID': '[1]',
372
+ },
373
+ },
374
+ },
375
+ 'helix/{endpoint}': {
376
+ __path: {
377
+ alias: '__default',
378
+ },
379
+ },
380
+ 'oauth2/{endpoint}': {
381
+ __path: {
382
+ alias: 'oauth',
383
+ },
384
+ },
385
+ },
386
+ },
387
+ },
388
+ });
389
+
390
+ twitch
391
+ .get('users')
392
+ .auth(access_token, grant.twitch.key)
393
+ .request((err, res, body) => {
394
+ if (err) {
395
+ callback(err);
396
+ } else {
397
+ callback(null, {
398
+ username: body.data[0].login,
399
+ email: body.data[0].email,
400
+ });
401
+ }
402
+ });
403
+ break;
404
+ }
405
+ case 'linkedin': {
406
+ const linkedIn = purest({
407
+ provider: 'linkedin',
408
+ config: {
409
+ linkedin: {
410
+ 'https://api.linkedin.com': {
411
+ __domain: {
412
+ auth: [{ auth: { bearer: '[0]' } }],
413
+ },
414
+ '[version]/{endpoint}': {
415
+ __path: {
416
+ alias: '__default',
417
+ version: 'v2',
418
+ },
419
+ },
420
+ },
421
+ },
422
+ },
423
+ });
424
+ try {
425
+ const getDetailsRequest = () => {
426
+ return new Promise((resolve, reject) => {
427
+ linkedIn
428
+ .query()
429
+ .get('me')
430
+ .auth(access_token)
431
+ .request((err, res, body) => {
432
+ if (err) {
433
+ return reject(err);
434
+ }
435
+ resolve(body);
436
+ });
437
+ });
438
+ };
439
+
440
+ const getEmailRequest = () => {
441
+ return new Promise((resolve, reject) => {
442
+ linkedIn
443
+ .query()
444
+ .get('emailAddress?q=members&projection=(elements*(handle~))')
445
+ .auth(access_token)
446
+ .request((err, res, body) => {
447
+ if (err) {
448
+ return reject(err);
449
+ }
450
+ resolve(body);
451
+ });
452
+ });
453
+ };
454
+
455
+ const { localizedFirstName } = await getDetailsRequest();
456
+ const { elements } = await getEmailRequest();
457
+ const email = elements[0]['handle~'];
458
+
459
+ callback(null, {
460
+ username: localizedFirstName,
461
+ email: email.emailAddress,
462
+ });
463
+ } catch (err) {
464
+ callback(err);
465
+ }
466
+ break;
467
+ }
468
+ case 'reddit': {
469
+ const reddit = purest({
470
+ provider: 'reddit',
471
+ config: purestConfig,
472
+ defaults: {
473
+ headers: {
474
+ 'user-agent': 'strapi',
475
+ },
476
+ },
477
+ });
478
+
479
+ reddit
480
+ .query('auth')
481
+ .get('me')
482
+ .auth(access_token)
483
+ .request((err, res, body) => {
484
+ if (err) {
485
+ callback(err);
486
+ } else {
487
+ callback(null, {
488
+ username: body.name,
489
+ email: `${body.name}@strapi.io`, // dummy email as Reddit does not provide user email
490
+ });
491
+ }
492
+ });
493
+ break;
494
+ }
495
+ case 'auth0': {
496
+ const purestAuth0Conf = {};
497
+ purestAuth0Conf[`https://${grant.auth0.subdomain}.auth0.com`] = {
498
+ __domain: {
499
+ auth: {
500
+ auth: { bearer: '[0]' },
501
+ },
502
+ },
503
+ '{endpoint}': {
504
+ __path: {
505
+ alias: '__default',
506
+ },
507
+ },
508
+ };
509
+ const auth0 = purest({
510
+ provider: 'auth0',
511
+ config: {
512
+ auth0: purestAuth0Conf,
513
+ },
514
+ });
515
+
516
+ auth0
517
+ .get('userinfo')
518
+ .auth(access_token)
519
+ .request((err, res, body) => {
520
+ if (err) {
521
+ callback(err);
522
+ } else {
523
+ const username =
524
+ body.username || body.nickname || body.name || body.email.split('@')[0];
525
+ const email = body.email || `${username.replace(/\s+/g, '.')}@strapi.io`;
526
+
527
+ callback(null, {
528
+ username,
529
+ email,
530
+ });
531
+ }
532
+ });
533
+ break;
534
+ }
535
+ case 'cas': {
536
+ const provider_url = 'https://' + _.get(grant['cas'], 'subdomain');
537
+ const cas = purest({
538
+ provider: 'cas',
539
+ config: {
540
+ cas: {
541
+ [provider_url]: {
542
+ __domain: {
543
+ auth: {
544
+ auth: { bearer: '[0]' },
545
+ },
546
+ },
547
+ '{endpoint}': {
548
+ __path: {
549
+ alias: '__default',
550
+ },
551
+ },
552
+ },
553
+ },
554
+ },
555
+ });
556
+ cas
557
+ .query()
558
+ .get('oidc/profile')
559
+ .auth(access_token)
560
+ .request((err, res, body) => {
561
+ if (err) {
562
+ callback(err);
563
+ } else {
564
+ // CAS attribute may be in body.attributes or "FLAT", depending on CAS config
565
+ const username = body.attributes
566
+ ? body.attributes.strapiusername || body.id || body.sub
567
+ : body.strapiusername || body.id || body.sub;
568
+ const email = body.attributes
569
+ ? body.attributes.strapiemail || body.attributes.email
570
+ : body.strapiemail || body.email;
571
+ if (!username || !email) {
572
+ strapi.log.warn(
573
+ 'CAS Response Body did not contain required attributes: ' + JSON.stringify(body)
574
+ );
575
+ }
576
+ callback(null, {
577
+ username,
578
+ email,
579
+ });
580
+ }
581
+ });
582
+ break;
583
+ }
584
+ default:
585
+ callback(new Error('Unknown provider.'));
586
+ break;
587
+ }
588
+ };
589
+
590
+ const buildRedirectUri = (provider = '') =>
591
+ `${getAbsoluteServerUrl(strapi.config)}/connect/${provider}/callback`;
592
+
593
+ module.exports = {
594
+ connect,
595
+ buildRedirectUri,
596
+ };