Files
2026-06-12 13:43:37 +02:00

134 lines
4.1 KiB
Go

// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package docui
import (
"bytes"
"fmt"
"net/http"
"path"
"text/template"
)
// UseSwaggerUIOAuth2Callback creates a middleware that serves a callback URL to complete
// a OAuth2 token handshake.
func UseSwaggerUIOAuth2Callback(opts ...Option) func(next http.Handler) http.Handler {
pth, assets := swaggeruiOAuth2Setup(opts)
return func(next http.Handler) http.Handler {
return serveUI(pth, assets, next)
}
}
// SwaggerUIOAuth2Callback creates a [http.Handler] that serves a callback URL to complete
// a OAuth2 token handshake.
func SwaggerUIOAuth2Callback(next http.Handler, opts ...Option) http.Handler {
pth, assets := swaggeruiOAuth2Setup(opts)
return serveUI(pth, assets, next)
}
func swaggeruiOAuth2Setup(opts []Option) (pth string, assets []byte) {
o := optionsWithDefaults(opts,
// defaults for SwaggerUI OAuth2 callback endpoint
WithUITemplate(swaggerOAuth2Template),
WithUIAssetsURL(swaggerLatest),
)
o.applySwaggerUIDefaults()
if o.OAuth2CallbackURL == "" {
o.OAuth2CallbackURL = path.Join(o.BasePath, o.Path, "oauth2-callback")
}
pth = o.OAuth2CallbackURL
tmpl := template.Must(template.New("swaggeroauth2").Parse(o.Template))
buf := bytes.NewBuffer(nil)
if err := tmpl.Execute(buf, o); err != nil {
panic(fmt.Errorf("cannot execute template: %w", err))
}
return pth, buf.Bytes()
}
const swaggerOAuth2Template = `
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ .Title }}</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>
`