rapidoc 9.3.7 → 10.0.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 (69) hide show
  1. package/README.md +193 -61
  2. package/dist/rapidoc-min.js +279 -3912
  3. package/package.json +24 -47
  4. package/.babelrc.json +0 -42
  5. package/.eslintrc +0 -53
  6. package/.github/FUNDING.yml +0 -13
  7. package/.github/workflow/words.yaml +0 -22
  8. package/CONTRIBUTING.md +0 -35
  9. package/dist/index.html +0 -6
  10. package/dist/index.html.gz +0 -0
  11. package/dist/rapidoc-min.js.LICENSE.txt +0 -64
  12. package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
  13. package/dist/rapidoc-min.js.gz +0 -0
  14. package/dist/rapidoc-min.js.map +0 -1
  15. package/dist/rapidoc-min.js.map.gz +0 -0
  16. package/dist/rapidoc.js +0 -21594
  17. package/dist/report.html +0 -39
  18. package/index-hashroute.html +0 -65
  19. package/index.html +0 -249
  20. package/index1.html +0 -244
  21. package/jsconfig.json +0 -11
  22. package/logo.png +0 -0
  23. package/performance.html +0 -31
  24. package/src/components/api-request.js +0 -1787
  25. package/src/components/api-response.js +0 -335
  26. package/src/components/dialog-box.js +0 -73
  27. package/src/components/json-tree.js +0 -145
  28. package/src/components/schema-table.js +0 -358
  29. package/src/components/schema-tree.js +0 -378
  30. package/src/components/tag-input.js +0 -135
  31. package/src/index.js +0 -7
  32. package/src/json-schema-viewer.js +0 -345
  33. package/src/oauth-receiver.js +0 -56
  34. package/src/rapidoc-mini.js +0 -380
  35. package/src/rapidoc.js +0 -1082
  36. package/src/styles/border-styles.js +0 -24
  37. package/src/styles/custom-styles.js +0 -10
  38. package/src/styles/dialog-box-styles.js +0 -75
  39. package/src/styles/endpoint-styles.js +0 -202
  40. package/src/styles/flex-styles.js +0 -15
  41. package/src/styles/font-styles.js +0 -268
  42. package/src/styles/info-styles.js +0 -21
  43. package/src/styles/input-styles.js +0 -202
  44. package/src/styles/nav-styles.js +0 -198
  45. package/src/styles/prism-styles.js +0 -105
  46. package/src/styles/schema-styles.js +0 -121
  47. package/src/styles/tab-styles.js +0 -47
  48. package/src/styles/table-styles.js +0 -58
  49. package/src/templates/advance-search-template.js +0 -72
  50. package/src/templates/callback-template.js +0 -73
  51. package/src/templates/code-samples-template.js +0 -34
  52. package/src/templates/components-template.js +0 -76
  53. package/src/templates/endpoint-template.js +0 -249
  54. package/src/templates/expanded-endpoint-template.js +0 -197
  55. package/src/templates/focused-endpoint-template.js +0 -110
  56. package/src/templates/header-template.js +0 -66
  57. package/src/templates/json-schema-viewer-template.js +0 -185
  58. package/src/templates/logo-template.js +0 -18
  59. package/src/templates/main-body-template.js +0 -121
  60. package/src/templates/navbar-template.js +0 -272
  61. package/src/templates/overview-template.js +0 -79
  62. package/src/templates/security-scheme-template.js +0 -610
  63. package/src/templates/server-template.js +0 -115
  64. package/src/utils/color-utils.js +0 -59
  65. package/src/utils/common-utils.js +0 -168
  66. package/src/utils/schema-utils.js +0 -1086
  67. package/src/utils/spec-parser.js +0 -462
  68. package/src/utils/theme.js +0 -288
  69. package/webpack.config.js +0 -142
@@ -1,610 +0,0 @@
1
- /* eslint-disable arrow-body-style */
2
- import { html } from 'lit';
3
- import { unsafeHTML } from 'lit/directives/unsafe-html.js'; // eslint-disable-line import/extensions
4
- import { marked } from 'marked';
5
-
6
- const codeVerifier = '731DB1C3F7EA533B85E29492D26AA-1234567890-1234567890';
7
- const codeChallenge = '4FatVDBJKPAo4JgLLaaQFMUcQPn5CrPRvLlaob9PTYc'; // Base64 encoded SHA-256
8
-
9
- const localStorageKey = 'rapidoc';
10
-
11
- export function applyApiKey(securitySchemeId, username = '', password = '', providedApikeyVal = '') {
12
- const securityObj = this.resolvedSpec.securitySchemes?.find((v) => (v.securitySchemeId === securitySchemeId));
13
- if (!securityObj) {
14
- return false;
15
- }
16
- let finalApiKeyValue = '';
17
- if (securityObj.scheme?.toLowerCase() === 'basic') {
18
- if (username) {
19
- finalApiKeyValue = `Basic ${Buffer.from(`${username}:${password}`, 'utf8').toString('base64')}`;
20
- }
21
- } else if (providedApikeyVal) {
22
- securityObj.value = providedApikeyVal;
23
- finalApiKeyValue = `${securityObj.scheme?.toLowerCase() === 'bearer' ? 'Bearer ' : ''}${providedApikeyVal}`;
24
- }
25
- if (finalApiKeyValue) {
26
- securityObj.finalKeyValue = finalApiKeyValue;
27
- this.requestUpdate();
28
- return true;
29
- }
30
- return false;
31
- }
32
-
33
- export function onClearAllApiKeys() {
34
- this.resolvedSpec.securitySchemes?.forEach((v) => {
35
- v.user = '';
36
- v.password = '';
37
- v.value = '';
38
- v.finalKeyValue = '';
39
- });
40
- this.requestUpdate();
41
- }
42
-
43
- function getPersistedApiKeys() {
44
- return JSON.parse(localStorage.getItem(localStorageKey)) || {};
45
- }
46
-
47
- function setPersistedApiKeys(obj) {
48
- localStorage.setItem(localStorageKey, JSON.stringify(obj));
49
- }
50
-
51
- export function recoverPersistedApiKeys() {
52
- const rapidocLs = getPersistedApiKeys.call(this);
53
- Object.values(rapidocLs).forEach((p) => {
54
- applyApiKey.call(this, p.securitySchemeId, p.username, p.password, p.value);
55
- });
56
- }
57
-
58
- function onApiKeyChange(securitySchemeId) {
59
- let apiKeyValue = '';
60
- const securityObj = this.resolvedSpec.securitySchemes.find((v) => (v.securitySchemeId === securitySchemeId));
61
- if (securityObj) {
62
- const trEl = this.shadowRoot.getElementById(`security-scheme-${securitySchemeId}`);
63
- if (trEl) {
64
- if (securityObj.type && securityObj.scheme && securityObj.type === 'http' && securityObj.scheme.toLowerCase() === 'basic') {
65
- const userVal = trEl.querySelector('.api-key-user').value.trim();
66
- const passwordVal = trEl.querySelector('.api-key-password').value.trim();
67
- applyApiKey.call(this, securitySchemeId, userVal, passwordVal);
68
- } else {
69
- apiKeyValue = trEl.querySelector('.api-key-input').value.trim();
70
- applyApiKey.call(this, securitySchemeId, '', '', apiKeyValue);
71
- }
72
- if (this.persistAuth === 'true') {
73
- const rapidocLs = getPersistedApiKeys.call(this);
74
- rapidocLs[securitySchemeId] = securityObj;
75
- setPersistedApiKeys.call(this, rapidocLs);
76
- }
77
- }
78
- }
79
- }
80
-
81
- // Updates the OAuth Access Token (API key), so it reflects in UI and gets used in TRY calls
82
- function updateOAuthKey(securitySchemeId, accessToken, tokenType = 'Bearer') {
83
- const securityObj = this.resolvedSpec.securitySchemes.find((v) => (v.securitySchemeId === securitySchemeId));
84
- securityObj.finalKeyValue = `${(tokenType.toLowerCase() === 'bearer' ? 'Bearer' : (tokenType.toLowerCase() === 'mac' ? 'MAC' : tokenType))} ${accessToken}`;
85
- this.requestUpdate();
86
- }
87
-
88
- /* eslint-disable no-console */
89
- // Gets Access-Token in exchange of Authorization Code
90
- async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, grantType, authCode, securitySchemeId, authFlowDivEl, sendClientSecretIn = 'header', scopes = null, username = null, password = null) {
91
- const respDisplayEl = authFlowDivEl ? authFlowDivEl.querySelector('.oauth-resp-display') : undefined;
92
- const urlFormParams = new URLSearchParams();
93
- const headers = new Headers();
94
- urlFormParams.append('grant_type', grantType);
95
- if (grantType === 'authorization_code') {
96
- urlFormParams.append('client_id', clientId);
97
- urlFormParams.append('client_secret', clientSecret);
98
- }
99
- if (grantType !== 'client_credentials' && grantType !== 'password') {
100
- urlFormParams.append('redirect_uri', redirectUrl);
101
- }
102
- if (authCode) {
103
- urlFormParams.append('code', authCode);
104
- urlFormParams.append('code_verifier', codeVerifier); // for PKCE
105
- }
106
- if (sendClientSecretIn === 'header') {
107
- headers.set('Authorization', `Basic ${Buffer.from(`${clientId}:${clientSecret}`, 'utf8').toString('base64')}`);
108
- } else if (grantType !== 'authorization_code') {
109
- urlFormParams.append('client_id', clientId);
110
- urlFormParams.append('client_secret', clientSecret);
111
- }
112
- if (grantType === 'password') {
113
- urlFormParams.append('username', username);
114
- urlFormParams.append('password', password);
115
- }
116
- if (scopes) {
117
- urlFormParams.append('scope', scopes);
118
- }
119
-
120
- try {
121
- const resp = await fetch(tokenUrl, { method: 'POST', headers, body: urlFormParams });
122
- const tokenResp = await resp.json();
123
- if (resp.ok) {
124
- if (tokenResp.token_type && tokenResp.access_token) {
125
- updateOAuthKey.call(this, securitySchemeId, tokenResp.access_token, tokenResp.token_type);
126
- if (respDisplayEl) {
127
- respDisplayEl.innerHTML = '<span style="color:var(--green)">Access Token Received</span>';
128
- }
129
- return true;
130
- }
131
- } else {
132
- if (respDisplayEl) {
133
- respDisplayEl.innerHTML = `<span style="color:var(--red)">${tokenResp.error_description || tokenResp.error_description || 'Unable to get access token'}</span>`;
134
- }
135
- return false;
136
- }
137
- } catch {
138
- if (respDisplayEl) {
139
- respDisplayEl.innerHTML = '<span style="color:var(--red)">Failed to get access token</span>';
140
- }
141
- return false;
142
- }
143
- }
144
-
145
- // Gets invoked when it receives the Authorization Code from the other window via message-event
146
- async function onWindowMessageEvent(msgEvent, winObj, tokenUrl, clientId, clientSecret, redirectUrl, grantType, sendClientSecretIn, securitySchemeId, authFlowDivEl) {
147
- sessionStorage.removeItem('winMessageEventActive');
148
- winObj.close();
149
- if (msgEvent.data.fake) {
150
- return;
151
- }
152
- if (!msgEvent.data) {
153
- console.warn('RapiDoc: Received no data with authorization message');
154
- }
155
- if (msgEvent.data.error) {
156
- console.warn('RapiDoc: Error while receiving data');
157
- }
158
- if (msgEvent.data) {
159
- if (msgEvent.data.responseType === 'code') {
160
- // Authorization Code flow
161
- fetchAccessToken.call(this, tokenUrl, clientId, clientSecret, redirectUrl, grantType, msgEvent.data.code, securitySchemeId, authFlowDivEl, sendClientSecretIn);
162
- } else if (msgEvent.data.responseType === 'token') {
163
- // Implicit flow
164
- updateOAuthKey.call(this, securitySchemeId, msgEvent.data.access_token, msgEvent.data.token_type);
165
- }
166
- }
167
- }
168
-
169
- // code_challenge generator for PKCE flow
170
- // TODO: Implement dynamic generation of code-challenge based on code-verifier
171
- /*
172
- async function generateCodeChallenge() {
173
- const encoder = new TextEncoder();
174
- const data = encoder.encode(codeVerifier);
175
- const sha256Hash = await window.crypto.subtle.digest('SHA-256', data); // returns Unit8Array
176
- // const utf8Decoder = new TextDecoder();
177
- // const b64EncodedSha256 = btoa(utf8Decoder.decode(sha256Hash));
178
- const b64EncodedSha256 = base64encode(sha256Hash);
179
- return b64EncodedSha256;
180
- }
181
- */
182
-
183
- async function onInvokeOAuthFlow(securitySchemeId, flowType, authUrl, tokenUrl, e) {
184
- const authFlowDivEl = e.target.closest('.oauth-flow');
185
- const clientId = authFlowDivEl.querySelector('.oauth-client-id') ? authFlowDivEl.querySelector('.oauth-client-id').value.trim() : '';
186
- const clientSecret = authFlowDivEl.querySelector('.oauth-client-secret') ? authFlowDivEl.querySelector('.oauth-client-secret').value.trim() : '';
187
- const username = authFlowDivEl.querySelector('.api-key-user') ? authFlowDivEl.querySelector('.api-key-user').value.trim() : '';
188
- const password = authFlowDivEl.querySelector('.api-key-password') ? authFlowDivEl.querySelector('.api-key-password').value.trim() : '';
189
- const sendClientSecretIn = authFlowDivEl.querySelector('.oauth-send-client-secret-in') ? authFlowDivEl.querySelector('.oauth-send-client-secret-in').value.trim() : 'header';
190
- const checkedScopeEls = [...authFlowDivEl.querySelectorAll('.scope-checkbox:checked')];
191
- const pkceCheckboxEl = authFlowDivEl.querySelector(`#${securitySchemeId}-pkce`);
192
- const state = (`${Math.random().toString(36).slice(2, 9)}random${Math.random().toString(36).slice(2, 9)}`);
193
- const nonce = (`${Math.random().toString(36).slice(2, 9)}random${Math.random().toString(36).slice(2, 9)}`);
194
- // const codeChallenge = await generateCodeChallenge(codeVerifier);
195
- const redirectUrlObj = new URL(`${window.location.origin}${window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'))}/${this.oauthReceiver}`);
196
- let grantType = '';
197
- let responseType = '';
198
- let newWindow;
199
-
200
- // clear previous error messages
201
- const errEls = [...authFlowDivEl.parentNode.querySelectorAll('.oauth-resp-display')];
202
- errEls.forEach((v) => { v.innerHTML = ''; });
203
-
204
- if (flowType === 'authorizationCode' || flowType === 'implicit') {
205
- const authUrlObj = new URL(authUrl);
206
- if (flowType === 'authorizationCode') {
207
- grantType = 'authorization_code';
208
- responseType = 'code';
209
- } else if (flowType === 'implicit') {
210
- responseType = 'token';
211
- }
212
- const authCodeParams = new URLSearchParams(authUrlObj.search);
213
- const selectedScopes = checkedScopeEls.map((v) => v.value).join(' ');
214
- if (selectedScopes) {
215
- authCodeParams.set('scope', selectedScopes);
216
- }
217
- authCodeParams.set('client_id', clientId);
218
- authCodeParams.set('redirect_uri', redirectUrlObj.toString());
219
- authCodeParams.set('response_type', responseType);
220
- authCodeParams.set('state', state);
221
- authCodeParams.set('nonce', nonce);
222
- if (pkceCheckboxEl && pkceCheckboxEl.checked) {
223
- authCodeParams.set('code_challenge', codeChallenge);
224
- authCodeParams.set('code_challenge_method', 'S256');
225
- }
226
- authCodeParams.set('show_dialog', true);
227
- authUrlObj.search = authCodeParams.toString();
228
- // If any older message-event-listener is active then fire a fake message to remove it (these are single time listeners)
229
- if (sessionStorage.getItem('winMessageEventActive') === 'true') {
230
- window.postMessage({ fake: true }, this);
231
- }
232
- setTimeout(() => {
233
- newWindow = window.open(authUrlObj.toString());
234
- if (!newWindow) {
235
- console.error(`RapiDoc: Unable to open ${authUrlObj.toString()} in a new window`);
236
- } else {
237
- sessionStorage.setItem('winMessageEventActive', 'true');
238
- window.addEventListener(
239
- 'message',
240
- (msgEvent) => onWindowMessageEvent.call(this, msgEvent, newWindow, tokenUrl, clientId, clientSecret, redirectUrlObj.toString(), grantType, sendClientSecretIn, securitySchemeId, authFlowDivEl),
241
- { once: true },
242
- );
243
- }
244
- }, 10);
245
- } else if (flowType === 'clientCredentials') {
246
- grantType = 'client_credentials';
247
- const selectedScopes = checkedScopeEls.map((v) => v.value).join(' ');
248
- fetchAccessToken.call(this, tokenUrl, clientId, clientSecret, redirectUrlObj.toString(), grantType, '', securitySchemeId, authFlowDivEl, sendClientSecretIn, selectedScopes);
249
- } else if (flowType === 'password') {
250
- grantType = 'password';
251
- const selectedScopes = checkedScopeEls.map((v) => v.value).join(' ');
252
- fetchAccessToken.call(this, tokenUrl, clientId, clientSecret, redirectUrlObj.toString(), grantType, '', securitySchemeId, authFlowDivEl, sendClientSecretIn, selectedScopes, username, password);
253
- }
254
- }
255
- /* eslint-enable no-console */
256
-
257
- /* eslint-disable indent */
258
-
259
- function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, authFlow, defaultScopes = [], receiveTokenIn = 'header', receiveTokenInOptions = undefined) {
260
- let { authorizationUrl, tokenUrl, refreshUrl } = authFlow;
261
- const pkceOnly = authFlow['x-pkce-only'] || false;
262
- const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0);
263
- // Calculcate base URL
264
- const url = new URL(this.selectedServer?.computedUrl);
265
- const baseUrl = url.origin;
266
-
267
- if (refreshUrl && !isUrlAbsolute(refreshUrl)) {
268
- refreshUrl = `${baseUrl}/${refreshUrl.replace(/^\//, '')}`;
269
- }
270
- if (tokenUrl && !isUrlAbsolute(tokenUrl)) {
271
- tokenUrl = `${baseUrl}/${tokenUrl.replace(/^\//, '')}`;
272
- }
273
- if (authorizationUrl && !isUrlAbsolute(authorizationUrl)) {
274
- authorizationUrl = `${baseUrl}/${authorizationUrl.replace(/^\//, '')}`;
275
- }
276
- let flowNameDisplay;
277
- if (flowName === 'authorizationCode') {
278
- flowNameDisplay = 'Authorization Code Flow';
279
- } else if (flowName === 'clientCredentials') {
280
- flowNameDisplay = 'Client Credentials Flow';
281
- } else if (flowName === 'implicit') {
282
- flowNameDisplay = 'Implicit Flow';
283
- } else if (flowName === 'password') {
284
- flowNameDisplay = 'Password Flow';
285
- } else {
286
- flowNameDisplay = flowName;
287
- }
288
- return html`
289
- <div class="oauth-flow ${flowName}" style="padding: 12px 0; margin-bottom:12px;">
290
- <div class="tiny-title upper" style="margin-bottom:8px;">${flowNameDisplay}</div>
291
- ${authorizationUrl
292
- ? html`<div style="margin-bottom:5px"><span style="width:75px; display: inline-block;">Auth URL</span> <span class="mono-font"> ${authorizationUrl} </span></div>`
293
- : ''
294
- }
295
- ${tokenUrl
296
- ? html`<div style="margin-bottom:5px"><span style="width:75px; display: inline-block;">Token URL</span> <span class="mono-font">${tokenUrl}</span></div>`
297
- : ''
298
- }
299
- ${refreshUrl
300
- ? html`<div style="margin-bottom:5px"><span style="width:75px; display: inline-block;">Refresh URL</span> <span class="mono-font">${refreshUrl}</span></div>`
301
- : ''
302
- }
303
- ${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'implicit' || flowName === 'password'
304
- ? html`
305
- ${authFlow.scopes
306
- ? html`
307
- <span> Scopes </span>
308
- <div class= "oauth-scopes" part="section-auth-scopes" style = "width:100%; display:flex; flex-direction:column; flex-wrap:wrap; margin:0 0 10px 24px">
309
- ${Object.entries(authFlow.scopes).map((scopeAndDescr, index) => html`
310
- <div class="m-checkbox" style="display:inline-flex; align-items:center">
311
- <input type="checkbox" part="checkbox checkbox-auth-scope" class="scope-checkbox" id="${securitySchemeId}${flowName}${index}" ?checked="${defaultScopes.includes(scopeAndDescr[0])}" value="${scopeAndDescr[0]}">
312
- <label for="${securitySchemeId}${flowName}${index}" style="margin-left:5px; cursor:pointer">
313
- <span class="mono-font">${scopeAndDescr[0]}</span>
314
- ${scopeAndDescr[0] !== scopeAndDescr[1] ? ` - ${scopeAndDescr[1] || ''}` : ''}
315
- </label>
316
- </div>
317
- `)}
318
- </div>
319
- `
320
- : ''
321
- }
322
- ${flowName === 'password'
323
- ? html`
324
- <div style="margin:5px 0">
325
- <input type="text" value = "" placeholder="username" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-user" part="textbox textbox-username" id="input-${securitySchemeId}-${flowName}-api-key-user">
326
- <input type="password" value = "" placeholder="password" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-password" style = "margin:0 5px;" part="textbox textbox-password" id="input-${securitySchemeId}-${flowName}-api-key-password">
327
- </div>`
328
- : ''
329
- }
330
- <div>
331
- ${flowName === 'authorizationCode'
332
- ? html`
333
- <div style="margin: 16px 0 4px">
334
- <input type="checkbox" part="checkbox checkbox-auth-scope" id="${securitySchemeId}-pkce" checked ?disabled=${pkceOnly}>
335
- <label for="${securitySchemeId}-pkce" style="margin:0 16px 0 4px; line-height:24px; cursor:pointer">
336
- Send Proof Key for Code Exchange (PKCE)
337
- </label>
338
- </div>
339
- `
340
- : ''
341
- }
342
- <input type="text" part="textbox textbox-auth-client-id" value = "${clientId || ''}" placeholder="client-id" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} oauth-client-id">
343
- ${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'password'
344
- ? html`
345
- <input
346
- id="${securitySchemeId}-${flowName}-oauth-client-secret"
347
- type="password" part="textbox textbox-auth-client-secret"
348
- value = "${clientSecret || ''}" placeholder="client-secret" spellcheck="false"
349
- class="oauth2 ${flowName} ${securitySchemeId}
350
- oauth-client-secret"
351
- style = "margin:0 5px;${pkceOnly ? 'display:none;' : ''}"
352
- >
353
- <select style="margin-right:5px;${pkceOnly ? 'display:none;' : ''}" class="${flowName} ${securitySchemeId} oauth-send-client-secret-in">
354
- ${(!receiveTokenInOptions || receiveTokenInOptions.includes('header')) ? html`<option value = 'header' .selected = ${receiveTokenIn === 'header'} > Authorization Header </option>` : ''}
355
- ${(!receiveTokenInOptions || receiveTokenInOptions.includes('request-body')) ? html` <option value = 'request-body' .selected = ${receiveTokenIn === 'request-body'}> Request Body </option>` : ''}
356
- </select>`
357
- : ''
358
- }
359
- ${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'implicit' || flowName === 'password'
360
- ? html`
361
- <button class="m-btn thin-border" part="btn btn-outline"
362
- @click="${(e) => { onInvokeOAuthFlow.call(this, securitySchemeId, flowName, authorizationUrl, tokenUrl, e); }}"
363
- > GET TOKEN </button>`
364
- : ''
365
- }
366
- </div>
367
- <div class="oauth-resp-display red-text small-font-size"></div>
368
- `
369
- : ''
370
- }
371
- </div>
372
- `;
373
- }
374
-
375
- function removeApiKey(securitySchemeId) {
376
- const securityObj = this.resolvedSpec.securitySchemes?.find((v) => (v.securitySchemeId === securitySchemeId));
377
- securityObj.user = '';
378
- securityObj.password = '';
379
- securityObj.value = '';
380
- securityObj.finalKeyValue = '';
381
- if (this.persistAuth === 'true') {
382
- const rapidocLs = getPersistedApiKeys.call(this);
383
- delete rapidocLs[securityObj.securitySchemeId];
384
- setPersistedApiKeys.call(this, rapidocLs);
385
- }
386
- this.requestUpdate();
387
- }
388
-
389
- export default function securitySchemeTemplate() {
390
- if (!this.resolvedSpec) { return ''; }
391
- const providedApiKeys = this.resolvedSpec.securitySchemes?.filter((v) => (v.finalKeyValue));
392
- if (!providedApiKeys) {
393
- return;
394
- }
395
- return html`
396
- <section id='auth' part="section-auth" style="text-align:left; direction:ltr; margin-top:24px; margin-bottom:24px;" class = 'observe-me ${'read focused'.includes(this.renderStyle) ? 'section-gap--read-mode' : 'section-gap '}'>
397
- <div class='sub-title regular-font'> AUTHENTICATION </div>
398
-
399
- <div class="small-font-size" style="display:flex; align-items: center; min-height:30px">
400
- ${providedApiKeys.length > 0
401
- ? html`
402
- <div class="blue-text"> ${providedApiKeys.length} API key applied </div>
403
- <div style="flex:1"></div>
404
- <button class="m-btn thin-border" part="btn btn-outline" @click=${() => { onClearAllApiKeys.call(this); }}>CLEAR ALL API KEYS</button>`
405
- : html`<div class="red-text">No API key applied</div>`
406
- }
407
- </div>
408
- ${this.resolvedSpec.securitySchemes && this.resolvedSpec.securitySchemes.length > 0
409
- ? html`
410
- <table role="presentation" id="auth-table" class='m-table padded-12' style="width:100%;">
411
- ${this.resolvedSpec.securitySchemes.map((v) => html`
412
- <tr id="security-scheme-${v.securitySchemeId}" class="${v.type.toLowerCase()}">
413
- <td style="max-width:500px; overflow-wrap: break-word;">
414
- <div style="line-height:28px; margin-bottom:5px;">
415
- <span style="font-weight:bold; font-size:var(--font-size-regular)">${v.typeDisplay}</span>
416
- ${v.finalKeyValue
417
- ? html`
418
- <span class='blue-text'> ${v.finalKeyValue ? 'Key Applied' : ''} </span>
419
- <button class="m-btn thin-border small" part="btn btn-outline" @click=${() => { removeApiKey.call(this, v.securitySchemeId); }}>REMOVE</button>
420
- `
421
- : ''
422
- }
423
- </div>
424
- ${v.description
425
- ? html`
426
- <div class="m-markdown">
427
- ${unsafeHTML(marked(v.description || ''))}
428
- </div>`
429
- : ''
430
- }
431
-
432
- ${(v.type.toLowerCase() === 'apikey') || (v.type.toLowerCase() === 'http' && v.scheme.toLowerCase() === 'bearer')
433
- ? html`
434
- <div style="margin-bottom:5px">
435
- ${v.type.toLowerCase() === 'apikey'
436
- ? html`Send <code>${v.name}</code> in <code>${v.in}</code>`
437
- : html`Send <code>Authorization</code> in <code>header</code> containing the word <code>Bearer</code> followed by a space and a Token String.`
438
- }
439
- </div>
440
- <div style="max-height:28px;">
441
- ${v.in !== 'cookie'
442
- ? html`
443
- <input type = "text" value = "${v.value}" class="${v.type} ${v.securitySchemeId} api-key-input" placeholder = "api-token" spellcheck = "false" id = "${v.type}-${v.securitySchemeId}-api-key-input">
444
- <button class="m-btn thin-border" style = "margin-left:5px;"
445
- part = "btn btn-outline"
446
- @click="${(e) => { onApiKeyChange.call(this, v.securitySchemeId, e); }}">
447
- ${v.finalKeyValue ? 'UPDATE' : 'SET'}
448
- </button>`
449
- : html`<span class="gray-text" style="font-size::var(--font-size-small)"> cookies cannot be set from here</span>`
450
- }
451
- </div>`
452
- : ''
453
- }
454
- ${v.type.toLowerCase() === 'http' && v.scheme.toLowerCase() === 'basic'
455
- ? html`
456
- <div style="margin-bottom:5px">
457
- Send <code>Authorization</code> in <code>header</code> containing the word <code>Basic</code> followed by a space and a base64 encoded string of <code>username:password</code>.
458
- </div>
459
- <div>
460
- <input type="text" value = "${v.user}" placeholder="username" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-user" style="width:100px" id = "input-${v.type}-${v.securitySchemeId}-api-key-user">
461
- <input type="password" value = "${v.password}" placeholder="password" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-password" style = "width:100px; margin:0 5px;" id = "input-${v.type}-${v.securitySchemeId}-api-key-password">
462
- <button class="m-btn thin-border"
463
- @click="${(e) => { onApiKeyChange.call(this, v.securitySchemeId, e); }}"
464
- part = "btn btn-outline"
465
- >
466
- ${v.finalKeyValue ? 'UPDATE' : 'SET'}
467
- </button>
468
- </div>`
469
- : ''
470
- }
471
- </td>
472
- </tr>
473
- ${v.type.toLowerCase() === 'oauth2'
474
- ? html`
475
- <tr>
476
- <td style="border:none; padding-left:48px">
477
- ${Object.keys(v.flows).map((f) => oAuthFlowTemplate
478
- .call(
479
- this,
480
- f,
481
- (v.flows[f]['x-client-id'] || v['x-client-id'] || ''),
482
- (v.flows[f]['x-client-secret'] || v['x-client-secret'] || ''),
483
- v.securitySchemeId,
484
- v.flows[f],
485
- (v.flows[f]['x-default-scopes'] || v['x-default-scopes']),
486
- (v.flows[f]['x-receive-token-in'] || v['x-receive-token-in']),
487
- (v.flows[f]['x-receive-token-in-options'] || v['x-receive-token-in-options']),
488
- ))}
489
- </td>
490
- </tr>
491
- `
492
- : ''
493
- }
494
- `)}
495
- </table>`
496
- : ''
497
- }
498
- <slot name="auth"></slot>
499
- </section>
500
- `;
501
- }
502
-
503
- export function pathSecurityTemplate(pathSecurity) {
504
- if (this.resolvedSpec.securitySchemes && pathSecurity) {
505
- const orSecurityKeys1 = [];
506
- if (Array.isArray(pathSecurity)) {
507
- if (pathSecurity.length === 0) {
508
- return '';
509
- }
510
- } else {
511
- return '';
512
- }
513
- pathSecurity.forEach((pSecurity) => {
514
- const andSecurityKeys1 = [];
515
- const andKeyTypes = [];
516
- if (Object.keys(pSecurity).length === 0) {
517
- orSecurityKeys1.push({
518
- securityTypes: 'None',
519
- securityDefs: [],
520
- });
521
- } else {
522
- Object.keys(pSecurity).forEach((pathSecurityKey) => {
523
- let pathScopes = '';
524
- const s = this.resolvedSpec.securitySchemes.find((ss) => ss.securitySchemeId === pathSecurityKey);
525
- if (pSecurity[pathSecurityKey] && Array.isArray(pSecurity[pathSecurityKey])) {
526
- pathScopes = pSecurity[pathSecurityKey].join(', ');
527
- }
528
- if (s) {
529
- andKeyTypes.push(s.typeDisplay);
530
- andSecurityKeys1.push({ ...s, ...({ scopes: pathScopes }) });
531
- }
532
- });
533
- orSecurityKeys1.push({
534
- securityTypes: andKeyTypes.length > 1 ? `${andKeyTypes[0]} + ${andKeyTypes.length - 1} more` : andKeyTypes[0],
535
- securityDefs: andSecurityKeys1,
536
- });
537
- }
538
- });
539
- return html`<div style="position:absolute; top:3px; right:2px; font-size:var(--font-size-small); line-height: 1.5;">
540
- <div style="position:relative; display:flex; min-width:350px; max-width:700px; justify-content: flex-end;">
541
- <svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" style="stroke:var(--fg3)"> <rect x="5" y="11" width="14" height="10" rx="2" /> <circle cx="12" cy="16" r="1" /> <path d="M8 11v-4a4 4 0 0 1 8 0v4" /></svg>
542
- ${orSecurityKeys1.map((orSecurityItem1, i) => html`
543
- ${orSecurityItem1.securityTypes
544
- ? html`
545
- ${i !== 0 ? html`<div style="padding:3px 4px;"> OR </div>` : ''}
546
- <div class="tooltip">
547
- <div style = "padding:2px 4px; white-space:nowrap; text-overflow:ellipsis;max-width:150px; overflow:hidden;">
548
- ${this.updateRoute === 'true' && this.allowAuthentication === 'true'
549
- ? html`<a part="anchor anchor-operation-security" href="#auth"> ${orSecurityItem1.securityTypes} </a>`
550
- : html`${orSecurityItem1.securityTypes}`
551
- }
552
- </div>
553
- <div class="tooltip-text" style="position:absolute; color: var(--fg); top:26px; right:0; border:1px solid var(--border-color);padding:2px 4px; display:block;">
554
- ${orSecurityItem1.securityDefs.length > 1 ? html`<div>Requires <b>all</b> of the following </div>` : ''}
555
- <div style="padding-left: 8px">
556
- ${orSecurityItem1.securityDefs.map((andSecurityItem, j) => {
557
- const scopeHtml = html`${andSecurityItem.scopes !== ''
558
- ? html`
559
- <div>
560
- <b>Required scopes:</b>
561
- <br/>
562
- <div style="margin-left:8px">
563
- ${andSecurityItem.scopes.split(',').map((scope, cnt) => html`${cnt === 0 ? '' : '┃'}<span>${scope}</span>`)}
564
- </div>
565
- </div>`
566
- : ''
567
- }`;
568
-
569
- return html`
570
- ${andSecurityItem.type === 'oauth2'
571
- ? html`
572
- <div>
573
- ${orSecurityItem1.securityDefs.length > 1
574
- ? html`<b>${j + 1}.</b> &nbsp;`
575
- : 'Needs'
576
- }
577
- OAuth Token <span style="font-family:var(--font-mono); color:var(--primary-color);">${andSecurityItem.securitySchemeId}</span> in <b>Authorization header</b>
578
- ${scopeHtml}
579
- </div>`
580
- : andSecurityItem.type === 'http'
581
- ? html`
582
- <div>
583
- ${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> &nbsp;` : html`Requires`}
584
- ${andSecurityItem.scheme === 'basic' ? 'Base 64 encoded username:password' : 'Bearer Token'} in <b>Authorization header</b>
585
- ${scopeHtml}
586
- </div>`
587
- : html`
588
- <div>
589
- ${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> &nbsp;` : html`Requires`}
590
- Token in <b>${andSecurityItem.name} ${andSecurityItem.in}</b>
591
- ${scopeHtml}
592
- </div>`
593
- }`;
594
- })}
595
- </div>
596
- </div>
597
- </div>
598
- `
599
- : ''
600
- }
601
- `)
602
- }
603
- </div>
604
- </div>
605
- `;
606
- }
607
- return '';
608
- }
609
-
610
- /* eslint-enable indent */