@quiltt/react-native 3.9.6 → 3.9.7
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/CHANGELOG.md +10 -0
- package/dist/index.js +32 -32
- package/package.json +3 -3
- package/src/components/QuilttConnector.tsx +30 -32
- package/src/utils/url.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @quiltt/react-native
|
|
2
2
|
|
|
3
|
+
## 3.9.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#330](https://github.com/quiltt/quiltt-js/pull/330) [`e7b8e74`](https://github.com/quiltt/quiltt-js/commit/e7b8e74613f7725c6f2653be6d8ac0e06cce661d) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Make OAuth Handling Safer
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`e7b8e74`](https://github.com/quiltt/quiltt-js/commit/e7b8e74613f7725c6f2653be6d8ac0e06cce661d)]:
|
|
10
|
+
- @quiltt/core@3.9.7
|
|
11
|
+
- @quiltt/react@3.9.7
|
|
12
|
+
|
|
3
13
|
## 3.9.6
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { URL } from 'react-native-url-polyfill';
|
|
|
9
9
|
import { WebView } from 'react-native-webview';
|
|
10
10
|
import { generateStackTrace, makeBacktrace, getCauses } from '@honeybadger-io/core/build/src/util';
|
|
11
11
|
|
|
12
|
-
var version = "3.9.
|
|
12
|
+
var version = "3.9.7";
|
|
13
13
|
|
|
14
14
|
const ErrorReporterConfig = {
|
|
15
15
|
honeybadger_api_key: 'undefined'
|
|
@@ -103,7 +103,7 @@ const getErrorMessage = (responseStatus, error)=>{
|
|
|
103
103
|
* Checks if a string appears to be already URL encoded
|
|
104
104
|
* @param str The string to check
|
|
105
105
|
* @returns boolean indicating if the string appears to be URL encoded
|
|
106
|
-
*/ const
|
|
106
|
+
*/ const isEncoded = (str)=>{
|
|
107
107
|
// Check for typical URL encoding patterns like %20, %3A, etc.
|
|
108
108
|
const hasEncodedChars = /%[0-9A-F]{2}/i.test(str);
|
|
109
109
|
// Check if double encoding has occurred (e.g., %253A instead of %3A)
|
|
@@ -118,7 +118,7 @@ const getErrorMessage = (responseStatus, error)=>{
|
|
|
118
118
|
*/ const smartEncodeURIComponent = (str)=>{
|
|
119
119
|
if (!str) return str;
|
|
120
120
|
// If it's already encoded, return as is
|
|
121
|
-
if (
|
|
121
|
+
if (isEncoded(str)) {
|
|
122
122
|
console.log('URL already encoded, skipping encoding:', str);
|
|
123
123
|
return str;
|
|
124
124
|
}
|
|
@@ -267,19 +267,18 @@ const checkConnectorUrl = async (connectorUrl, retryCount = 0)=>{
|
|
|
267
267
|
const response = await fetch(connectorUrl);
|
|
268
268
|
if (!response.ok) {
|
|
269
269
|
responseStatus = response.status;
|
|
270
|
-
throw new Error(
|
|
270
|
+
throw new Error('Connector URL is not routable.');
|
|
271
271
|
}
|
|
272
|
-
console.log(`The URL ${connectorUrl} is routable.`);
|
|
273
272
|
return {
|
|
274
273
|
checked: true
|
|
275
274
|
};
|
|
276
275
|
} catch (e) {
|
|
277
276
|
error = e;
|
|
278
|
-
console.error(
|
|
277
|
+
console.error('Failed to connect to connector URL');
|
|
279
278
|
if (retryCount < PREFLIGHT_RETRY_COUNT) {
|
|
280
279
|
const delay = 50 * 2 ** retryCount;
|
|
281
280
|
await new Promise((resolve)=>setTimeout(resolve, delay));
|
|
282
|
-
console.log(`Retrying... Attempt
|
|
281
|
+
console.log(`Retrying connection... Attempt ${retryCount + 1}`);
|
|
283
282
|
return checkConnectorUrl(connectorUrl, retryCount + 1);
|
|
284
283
|
}
|
|
285
284
|
const errorMessage = getErrorMessage(responseStatus, error);
|
|
@@ -301,30 +300,28 @@ const checkConnectorUrl = async (connectorUrl, retryCount = 0)=>{
|
|
|
301
300
|
try {
|
|
302
301
|
// Throw error if oauthUrl is null or undefined
|
|
303
302
|
if (oauthUrl == null) {
|
|
304
|
-
throw new Error('
|
|
303
|
+
throw new Error('OAuth URL missing');
|
|
305
304
|
}
|
|
306
305
|
// Convert to string if it's a URL object
|
|
307
306
|
const urlString = oauthUrl.toString();
|
|
308
307
|
// Throw error if the resulting string is empty
|
|
309
308
|
if (!urlString || urlString.trim() === '') {
|
|
310
|
-
throw new Error('
|
|
309
|
+
throw new Error('Empty OAuth URL');
|
|
311
310
|
}
|
|
312
311
|
// Normalize the URL encoding
|
|
313
312
|
const normalizedUrl = normalizeUrlEncoding(urlString);
|
|
314
|
-
// Log the URL we're about to open
|
|
315
|
-
console.log(`handleOAuthUrl - Opening URL - ${normalizedUrl}`);
|
|
316
313
|
// Open the normalized URL
|
|
317
314
|
Linking.openURL(normalizedUrl);
|
|
318
315
|
} catch (error) {
|
|
319
|
-
console.error('
|
|
316
|
+
console.error('OAuth URL handling error');
|
|
320
317
|
// Only try the fallback if oauthUrl is not null
|
|
321
318
|
if (oauthUrl != null) {
|
|
322
319
|
try {
|
|
323
320
|
const fallbackUrl = typeof oauthUrl === 'string' ? oauthUrl : oauthUrl.toString();
|
|
324
|
-
console.log(
|
|
321
|
+
console.log('Attempting fallback OAuth opening');
|
|
325
322
|
Linking.openURL(fallbackUrl);
|
|
326
323
|
} catch (fallbackError) {
|
|
327
|
-
console.error('
|
|
324
|
+
console.error('Fallback OAuth opening failed');
|
|
328
325
|
}
|
|
329
326
|
}
|
|
330
327
|
}
|
|
@@ -355,7 +352,6 @@ const QuilttConnector = ({ testId, connectorId, connectionId, institution, oauth
|
|
|
355
352
|
}, []);
|
|
356
353
|
// Ensure oauthRedirectUrl is encoded properly - only once
|
|
357
354
|
const safeOAuthRedirectUrl = useMemo(()=>{
|
|
358
|
-
console.log('Original oauthRedirectUrl:', oauthRedirectUrl);
|
|
359
355
|
return smartEncodeURIComponent(oauthRedirectUrl);
|
|
360
356
|
}, [
|
|
361
357
|
oauthRedirectUrl
|
|
@@ -368,17 +364,13 @@ const QuilttConnector = ({ testId, connectorId, connectionId, institution, oauth
|
|
|
368
364
|
// For the oauth_redirect_url, we need to be careful
|
|
369
365
|
// If it's already encoded, we need to decode it once to prevent
|
|
370
366
|
// the automatic encoding that happens with searchParams.append
|
|
371
|
-
if (
|
|
367
|
+
if (isEncoded(safeOAuthRedirectUrl)) {
|
|
372
368
|
const decodedOnce = decodeURIComponent(safeOAuthRedirectUrl);
|
|
373
369
|
url.searchParams.append('oauth_redirect_url', decodedOnce);
|
|
374
|
-
console.log('Using decoded oauth_redirect_url:', decodedOnce);
|
|
375
370
|
} else {
|
|
376
371
|
url.searchParams.append('oauth_redirect_url', safeOAuthRedirectUrl);
|
|
377
|
-
console.log('Using original oauth_redirect_url:', safeOAuthRedirectUrl);
|
|
378
372
|
}
|
|
379
|
-
|
|
380
|
-
console.log('Final connectorUrl:', finalUrl);
|
|
381
|
-
return finalUrl;
|
|
373
|
+
return url.toString();
|
|
382
374
|
}, [
|
|
383
375
|
connectorId,
|
|
384
376
|
safeOAuthRedirectUrl
|
|
@@ -435,50 +427,58 @@ const QuilttConnector = ({ testId, connectorId, connectionId, institution, oauth
|
|
|
435
427
|
const eventType = url.host;
|
|
436
428
|
switch(eventType){
|
|
437
429
|
case 'Load':
|
|
430
|
+
console.log('Event: Load');
|
|
438
431
|
initInjectedJavaScript();
|
|
439
432
|
onEvent?.(ConnectorSDKEventType.Load, metadata);
|
|
440
433
|
onLoad?.(metadata);
|
|
441
434
|
break;
|
|
442
435
|
case 'ExitAbort':
|
|
436
|
+
console.log('Event: ExitAbort');
|
|
443
437
|
clearLocalStorage();
|
|
444
438
|
onEvent?.(ConnectorSDKEventType.ExitAbort, metadata);
|
|
445
439
|
onExit?.(ConnectorSDKEventType.ExitAbort, metadata);
|
|
446
440
|
onExitAbort?.(metadata);
|
|
447
441
|
break;
|
|
448
442
|
case 'ExitError':
|
|
443
|
+
console.log('Event: ExitError');
|
|
449
444
|
clearLocalStorage();
|
|
450
445
|
onEvent?.(ConnectorSDKEventType.ExitError, metadata);
|
|
451
446
|
onExit?.(ConnectorSDKEventType.ExitError, metadata);
|
|
452
447
|
onExitError?.(metadata);
|
|
453
448
|
break;
|
|
454
449
|
case 'ExitSuccess':
|
|
450
|
+
console.log('Event: ExitSuccess');
|
|
455
451
|
clearLocalStorage();
|
|
456
452
|
onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata);
|
|
457
453
|
onExit?.(ConnectorSDKEventType.ExitSuccess, metadata);
|
|
458
454
|
onExitSuccess?.(metadata);
|
|
459
455
|
break;
|
|
460
456
|
case 'Authenticate':
|
|
457
|
+
console.log('Event: Authenticate');
|
|
461
458
|
break;
|
|
462
459
|
case 'OauthRequested':
|
|
463
460
|
{
|
|
464
|
-
|
|
465
|
-
console.log('Available search params:', Array.from(url.searchParams.keys()));
|
|
466
|
-
// Now we should be getting the oauthUrl parameter directly
|
|
461
|
+
console.log('Event: OauthRequested');
|
|
467
462
|
const oauthUrl = url.searchParams.get('oauthUrl');
|
|
468
|
-
console.log('Received oauthUrl:', oauthUrl);
|
|
469
|
-
// Check if oauthUrl exists before proceeding
|
|
470
463
|
if (oauthUrl) {
|
|
471
|
-
|
|
472
|
-
|
|
464
|
+
if (isEncoded(oauthUrl)) {
|
|
465
|
+
try {
|
|
466
|
+
const decodedUrl = decodeURIComponent(oauthUrl);
|
|
467
|
+
handleOAuthUrl(decodedUrl);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
console.error('OAuth URL decoding failed, using original');
|
|
470
|
+
handleOAuthUrl(oauthUrl);
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
handleOAuthUrl(oauthUrl);
|
|
474
|
+
}
|
|
473
475
|
} else {
|
|
474
|
-
|
|
475
|
-
console.error('OauthRequested event missing oauthUrl parameter');
|
|
476
|
-
console.log('All available params:', Object.fromEntries(url.searchParams.entries()));
|
|
476
|
+
console.error('OAuth URL missing from request');
|
|
477
477
|
}
|
|
478
478
|
break;
|
|
479
479
|
}
|
|
480
480
|
default:
|
|
481
|
-
console.log(
|
|
481
|
+
console.log(`Unhandled event: ${eventType}`);
|
|
482
482
|
break;
|
|
483
483
|
}
|
|
484
484
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quiltt/react-native",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.7",
|
|
4
4
|
"description": "React Native Components for Quiltt Connector",
|
|
5
5
|
"homepage": "https://github.com/quiltt/quiltt-js/tree/main/packages/react-native#readme",
|
|
6
6
|
"repository": {
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@honeybadger-io/core": "6.6.0",
|
|
32
32
|
"lodash.debounce": "4.0.8",
|
|
33
|
-
"@quiltt/
|
|
34
|
-
"@quiltt/
|
|
33
|
+
"@quiltt/core": "3.9.7",
|
|
34
|
+
"@quiltt/react": "3.9.7"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@biomejs/biome": "1.9.4",
|
|
@@ -11,7 +11,7 @@ import type { ConnectorSDKCallbackMetadata, ConnectorSDKCallbacks } from '@quilt
|
|
|
11
11
|
import {
|
|
12
12
|
ErrorReporter,
|
|
13
13
|
getErrorMessage,
|
|
14
|
-
|
|
14
|
+
isEncoded,
|
|
15
15
|
normalizeUrlEncoding,
|
|
16
16
|
smartEncodeURIComponent,
|
|
17
17
|
} from '@/utils'
|
|
@@ -38,18 +38,17 @@ export const checkConnectorUrl = async (
|
|
|
38
38
|
const response = await fetch(connectorUrl)
|
|
39
39
|
if (!response.ok) {
|
|
40
40
|
responseStatus = response.status
|
|
41
|
-
throw new Error(
|
|
41
|
+
throw new Error('Connector URL is not routable.')
|
|
42
42
|
}
|
|
43
|
-
console.log(`The URL ${connectorUrl} is routable.`)
|
|
44
43
|
return { checked: true }
|
|
45
44
|
} catch (e) {
|
|
46
45
|
error = e as Error
|
|
47
|
-
console.error(
|
|
46
|
+
console.error('Failed to connect to connector URL')
|
|
48
47
|
|
|
49
48
|
if (retryCount < PREFLIGHT_RETRY_COUNT) {
|
|
50
49
|
const delay = 50 * 2 ** retryCount
|
|
51
50
|
await new Promise((resolve) => setTimeout(resolve, delay))
|
|
52
|
-
console.log(`Retrying... Attempt
|
|
51
|
+
console.log(`Retrying connection... Attempt ${retryCount + 1}`)
|
|
53
52
|
return checkConnectorUrl(connectorUrl, retryCount + 1)
|
|
54
53
|
}
|
|
55
54
|
const errorMessage = getErrorMessage(responseStatus, error as Error)
|
|
@@ -67,7 +66,7 @@ export const handleOAuthUrl = (oauthUrl: URL | string | null | undefined) => {
|
|
|
67
66
|
try {
|
|
68
67
|
// Throw error if oauthUrl is null or undefined
|
|
69
68
|
if (oauthUrl == null) {
|
|
70
|
-
throw new Error('
|
|
69
|
+
throw new Error('OAuth URL missing')
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
// Convert to string if it's a URL object
|
|
@@ -75,28 +74,25 @@ export const handleOAuthUrl = (oauthUrl: URL | string | null | undefined) => {
|
|
|
75
74
|
|
|
76
75
|
// Throw error if the resulting string is empty
|
|
77
76
|
if (!urlString || urlString.trim() === '') {
|
|
78
|
-
throw new Error('
|
|
77
|
+
throw new Error('Empty OAuth URL')
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
// Normalize the URL encoding
|
|
82
81
|
const normalizedUrl = normalizeUrlEncoding(urlString)
|
|
83
82
|
|
|
84
|
-
// Log the URL we're about to open
|
|
85
|
-
console.log(`handleOAuthUrl - Opening URL - ${normalizedUrl}`)
|
|
86
|
-
|
|
87
83
|
// Open the normalized URL
|
|
88
84
|
Linking.openURL(normalizedUrl)
|
|
89
85
|
} catch (error) {
|
|
90
|
-
console.error('
|
|
86
|
+
console.error('OAuth URL handling error')
|
|
91
87
|
|
|
92
88
|
// Only try the fallback if oauthUrl is not null
|
|
93
89
|
if (oauthUrl != null) {
|
|
94
90
|
try {
|
|
95
91
|
const fallbackUrl = typeof oauthUrl === 'string' ? oauthUrl : oauthUrl.toString()
|
|
96
|
-
console.log(
|
|
92
|
+
console.log('Attempting fallback OAuth opening')
|
|
97
93
|
Linking.openURL(fallbackUrl)
|
|
98
94
|
} catch (fallbackError) {
|
|
99
|
-
console.error('
|
|
95
|
+
console.error('Fallback OAuth opening failed')
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
}
|
|
@@ -149,7 +145,6 @@ const QuilttConnector = ({
|
|
|
149
145
|
|
|
150
146
|
// Ensure oauthRedirectUrl is encoded properly - only once
|
|
151
147
|
const safeOAuthRedirectUrl = useMemo(() => {
|
|
152
|
-
console.log('Original oauthRedirectUrl:', oauthRedirectUrl)
|
|
153
148
|
return smartEncodeURIComponent(oauthRedirectUrl)
|
|
154
149
|
}, [oauthRedirectUrl])
|
|
155
150
|
|
|
@@ -163,18 +158,14 @@ const QuilttConnector = ({
|
|
|
163
158
|
// For the oauth_redirect_url, we need to be careful
|
|
164
159
|
// If it's already encoded, we need to decode it once to prevent
|
|
165
160
|
// the automatic encoding that happens with searchParams.append
|
|
166
|
-
if (
|
|
161
|
+
if (isEncoded(safeOAuthRedirectUrl)) {
|
|
167
162
|
const decodedOnce = decodeURIComponent(safeOAuthRedirectUrl)
|
|
168
163
|
url.searchParams.append('oauth_redirect_url', decodedOnce)
|
|
169
|
-
console.log('Using decoded oauth_redirect_url:', decodedOnce)
|
|
170
164
|
} else {
|
|
171
165
|
url.searchParams.append('oauth_redirect_url', safeOAuthRedirectUrl)
|
|
172
|
-
console.log('Using original oauth_redirect_url:', safeOAuthRedirectUrl)
|
|
173
166
|
}
|
|
174
167
|
|
|
175
|
-
|
|
176
|
-
console.log('Final connectorUrl:', finalUrl)
|
|
177
|
-
return finalUrl
|
|
168
|
+
return url.toString()
|
|
178
169
|
}, [connectorId, safeOAuthRedirectUrl])
|
|
179
170
|
|
|
180
171
|
useEffect(() => {
|
|
@@ -226,52 +217,59 @@ const QuilttConnector = ({
|
|
|
226
217
|
const eventType = url.host
|
|
227
218
|
switch (eventType) {
|
|
228
219
|
case 'Load':
|
|
220
|
+
console.log('Event: Load')
|
|
229
221
|
initInjectedJavaScript()
|
|
230
222
|
onEvent?.(ConnectorSDKEventType.Load, metadata)
|
|
231
223
|
onLoad?.(metadata)
|
|
232
224
|
break
|
|
233
225
|
case 'ExitAbort':
|
|
226
|
+
console.log('Event: ExitAbort')
|
|
234
227
|
clearLocalStorage()
|
|
235
228
|
onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)
|
|
236
229
|
onExit?.(ConnectorSDKEventType.ExitAbort, metadata)
|
|
237
230
|
onExitAbort?.(metadata)
|
|
238
231
|
break
|
|
239
232
|
case 'ExitError':
|
|
233
|
+
console.log('Event: ExitError')
|
|
240
234
|
clearLocalStorage()
|
|
241
235
|
onEvent?.(ConnectorSDKEventType.ExitError, metadata)
|
|
242
236
|
onExit?.(ConnectorSDKEventType.ExitError, metadata)
|
|
243
237
|
onExitError?.(metadata)
|
|
244
238
|
break
|
|
245
239
|
case 'ExitSuccess':
|
|
240
|
+
console.log('Event: ExitSuccess')
|
|
246
241
|
clearLocalStorage()
|
|
247
242
|
onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)
|
|
248
243
|
onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)
|
|
249
244
|
onExitSuccess?.(metadata)
|
|
250
245
|
break
|
|
251
246
|
case 'Authenticate':
|
|
247
|
+
console.log('Event: Authenticate')
|
|
252
248
|
// TODO: handle Authenticate
|
|
253
249
|
break
|
|
254
250
|
case 'OauthRequested': {
|
|
255
|
-
|
|
256
|
-
console.log('Available search params:', Array.from(url.searchParams.keys()))
|
|
257
|
-
|
|
258
|
-
// Now we should be getting the oauthUrl parameter directly
|
|
251
|
+
console.log('Event: OauthRequested')
|
|
259
252
|
const oauthUrl = url.searchParams.get('oauthUrl')
|
|
260
|
-
console.log('Received oauthUrl:', oauthUrl)
|
|
261
253
|
|
|
262
|
-
// Check if oauthUrl exists before proceeding
|
|
263
254
|
if (oauthUrl) {
|
|
264
|
-
|
|
265
|
-
|
|
255
|
+
if (isEncoded(oauthUrl)) {
|
|
256
|
+
try {
|
|
257
|
+
const decodedUrl = decodeURIComponent(oauthUrl)
|
|
258
|
+
handleOAuthUrl(decodedUrl)
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error('OAuth URL decoding failed, using original')
|
|
261
|
+
handleOAuthUrl(oauthUrl)
|
|
262
|
+
}
|
|
263
|
+
} else {
|
|
264
|
+
handleOAuthUrl(oauthUrl)
|
|
265
|
+
}
|
|
266
266
|
} else {
|
|
267
|
-
|
|
268
|
-
console.error('OauthRequested event missing oauthUrl parameter')
|
|
269
|
-
console.log('All available params:', Object.fromEntries(url.searchParams.entries()))
|
|
267
|
+
console.error('OAuth URL missing from request')
|
|
270
268
|
}
|
|
271
269
|
break
|
|
272
270
|
}
|
|
273
271
|
default:
|
|
274
|
-
console.log(
|
|
272
|
+
console.log(`Unhandled event: ${eventType}`)
|
|
275
273
|
break
|
|
276
274
|
}
|
|
277
275
|
})
|
package/src/utils/url.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @param str The string to check
|
|
4
4
|
* @returns boolean indicating if the string appears to be URL encoded
|
|
5
5
|
*/
|
|
6
|
-
export const
|
|
6
|
+
export const isEncoded = (str: string): boolean => {
|
|
7
7
|
// Check for typical URL encoding patterns like %20, %3A, etc.
|
|
8
8
|
const hasEncodedChars = /%[0-9A-F]{2}/i.test(str)
|
|
9
9
|
|
|
@@ -23,7 +23,7 @@ export const smartEncodeURIComponent = (str: string): string => {
|
|
|
23
23
|
if (!str) return str
|
|
24
24
|
|
|
25
25
|
// If it's already encoded, return as is
|
|
26
|
-
if (
|
|
26
|
+
if (isEncoded(str)) {
|
|
27
27
|
console.log('URL already encoded, skipping encoding:', str)
|
|
28
28
|
return str
|
|
29
29
|
}
|
|
@@ -51,7 +51,7 @@ export const createUrlWithParams = (baseUrl: string, params: Record<string, stri
|
|
|
51
51
|
if (value == null) return
|
|
52
52
|
|
|
53
53
|
// For oauth_redirect_url specifically, ensure it's not double encoded
|
|
54
|
-
if (key === 'oauth_redirect_url' &&
|
|
54
|
+
if (key === 'oauth_redirect_url' && isEncoded(value)) {
|
|
55
55
|
// Decode once to counteract the automatic encoding that will happen
|
|
56
56
|
const decodedOnce = decodeURIComponent(value)
|
|
57
57
|
url.searchParams.append(key, decodedOnce)
|