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, clientId, clientSecret, redirectUrl, grantType, authCode, sendClientSecretIn = 'header', apiKeyId, authFlowDivEl, scopes = null) {
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
- } = JSON.parse(base64url.decode(parameters.state));
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(3);
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
- const codeVerifier = randomBytes.toString('hex').split(',').join('');
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, clientId, clientSecret, redirectUrl, grantType, authCode, sendClientSecretIn = 'header', apiKeyId, authFlowDivEl, scopes = null) {
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
- } = JSON.parse(_base64url.default.decode(parameters.state));
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(3);
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
- const codeVerifier = randomBytes.toString('hex').split(',').join('');
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.534",
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",