@strapi/plugin-users-permissions 5.52.3 → 5.53.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.
- package/dist/server/controllers/auth.js +7 -1
- package/dist/server/controllers/auth.js.map +1 -1
- package/dist/server/controllers/auth.mjs +7 -1
- package/dist/server/controllers/auth.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/change-password.js +6 -3
- package/dist/server/graphql/mutations/auth/change-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/change-password.mjs +6 -3
- package/dist/server/graphql/mutations/auth/change-password.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/forgot-password.js +6 -3
- package/dist/server/graphql/mutations/auth/forgot-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/forgot-password.mjs +6 -3
- package/dist/server/graphql/mutations/auth/forgot-password.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/login.js +9 -6
- package/dist/server/graphql/mutations/auth/login.js.map +1 -1
- package/dist/server/graphql/mutations/auth/login.mjs +9 -6
- package/dist/server/graphql/mutations/auth/login.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/rate-limit.js +63 -0
- package/dist/server/graphql/mutations/auth/rate-limit.js.map +1 -0
- package/dist/server/graphql/mutations/auth/rate-limit.mjs +61 -0
- package/dist/server/graphql/mutations/auth/rate-limit.mjs.map +1 -0
- package/dist/server/graphql/mutations/auth/register.js +6 -3
- package/dist/server/graphql/mutations/auth/register.js.map +1 -1
- package/dist/server/graphql/mutations/auth/register.mjs +6 -3
- package/dist/server/graphql/mutations/auth/register.mjs.map +1 -1
- package/dist/server/graphql/mutations/auth/reset-password.js +6 -3
- package/dist/server/graphql/mutations/auth/reset-password.js.map +1 -1
- package/dist/server/graphql/mutations/auth/reset-password.mjs +6 -3
- package/dist/server/graphql/mutations/auth/reset-password.mjs.map +1 -1
- package/dist/server/services/providers-registry.js +80 -19
- package/dist/server/services/providers-registry.js.map +1 -1
- package/dist/server/services/providers-registry.mjs +80 -19
- package/dist/server/services/providers-registry.mjs.map +1 -1
- package/dist/server/services/providers.js +12 -8
- package/dist/server/services/providers.js.map +1 -1
- package/dist/server/services/providers.mjs +12 -8
- package/dist/server/services/providers.mjs.map +1 -1
- package/dist/server/services/user.js +7 -7
- package/dist/server/services/user.js.map +1 -1
- package/dist/server/services/user.mjs +7 -7
- package/dist/server/services/user.mjs.map +1 -1
- package/dist/server/utils/oauth-connect/index.js +11 -6
- package/dist/server/utils/oauth-connect/index.js.map +1 -1
- package/dist/server/utils/oauth-connect/index.mjs +11 -6
- package/dist/server/utils/oauth-connect/index.mjs.map +1 -1
- package/dist/server/utils/trim-grant-session-response.js +67 -0
- package/dist/server/utils/trim-grant-session-response.js.map +1 -0
- package/dist/server/utils/trim-grant-session-response.mjs +65 -0
- package/dist/server/utils/trim-grant-session-response.mjs.map +1 -0
- package/package.json +4 -4
- package/server/src/controllers/auth.js +9 -1
- package/server/src/graphql/mutations/auth/change-password.js +5 -5
- package/server/src/graphql/mutations/auth/forgot-password.js +5 -5
- package/server/src/graphql/mutations/auth/login.js +10 -6
- package/server/src/graphql/mutations/auth/rate-limit.js +62 -0
- package/server/src/graphql/mutations/auth/register.js +5 -5
- package/server/src/graphql/mutations/auth/reset-password.js +5 -5
- package/server/src/services/providers-registry.js +99 -23
- package/server/src/services/providers.js +9 -7
- package/server/src/services/user.js +15 -5
- package/server/src/utils/oauth-connect/index.js +12 -6
- package/server/src/utils/trim-grant-session-response.js +70 -0
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
const { toPlainObject } = require('lodash/fp');
|
|
4
4
|
|
|
5
5
|
const { checkBadRequest } = require('../../utils');
|
|
6
|
+
const { createRateLimitRunner } = require('./rate-limit');
|
|
6
7
|
|
|
7
8
|
module.exports = ({ nexus, strapi }) => {
|
|
8
9
|
const { nonNull } = nexus;
|
|
10
|
+
const runRateLimit = createRateLimitRunner(strapi, '/auth/reset-password');
|
|
9
11
|
|
|
10
12
|
return {
|
|
11
13
|
type: 'UsersPermissionsLoginPayload',
|
|
@@ -21,11 +23,9 @@ module.exports = ({ nexus, strapi }) => {
|
|
|
21
23
|
async resolve(parent, args, context) {
|
|
22
24
|
const { koaContext } = context;
|
|
23
25
|
|
|
24
|
-
koaContext
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const output = koaContext.body;
|
|
26
|
+
const output = await runRateLimit(koaContext, { body: toPlainObject(args) }, (ctx) =>
|
|
27
|
+
strapi.plugin('users-permissions').controller('auth').resetPassword(ctx)
|
|
28
|
+
);
|
|
29
29
|
|
|
30
30
|
checkBadRequest(output);
|
|
31
31
|
|
|
@@ -23,6 +23,9 @@ const initProviders = ({ baseURL }) => ({
|
|
|
23
23
|
},
|
|
24
24
|
async authCallback({ accessToken }) {
|
|
25
25
|
const { body } = await bearerGet('https://discord.com/api/users/@me', accessToken);
|
|
26
|
+
if (body.verified !== true) {
|
|
27
|
+
throw new Error('Email not verified by Discord');
|
|
28
|
+
}
|
|
26
29
|
const username =
|
|
27
30
|
body.discriminator && body.discriminator !== '0'
|
|
28
31
|
? `${body.username}#${body.discriminator}`
|
|
@@ -46,6 +49,9 @@ const initProviders = ({ baseURL }) => ({
|
|
|
46
49
|
const { body } = await bearerGet('https://graph.facebook.com/me', accessToken, {
|
|
47
50
|
qs: { fields: 'name,email' },
|
|
48
51
|
});
|
|
52
|
+
if (!body.email) {
|
|
53
|
+
throw new Error('Email not verified by Facebook');
|
|
54
|
+
}
|
|
49
55
|
return {
|
|
50
56
|
username: body.name,
|
|
51
57
|
email: body.email,
|
|
@@ -65,6 +71,10 @@ const initProviders = ({ baseURL }) => ({
|
|
|
65
71
|
const { body } = await fetchJson(
|
|
66
72
|
`https://oauth2.googleapis.com/tokeninfo?access_token=${encodeURIComponent(accessToken)}`
|
|
67
73
|
);
|
|
74
|
+
const verified = body.verified_email ?? body.email_verified;
|
|
75
|
+
if (verified !== true && verified !== 'true') {
|
|
76
|
+
throw new Error('Email not verified by Google');
|
|
77
|
+
}
|
|
68
78
|
return {
|
|
69
79
|
username: body.email.split('@')[0],
|
|
70
80
|
email: body.email,
|
|
@@ -85,13 +95,6 @@ const initProviders = ({ baseURL }) => ({
|
|
|
85
95
|
headers: { 'user-agent': 'strapi' },
|
|
86
96
|
});
|
|
87
97
|
|
|
88
|
-
if (userBody.email) {
|
|
89
|
-
return {
|
|
90
|
-
username: userBody.login,
|
|
91
|
-
email: userBody.email,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
98
|
const { body: emailBody } = await bearerGet(
|
|
96
99
|
'https://api.github.com/user/emails',
|
|
97
100
|
accessToken,
|
|
@@ -100,11 +103,32 @@ const initProviders = ({ baseURL }) => ({
|
|
|
100
103
|
}
|
|
101
104
|
);
|
|
102
105
|
|
|
106
|
+
if (userBody.email) {
|
|
107
|
+
const verifiedPublicEmail = Array.isArray(emailBody)
|
|
108
|
+
? emailBody.find((entry) => entry.email === userBody.email && entry.verified === true)
|
|
109
|
+
: null;
|
|
110
|
+
|
|
111
|
+
if (!verifiedPublicEmail) {
|
|
112
|
+
throw new Error('Email not verified by GitHub');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
username: userBody.login,
|
|
117
|
+
email: userBody.email,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const primaryEmail = Array.isArray(emailBody)
|
|
122
|
+
? emailBody.find((email) => email.primary === true)
|
|
123
|
+
: null;
|
|
124
|
+
|
|
125
|
+
if (!primaryEmail || primaryEmail.verified !== true) {
|
|
126
|
+
throw new Error('Email not verified by GitHub');
|
|
127
|
+
}
|
|
128
|
+
|
|
103
129
|
return {
|
|
104
130
|
username: userBody.login,
|
|
105
|
-
email:
|
|
106
|
-
? emailBody.find((email) => email.primary === true).email
|
|
107
|
-
: null,
|
|
131
|
+
email: primaryEmail.email,
|
|
108
132
|
};
|
|
109
133
|
},
|
|
110
134
|
},
|
|
@@ -134,17 +158,28 @@ const initProviders = ({ baseURL }) => ({
|
|
|
134
158
|
secret: '',
|
|
135
159
|
callbackUrl: `${baseURL}/twitter/callback`,
|
|
136
160
|
},
|
|
137
|
-
async authCallback({ accessToken,
|
|
161
|
+
async authCallback({ accessToken, providers, grantResponse }) {
|
|
162
|
+
const accessSecret = grantResponse?.access_secret;
|
|
163
|
+
const screenName = grantResponse?.raw?.screen_name;
|
|
164
|
+
|
|
165
|
+
if (!accessSecret) {
|
|
166
|
+
throw new Error('Twitter authentication requires a completed OAuth session');
|
|
167
|
+
}
|
|
168
|
+
|
|
138
169
|
const { twitterGet } = require('../utils/oauth-connect/oauth1');
|
|
139
170
|
const { body } = await twitterGet({
|
|
140
171
|
url: 'https://api.twitter.com/1.1/account/verify_credentials.json',
|
|
141
172
|
accessToken,
|
|
142
|
-
accessCredential:
|
|
173
|
+
accessCredential: accessSecret,
|
|
143
174
|
consumerKey: providers.twitter.key,
|
|
144
175
|
clientCredential: providers.twitter.secret,
|
|
145
|
-
qs: { include_email: 'true', screen_name:
|
|
176
|
+
qs: { include_email: 'true', screen_name: screenName },
|
|
146
177
|
});
|
|
147
178
|
|
|
179
|
+
if (!body.email) {
|
|
180
|
+
throw new Error('Email not verified by Twitter');
|
|
181
|
+
}
|
|
182
|
+
|
|
148
183
|
return {
|
|
149
184
|
username: body.screen_name,
|
|
150
185
|
email: body.email,
|
|
@@ -179,13 +214,25 @@ const initProviders = ({ baseURL }) => ({
|
|
|
179
214
|
callbackUrl: `${baseURL}/vk/callback`,
|
|
180
215
|
scope: ['email'],
|
|
181
216
|
},
|
|
182
|
-
async authCallback({ accessToken,
|
|
217
|
+
async authCallback({ accessToken, grantResponse }) {
|
|
218
|
+
const email = grantResponse?.raw?.email;
|
|
219
|
+
const userId = grantResponse?.raw?.user_id;
|
|
220
|
+
|
|
221
|
+
if (!email || !userId) {
|
|
222
|
+
throw new Error('VK authentication requires a completed OAuth session');
|
|
223
|
+
}
|
|
224
|
+
|
|
183
225
|
const { body } = await bearerGet('https://api.vk.com/method/users.get', accessToken, {
|
|
184
|
-
qs: { user_ids:
|
|
226
|
+
qs: { user_ids: userId, v: '5.122' },
|
|
185
227
|
});
|
|
228
|
+
|
|
229
|
+
if (!body.response?.[0]) {
|
|
230
|
+
throw new Error('Invalid VK access token');
|
|
231
|
+
}
|
|
232
|
+
|
|
186
233
|
return {
|
|
187
234
|
username: `${body.response[0].last_name} ${body.response[0].first_name}`,
|
|
188
|
-
email
|
|
235
|
+
email,
|
|
189
236
|
};
|
|
190
237
|
},
|
|
191
238
|
},
|
|
@@ -205,9 +252,13 @@ const initProviders = ({ baseURL }) => ({
|
|
|
205
252
|
'Client-Id': providers.twitch.key,
|
|
206
253
|
},
|
|
207
254
|
});
|
|
255
|
+
const email = body.data?.[0]?.email;
|
|
256
|
+
if (!email) {
|
|
257
|
+
throw new Error('Email not verified by Twitch');
|
|
258
|
+
}
|
|
208
259
|
return {
|
|
209
260
|
username: body.data[0].login,
|
|
210
|
-
email
|
|
261
|
+
email,
|
|
211
262
|
};
|
|
212
263
|
},
|
|
213
264
|
},
|
|
@@ -228,7 +279,11 @@ const initProviders = ({ baseURL }) => ({
|
|
|
228
279
|
accessToken
|
|
229
280
|
);
|
|
230
281
|
|
|
231
|
-
const email = emailBody.elements[0]['handle~'];
|
|
282
|
+
const email = emailBody.elements[0]?.['handle~'];
|
|
283
|
+
|
|
284
|
+
if (!email?.emailAddress) {
|
|
285
|
+
throw new Error('Email not verified by LinkedIn');
|
|
286
|
+
}
|
|
232
287
|
|
|
233
288
|
return {
|
|
234
289
|
username: profileBody.localizedFirstName,
|
|
@@ -247,10 +302,18 @@ const initProviders = ({ baseURL }) => ({
|
|
|
247
302
|
callback: `${baseURL}/cognito/callback`,
|
|
248
303
|
scope: ['email', 'openid', 'profile'],
|
|
249
304
|
},
|
|
250
|
-
async authCallback({
|
|
305
|
+
async authCallback({ providers, grantResponse }) {
|
|
251
306
|
const jwksUrl = new URL(providers.cognito.jwksurl);
|
|
252
|
-
const idToken =
|
|
307
|
+
const idToken = grantResponse?.id_token;
|
|
308
|
+
|
|
309
|
+
if (!idToken) {
|
|
310
|
+
throw new Error('Cognito authentication requires a completed OAuth session');
|
|
311
|
+
}
|
|
312
|
+
|
|
253
313
|
const tokenPayload = await verifyJwtWithJwks({ idToken, jwksUrl });
|
|
314
|
+
if (tokenPayload.email_verified !== true) {
|
|
315
|
+
throw new Error('Email not verified by Cognito');
|
|
316
|
+
}
|
|
254
317
|
return {
|
|
255
318
|
username: tokenPayload['cognito:username'],
|
|
256
319
|
email: tokenPayload.email,
|
|
@@ -293,6 +356,9 @@ const initProviders = ({ baseURL }) => ({
|
|
|
293
356
|
`https://${providers.auth0.subdomain}.auth0.com/userinfo`,
|
|
294
357
|
accessToken
|
|
295
358
|
);
|
|
359
|
+
if (body.email && body.email_verified !== true) {
|
|
360
|
+
throw new Error('Email not verified by Auth0');
|
|
361
|
+
}
|
|
296
362
|
const username = body.username || body.nickname || body.name || body.email.split('@')[0];
|
|
297
363
|
const email = body.email || `${username.replace(/\s+/g, '.')}@strapi.io`;
|
|
298
364
|
|
|
@@ -324,11 +390,15 @@ const initProviders = ({ baseURL }) => ({
|
|
|
324
390
|
const email = body.attributes
|
|
325
391
|
? body.attributes.strapiemail || body.attributes.email
|
|
326
392
|
: body.strapiemail || body.email;
|
|
393
|
+
const emailVerified = body.email_verified ?? body.attributes?.email_verified;
|
|
327
394
|
if (!username || !email) {
|
|
328
395
|
strapi.log.warn(
|
|
329
396
|
`CAS Response Body did not contain required attributes: ${JSON.stringify(body)}`
|
|
330
397
|
);
|
|
331
398
|
}
|
|
399
|
+
if (email && emailVerified !== true) {
|
|
400
|
+
throw new Error('Email not verified by CAS');
|
|
401
|
+
}
|
|
332
402
|
return {
|
|
333
403
|
username,
|
|
334
404
|
email,
|
|
@@ -347,10 +417,13 @@ const initProviders = ({ baseURL }) => ({
|
|
|
347
417
|
},
|
|
348
418
|
async authCallback({ accessToken }) {
|
|
349
419
|
const { body } = await bearerGet(
|
|
350
|
-
'https://www.patreon.com/api/oauth2/v2/identity?fields[user]=full_name,email',
|
|
420
|
+
'https://www.patreon.com/api/oauth2/v2/identity?fields[user]=full_name,email,is_email_verified',
|
|
351
421
|
accessToken
|
|
352
422
|
);
|
|
353
423
|
const patreonData = body.data.attributes;
|
|
424
|
+
if (patreonData.is_email_verified !== true) {
|
|
425
|
+
throw new Error('Email not verified by Patreon');
|
|
426
|
+
}
|
|
354
427
|
return {
|
|
355
428
|
username: patreonData.full_name,
|
|
356
429
|
email: patreonData.email,
|
|
@@ -372,6 +445,9 @@ const initProviders = ({ baseURL }) => ({
|
|
|
372
445
|
`https://${providers.keycloak.subdomain}/protocol/openid-connect/userinfo`,
|
|
373
446
|
accessToken
|
|
374
447
|
);
|
|
448
|
+
if (body.email_verified !== true) {
|
|
449
|
+
throw new Error('Email not verified by Keycloak');
|
|
450
|
+
}
|
|
375
451
|
return {
|
|
376
452
|
username: body.preferred_username,
|
|
377
453
|
email: body.email,
|
|
@@ -400,12 +476,12 @@ module.exports = () => {
|
|
|
400
476
|
delete authProviders[name];
|
|
401
477
|
},
|
|
402
478
|
|
|
403
|
-
async run({ provider, accessToken, query, providers }) {
|
|
479
|
+
async run({ provider, accessToken, query, providers, grantResponse }) {
|
|
404
480
|
const authProvider = authProviders[provider];
|
|
405
481
|
|
|
406
482
|
assert(authProvider, 'Unknown auth provider');
|
|
407
483
|
|
|
408
|
-
return authProvider.authCallback({ accessToken, query, providers });
|
|
484
|
+
return authProvider.authCallback({ accessToken, query, providers, grantResponse });
|
|
409
485
|
},
|
|
410
486
|
};
|
|
411
487
|
};
|
|
@@ -17,8 +17,8 @@ module.exports = ({ strapi }) => {
|
|
|
17
17
|
* @param {String} provider
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
const getProfile = async (provider,
|
|
21
|
-
const accessToken =
|
|
20
|
+
const getProfile = async (provider, oauthData, { grantResponse } = {}) => {
|
|
21
|
+
const accessToken = oauthData.access_token || oauthData.code || oauthData.oauth_token;
|
|
22
22
|
|
|
23
23
|
const providers = await strapi
|
|
24
24
|
.store({ type: 'plugin', name: 'users-permissions', key: 'grant' })
|
|
@@ -26,9 +26,10 @@ module.exports = ({ strapi }) => {
|
|
|
26
26
|
|
|
27
27
|
return getService('providers-registry').run({
|
|
28
28
|
provider,
|
|
29
|
-
query,
|
|
29
|
+
query: oauthData,
|
|
30
30
|
accessToken,
|
|
31
31
|
providers,
|
|
32
|
+
grantResponse,
|
|
32
33
|
});
|
|
33
34
|
};
|
|
34
35
|
|
|
@@ -42,15 +43,16 @@ module.exports = ({ strapi }) => {
|
|
|
42
43
|
* @return {*}
|
|
43
44
|
*/
|
|
44
45
|
|
|
45
|
-
const connect = async (provider,
|
|
46
|
-
const accessToken =
|
|
46
|
+
const connect = async (provider, oauthData, { grantResponse } = {}) => {
|
|
47
|
+
const accessToken = oauthData.access_token || oauthData.code || oauthData.oauth_token;
|
|
48
|
+
const idToken = oauthData.id_token;
|
|
47
49
|
|
|
48
|
-
if (!accessToken) {
|
|
50
|
+
if (!accessToken && !idToken) {
|
|
49
51
|
throw new Error('No access_token.');
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
// Get the profile.
|
|
53
|
-
const profile = await getProfile(provider,
|
|
55
|
+
const profile = await getProfile(provider, oauthData, { grantResponse });
|
|
54
56
|
|
|
55
57
|
const email = _.toLower(profile.email);
|
|
56
58
|
|
|
@@ -10,12 +10,14 @@ const crypto = require('crypto');
|
|
|
10
10
|
const bcrypt = require('bcryptjs');
|
|
11
11
|
const urlJoin = require('url-join');
|
|
12
12
|
|
|
13
|
-
const { sanitize } = require('@strapi/utils');
|
|
14
|
-
const { toNumber, getOr } = require('lodash/fp');
|
|
13
|
+
const { sanitize, ALLOWED_QUERY_PARAM_KEYS } = require('@strapi/utils');
|
|
14
|
+
const { toNumber, getOr, pick } = require('lodash/fp');
|
|
15
15
|
const { getService } = require('../utils');
|
|
16
16
|
|
|
17
17
|
const USER_MODEL_UID = 'plugin::users-permissions.user';
|
|
18
18
|
|
|
19
|
+
const pickAllowedQueryParams = pick(ALLOWED_QUERY_PARAM_KEYS);
|
|
20
|
+
|
|
19
21
|
const getSessionManager = () => {
|
|
20
22
|
const manager = strapi.sessionManager;
|
|
21
23
|
return manager ?? null;
|
|
@@ -29,7 +31,11 @@ module.exports = ({ strapi }) => ({
|
|
|
29
31
|
*/
|
|
30
32
|
|
|
31
33
|
count(params) {
|
|
32
|
-
|
|
34
|
+
const query = strapi
|
|
35
|
+
.get('query-params')
|
|
36
|
+
.transform(USER_MODEL_UID, pickAllowedQueryParams(params ?? {}));
|
|
37
|
+
|
|
38
|
+
return strapi.db.query(USER_MODEL_UID).count(query);
|
|
33
39
|
},
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -101,7 +107,9 @@ module.exports = ({ strapi }) => ({
|
|
|
101
107
|
* @return {Promise}
|
|
102
108
|
*/
|
|
103
109
|
fetch(id, params) {
|
|
104
|
-
const query = strapi
|
|
110
|
+
const query = strapi
|
|
111
|
+
.get('query-params')
|
|
112
|
+
.transform(USER_MODEL_UID, pickAllowedQueryParams(params ?? {}));
|
|
105
113
|
|
|
106
114
|
return strapi.db.query(USER_MODEL_UID).findOne({
|
|
107
115
|
...query,
|
|
@@ -124,7 +132,9 @@ module.exports = ({ strapi }) => ({
|
|
|
124
132
|
* @return {Promise}
|
|
125
133
|
*/
|
|
126
134
|
fetchAll(params) {
|
|
127
|
-
const query = strapi
|
|
135
|
+
const query = strapi
|
|
136
|
+
.get('query-params')
|
|
137
|
+
.transform(USER_MODEL_UID, pickAllowedQueryParams(params ?? {}));
|
|
128
138
|
|
|
129
139
|
return strapi.db.query(USER_MODEL_UID).findMany(query);
|
|
130
140
|
},
|
|
@@ -5,6 +5,7 @@ const { errors } = require('@strapi/utils');
|
|
|
5
5
|
const builtinProviderEndpoints = require('./providers');
|
|
6
6
|
const oauth1 = require('./oauth1');
|
|
7
7
|
const oauth2 = require('./oauth2');
|
|
8
|
+
const { trimGrantSessionResponse } = require('../trim-grant-session-response');
|
|
8
9
|
|
|
9
10
|
const CONNECT_PREFIX = '/connect';
|
|
10
11
|
|
|
@@ -87,6 +88,15 @@ const preserveGrantDynamic = (ctx) => {
|
|
|
87
88
|
return dynamic ? { dynamic } : {};
|
|
88
89
|
};
|
|
89
90
|
|
|
91
|
+
const redirectWithSessionResponse = (ctx, callbackUrl, provider, tokenResponse) => {
|
|
92
|
+
const grantResponse = oauth2.tokensToQueryPayload(provider, tokenResponse);
|
|
93
|
+
ctx.session.grant = {
|
|
94
|
+
response: trimGrantSessionResponse(grantResponse, provider.name),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return redirectWithPayload(ctx, callbackUrl, {});
|
|
98
|
+
};
|
|
99
|
+
|
|
90
100
|
const startOAuth1Flow = async (ctx, provider, parsed, redirectUri) => {
|
|
91
101
|
const requestToken = await oauth1.requestToken({
|
|
92
102
|
requestUrl: provider.request_url,
|
|
@@ -142,9 +152,7 @@ const handleOAuth1Callback = async (ctx, provider, callbackUrl) => {
|
|
|
142
152
|
oauthTokenCredential: requestToken.oauth_token_secret,
|
|
143
153
|
});
|
|
144
154
|
|
|
145
|
-
|
|
146
|
-
ctx.session.grant = {};
|
|
147
|
-
return redirectWithPayload(ctx, callbackUrl, payload);
|
|
155
|
+
return redirectWithSessionResponse(ctx, callbackUrl, provider, tokenResponse);
|
|
148
156
|
};
|
|
149
157
|
|
|
150
158
|
const handleOAuth2Callback = async (ctx, provider, callbackUrl, redirectUri) => {
|
|
@@ -176,9 +184,7 @@ const handleOAuth2Callback = async (ctx, provider, callbackUrl, redirectUri) =>
|
|
|
176
184
|
subdomain: provider.subdomain,
|
|
177
185
|
});
|
|
178
186
|
|
|
179
|
-
|
|
180
|
-
ctx.session.grant = {};
|
|
181
|
-
return redirectWithPayload(ctx, callbackUrl, payload);
|
|
187
|
+
return redirectWithSessionResponse(ctx, callbackUrl, provider, tokenResponse);
|
|
182
188
|
};
|
|
183
189
|
|
|
184
190
|
const createOAuthConnectMiddleware = () => {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const compact = (value) => {
|
|
4
|
+
if (value === null || value === undefined) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return Object.fromEntries(
|
|
13
|
+
Object.entries(value)
|
|
14
|
+
.map(([key, entry]) => [key, compact(entry)])
|
|
15
|
+
.filter(([, entry]) => entry !== undefined)
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compact grant's OAuth token response before it is written to the signed
|
|
21
|
+
* koa-session cookie. The full token exchange payload (especially Cognito's
|
|
22
|
+
* dual JWTs plus a duplicated raw blob) can exceed the browser's ~4 KB
|
|
23
|
+
* per-cookie limit and silently break the auth callback.
|
|
24
|
+
*
|
|
25
|
+
* Keep only fields that auth.callback / providers-registry actually read.
|
|
26
|
+
*/
|
|
27
|
+
const trimGrantSessionResponse = (grantResponse, provider) => {
|
|
28
|
+
if (!grantResponse || typeof grantResponse !== 'object') {
|
|
29
|
+
return grantResponse;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
switch (provider) {
|
|
33
|
+
case 'cognito':
|
|
34
|
+
return compact({
|
|
35
|
+
id_token: grantResponse.id_token,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
case 'twitter':
|
|
39
|
+
return compact({
|
|
40
|
+
access_token: grantResponse.access_token,
|
|
41
|
+
access_secret: grantResponse.access_secret,
|
|
42
|
+
raw: grantResponse.raw?.screen_name
|
|
43
|
+
? { screen_name: grantResponse.raw.screen_name }
|
|
44
|
+
: undefined,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
case 'vk':
|
|
48
|
+
return compact({
|
|
49
|
+
access_token: grantResponse.access_token,
|
|
50
|
+
raw:
|
|
51
|
+
grantResponse.raw?.email != null && grantResponse.raw?.user_id != null
|
|
52
|
+
? {
|
|
53
|
+
email: grantResponse.raw.email,
|
|
54
|
+
user_id: grantResponse.raw.user_id,
|
|
55
|
+
}
|
|
56
|
+
: undefined,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
default:
|
|
60
|
+
return compact({
|
|
61
|
+
access_token: grantResponse.access_token,
|
|
62
|
+
oauth_token: grantResponse.oauth_token,
|
|
63
|
+
id_token: grantResponse.id_token,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
trimGrantSessionResponse,
|
|
70
|
+
};
|