openapi-explorer 1.0.534 → 1.0.538
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.
|
@@ -480,6 +480,13 @@ export default class OpenApiExplorer extends LitElement {
|
|
|
480
480
|
this.resolvedSpec = null;
|
|
481
481
|
console.error('OpenAPI Explorer: Unable to resolve the API spec..', err); // eslint-disable-line no-console
|
|
482
482
|
}
|
|
483
|
+
|
|
484
|
+
try {
|
|
485
|
+
await checkForAuthToken.call(this);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
// eslint-disable-next-line no-console
|
|
488
|
+
console.error('Failed to check for authentication token', error);
|
|
489
|
+
}
|
|
483
490
|
} // Public Method
|
|
484
491
|
|
|
485
492
|
|
|
@@ -54,8 +54,14 @@ function updateOAuthKey(apiKeyId, tokenType = 'Bearer', accessToken) {
|
|
|
54
54
|
} // Gets Access-Token in exchange of Authorization Code
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
async function fetchAccessToken(tokenUrl,
|
|
57
|
+
async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redirectUrl, grantType, authCode, sendClientSecretIn = 'header', apiKeyId, authFlowDivEl, scopes = null) {
|
|
58
58
|
const respDisplayEl = authFlowDivEl ? authFlowDivEl.querySelector('.oauth-resp-display') : undefined;
|
|
59
|
+
const {
|
|
60
|
+
codeVerifier,
|
|
61
|
+
clientId: requestClientId
|
|
62
|
+
} = JSON.parse(localStorage.getItem('openapi-explorer-oauth') || '{}');
|
|
63
|
+
localStorage.removeItem('openapi-explorer-oauth');
|
|
64
|
+
const clientId = suggestedClientId || requestClientId;
|
|
59
65
|
const urlFormParams = new URLSearchParams();
|
|
60
66
|
const headers = new Headers();
|
|
61
67
|
urlFormParams.append('grant_type', grantType);
|
|
@@ -82,11 +88,6 @@ async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, g
|
|
|
82
88
|
urlFormParams.append('scope', scopes);
|
|
83
89
|
}
|
|
84
90
|
|
|
85
|
-
const {
|
|
86
|
-
codeVerifier
|
|
87
|
-
} = JSON.parse(localStorage.getItem('openapi-explorer-oauth') || '{}');
|
|
88
|
-
localStorage.removeItem('openapi-explorer-oauth');
|
|
89
|
-
|
|
90
91
|
if (codeVerifier) {
|
|
91
92
|
urlFormParams.append('code_verifier', codeVerifier);
|
|
92
93
|
}
|
|
@@ -163,11 +164,22 @@ export async function checkForAuthToken(redirectToApiLocation) {
|
|
|
163
164
|
|
|
164
165
|
const sanitizedUrlWithHash = newUrl.toString().replace(/#((code|state|access_token|id_token|authuser|expires_in|hd|prompt|scope|token_type)=[^&]+&?)*$/ig, '');
|
|
165
166
|
history.replaceState({}, undefined, sanitizedUrlWithHash);
|
|
167
|
+
let parsedState;
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
// If somehow the state contains a question mark, just remove it, a ? is not a valid here
|
|
171
|
+
parsedState = JSON.parse(base64url.decode(parameters.state.replace(/\?.*$/, '')));
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// eslint-disable-next-line no-console
|
|
174
|
+
console.error('The state parameter in the OAuth response is invalid', error, parameters.state);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
166
178
|
const {
|
|
167
179
|
apiKeyId,
|
|
168
180
|
flowId,
|
|
169
181
|
url
|
|
170
|
-
} =
|
|
182
|
+
} = parsedState;
|
|
171
183
|
|
|
172
184
|
if (redirectToApiLocation && url && !parameters.redirect_auth) {
|
|
173
185
|
const apiExplorerLocation = new URL(url);
|
|
@@ -207,25 +219,29 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
|
|
|
207
219
|
if (flowType === 'authorizationCode' || flowType === 'implicit') {
|
|
208
220
|
const authUrlObj = new URL(authUrl);
|
|
209
221
|
const authCodeParams = new URLSearchParams(authUrlObj.search);
|
|
222
|
+
let codeVerifier;
|
|
210
223
|
|
|
211
224
|
if (flowType === 'authorizationCode') {
|
|
212
|
-
const randomBytes = new Uint32Array(
|
|
225
|
+
const randomBytes = new Uint32Array(12);
|
|
213
226
|
(window.crypto || window.msCrypto).getRandomValues(randomBytes);
|
|
214
227
|
authCodeParams.set('nonce', randomBytes.toString('hex').split(',').join(''));
|
|
215
228
|
grantType = 'authorization_code';
|
|
216
229
|
responseType = 'code';
|
|
217
|
-
|
|
230
|
+
codeVerifier = randomBytes.toString('hex').split(',').join('');
|
|
218
231
|
const hash = await (window.crypto || window.msCrypto).subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
|
|
219
232
|
const codeChallenge = base64url(hash);
|
|
220
233
|
authCodeParams.set('code_challenge', codeChallenge);
|
|
221
234
|
authCodeParams.set('code_challenge_method', 'S256');
|
|
222
|
-
localStorage.setItem('openapi-explorer-oauth', JSON.stringify({
|
|
223
|
-
codeVerifier
|
|
224
|
-
}));
|
|
225
235
|
} else if (flowType === 'implicit') {
|
|
226
236
|
responseType = 'token';
|
|
227
237
|
}
|
|
228
238
|
|
|
239
|
+
localStorage.setItem('openapi-explorer-oauth', JSON.stringify({
|
|
240
|
+
codeVerifier,
|
|
241
|
+
clientId,
|
|
242
|
+
apiKeyId,
|
|
243
|
+
flowId: flowType
|
|
244
|
+
}));
|
|
229
245
|
const selectedScopes = checkedScopeEls.map(v => v.value).join(' ');
|
|
230
246
|
|
|
231
247
|
if (selectedScopes) {
|
|
@@ -521,6 +521,13 @@ class OpenApiExplorer extends _lit.LitElement {
|
|
|
521
521
|
this.resolvedSpec = null;
|
|
522
522
|
console.error('OpenAPI Explorer: Unable to resolve the API spec..', err); // eslint-disable-line no-console
|
|
523
523
|
}
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
await _securitySchemeTemplate.checkForAuthToken.call(this);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
// eslint-disable-next-line no-console
|
|
529
|
+
console.error('Failed to check for authentication token', error);
|
|
530
|
+
}
|
|
524
531
|
} // Public Method
|
|
525
532
|
|
|
526
533
|
|
|
@@ -67,8 +67,14 @@ function updateOAuthKey(apiKeyId, tokenType = 'Bearer', accessToken) {
|
|
|
67
67
|
} // Gets Access-Token in exchange of Authorization Code
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
async function fetchAccessToken(tokenUrl,
|
|
70
|
+
async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redirectUrl, grantType, authCode, sendClientSecretIn = 'header', apiKeyId, authFlowDivEl, scopes = null) {
|
|
71
71
|
const respDisplayEl = authFlowDivEl ? authFlowDivEl.querySelector('.oauth-resp-display') : undefined;
|
|
72
|
+
const {
|
|
73
|
+
codeVerifier,
|
|
74
|
+
clientId: requestClientId
|
|
75
|
+
} = JSON.parse(localStorage.getItem('openapi-explorer-oauth') || '{}');
|
|
76
|
+
localStorage.removeItem('openapi-explorer-oauth');
|
|
77
|
+
const clientId = suggestedClientId || requestClientId;
|
|
72
78
|
const urlFormParams = new URLSearchParams();
|
|
73
79
|
const headers = new Headers();
|
|
74
80
|
urlFormParams.append('grant_type', grantType);
|
|
@@ -95,11 +101,6 @@ async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, g
|
|
|
95
101
|
urlFormParams.append('scope', scopes);
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
const {
|
|
99
|
-
codeVerifier
|
|
100
|
-
} = JSON.parse(localStorage.getItem('openapi-explorer-oauth') || '{}');
|
|
101
|
-
localStorage.removeItem('openapi-explorer-oauth');
|
|
102
|
-
|
|
103
104
|
if (codeVerifier) {
|
|
104
105
|
urlFormParams.append('code_verifier', codeVerifier);
|
|
105
106
|
}
|
|
@@ -176,11 +177,22 @@ async function checkForAuthToken(redirectToApiLocation) {
|
|
|
176
177
|
|
|
177
178
|
const sanitizedUrlWithHash = newUrl.toString().replace(/#((code|state|access_token|id_token|authuser|expires_in|hd|prompt|scope|token_type)=[^&]+&?)*$/ig, '');
|
|
178
179
|
history.replaceState({}, undefined, sanitizedUrlWithHash);
|
|
180
|
+
let parsedState;
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
// If somehow the state contains a question mark, just remove it, a ? is not a valid here
|
|
184
|
+
parsedState = JSON.parse(_base64url.default.decode(parameters.state.replace(/\?.*$/, '')));
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// eslint-disable-next-line no-console
|
|
187
|
+
console.error('The state parameter in the OAuth response is invalid', error, parameters.state);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
179
191
|
const {
|
|
180
192
|
apiKeyId,
|
|
181
193
|
flowId,
|
|
182
194
|
url
|
|
183
|
-
} =
|
|
195
|
+
} = parsedState;
|
|
184
196
|
|
|
185
197
|
if (redirectToApiLocation && url && !parameters.redirect_auth) {
|
|
186
198
|
const apiExplorerLocation = new URL(url);
|
|
@@ -220,25 +232,29 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
|
|
|
220
232
|
if (flowType === 'authorizationCode' || flowType === 'implicit') {
|
|
221
233
|
const authUrlObj = new URL(authUrl);
|
|
222
234
|
const authCodeParams = new URLSearchParams(authUrlObj.search);
|
|
235
|
+
let codeVerifier;
|
|
223
236
|
|
|
224
237
|
if (flowType === 'authorizationCode') {
|
|
225
|
-
const randomBytes = new Uint32Array(
|
|
238
|
+
const randomBytes = new Uint32Array(12);
|
|
226
239
|
(window.crypto || window.msCrypto).getRandomValues(randomBytes);
|
|
227
240
|
authCodeParams.set('nonce', randomBytes.toString('hex').split(',').join(''));
|
|
228
241
|
grantType = 'authorization_code';
|
|
229
242
|
responseType = 'code';
|
|
230
|
-
|
|
243
|
+
codeVerifier = randomBytes.toString('hex').split(',').join('');
|
|
231
244
|
const hash = await (window.crypto || window.msCrypto).subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
|
|
232
245
|
const codeChallenge = (0, _base64url.default)(hash);
|
|
233
246
|
authCodeParams.set('code_challenge', codeChallenge);
|
|
234
247
|
authCodeParams.set('code_challenge_method', 'S256');
|
|
235
|
-
localStorage.setItem('openapi-explorer-oauth', JSON.stringify({
|
|
236
|
-
codeVerifier
|
|
237
|
-
}));
|
|
238
248
|
} else if (flowType === 'implicit') {
|
|
239
249
|
responseType = 'token';
|
|
240
250
|
}
|
|
241
251
|
|
|
252
|
+
localStorage.setItem('openapi-explorer-oauth', JSON.stringify({
|
|
253
|
+
codeVerifier,
|
|
254
|
+
clientId,
|
|
255
|
+
apiKeyId,
|
|
256
|
+
flowId: flowType
|
|
257
|
+
}));
|
|
242
258
|
const selectedScopes = checkedScopeEls.map(v => v.value).join(' ');
|
|
243
259
|
|
|
244
260
|
if (selectedScopes) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-explorer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.538",
|
|
4
4
|
"description": "OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console",
|
|
5
5
|
"author": "Rhosys Developers <developers@rhosys.ch>",
|
|
6
6
|
"type": "module",
|