From 18ff51a025c16e0784fd83e05cbfd86d63073c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=20V=C3=AEjdea?= Date: Sun, 14 Oct 2018 20:23:53 +0300 Subject: [PATCH] Improve handling of spec request url --- docs/custom_ui.rst | 2 +- docs/settings.rst | 3 +- .../static/drf-yasg/swagger-ui-init.js | 63 +++++++++++++------ 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/docs/custom_ui.rst b/docs/custom_ui.rst index 6603506..31da547 100644 --- a/docs/custom_ui.rst +++ b/docs/custom_ui.rst @@ -4,7 +4,7 @@ Customizing the web UI The web UI can be customized using the settings available in :ref:`swagger-ui-settings` and :ref:`redoc-ui-settings`. -You can also extend one of the drf-yasg/swagger-ui.html_ or drf-yasg/redoc.html_ templates that are used for +You can also extend one of the `drf-yasg/swagger-ui.html`_ or `drf-yasg/redoc.html`_ templates that are used for rendering. See the template source code (linked above) for a complete list of customizable blocks. .. _drf-yasg/swagger-ui.html: https://github.com/axnsan12/drf-yasg/blob/master/src/drf_yasg/templates/drf-yasg/swagger-ui.html diff --git a/docs/settings.rst b/docs/settings.rst index 9a27e15..47338d9 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -226,7 +226,8 @@ PERSIST_AUTH ------------ Persist swagger-ui authorization data to local storage. |br| -**WARNING:** this may be a security risk as the data is stored unencrypted +**WARNING:** This may be a security risk as the credentials are stored unencrypted and can be accessed +by all javascript code running on the same domain. **Default**: :python:`'False` |br| *Maps to parameter*: - diff --git a/src/drf_yasg/static/drf-yasg/swagger-ui-init.js b/src/drf_yasg/static/drf-yasg/swagger-ui-init.js index b3bfc78..fc1941f 100644 --- a/src/drf_yasg/static/drf-yasg/swagger-ui-init.js +++ b/src/drf_yasg/static/drf-yasg/swagger-ui-init.js @@ -126,16 +126,36 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) { } }; - var specRequestsInFlight = []; + var specRequestsInFlight = {}; var oldRequestInterceptor = swaggerUiConfig.requestInterceptor; swaggerUiConfig.requestInterceptor = function (request) { var headers = request.headers || {}; - if (refetchWithAuth && request.loadSpec) { - request.url = applyAuth(savedAuth, request.url, headers) || request.url; + if (request.loadSpec) { + var newUrl = request.url; - // need to manually remember requests for spec urls because - // responseInterceptor has no reference to the request... - specRequestsInFlight.push(request.url); + if (refetchWithAuth) { + newUrl = applyAuth(savedAuth, newUrl, headers) || newUrl; + } + + if (newUrl !== request.url) { + request.url = newUrl; + + if (window.ui) { + // this visually updates the spec url before the request is done, i.e. while loading + window.ui.specActions.updateUrl(request.url); + } else { + // setTimeout is needed here because the request interceptor can be called *during* + // window.ui initialization (by the SwaggerUIBundle constructor) + setTimeout(function () { + window.ui.specActions.updateUrl(request.url); + }); + } + + // need to manually remember requests for spec urls because + // responseInterceptor has no reference to the request... + var absUrl = new URL(request.url, currentPath); + specRequestsInFlight[absUrl.href] = request.url; + } } if (oldRequestInterceptor) { @@ -146,17 +166,20 @@ function initSwaggerUiConfig(swaggerSettings, oauth2Settings) { var oldResponseInterceptor = swaggerUiConfig.responseInterceptor; swaggerUiConfig.responseInterceptor = function (response) { - if (refetchWithAuth && specRequestsInFlight.indexOf(response.url) !== -1) { - // need setTimeout here because swagger-ui insists to call updateUrl - // with the initial request url after the response... + var absUrl = new URL(response.url, currentPath); + if (absUrl.href in specRequestsInFlight) { + var setToUrl = specRequestsInFlight[absUrl.href]; + delete specRequestsInFlight[absUrl.href]; if (response.ok) { + // need setTimeout here because swagger-ui insists to call updateUrl + // with the initial request url after the response... setTimeout(function () { - window.ui.specActions.updateUrl(response.url); + var currentUrl = new URL(window.ui.specSelectors.url(), currentPath); + if (currentUrl.href !== absUrl.href) { + window.ui.specActions.updateUrl(setToUrl); + } }); } - specRequestsInFlight = specRequestsInFlight.filter(function (val) { - return val !== response.url; - }); } if (oldResponseInterceptor) { @@ -172,13 +195,13 @@ function _usp(url, fn) { var usp = new URLSearchParams(url[1]); fn(usp); url[1] = usp.toString(); - return url.join('?'); + return url[1] ? url.join('?') : url[0]; } -function addQueryParam(url, key, value) { +function setQueryParam(url, key, value) { return _usp(url, function (usp) { usp.set(key, value); - }) + }); } function removeQueryParam(url, key) { @@ -238,7 +261,7 @@ function applyAuth(authorization, requestUrl, requestHeaders) { } if (_in === "query") { if (requestUrl) { - requestUrl = addQueryParam(requestUrl, paramName, key); + requestUrl = setQueryParam(requestUrl, paramName, key); } else { console.warn("WARNING: cannot apply apiKey query parameter via interceptor"); @@ -299,7 +322,9 @@ function hookAuthActions(sui, persistAuth, refetchWithAuth, refetchOnLogout) { if (refetchWithAuth) { var url = sui.specSelectors.url(); url = applyAuth(savedAuth, url) || url; - sui.specActions.download(url); + sui.specActions.updateUrl(url); + sui.specActions.download(); + sui.authActions.showDefinitions(); // hide authorize dialog } if (persistAuth) { localStorage.setItem("drf-yasg-auth", JSON.stringify(savedAuth.toJSON())); @@ -322,7 +347,9 @@ function hookAuthActions(sui, persistAuth, refetchWithAuth, refetchOnLogout) { if (refetchWithAuth) { var url = sui.specSelectors.url(); url = deauthUrl(loggedOut, url) || url; + sui.specActions.updateUrl(url); sui.specActions.download(url); + sui.authActions.showDefinitions(); // hide authorize dialog } if (persistAuth) { localStorage.setItem("drf-yasg-auth", JSON.stringify(savedAuth.toJSON()));