package openplatform import ( _ "embed" "net/http" "strconv" "strings" ) const ( OpenAPISpecPath = "/open-api/openapi.yaml" SwaggerUIPath = "/open-api/swagger/" SimpleDocsPath = "/open-api/docs/" swaggerInitJSPath = "/open-api/swagger-init.js" ) //go:embed assets/openapi.yaml var openAPISpec []byte //go:embed assets/swagger.html var swaggerHTML []byte //go:embed assets/swagger-init.js var swaggerInitJS []byte //go:embed assets/docs.html var simpleDocsHTML []byte // WithDocs exposes version-matched API documentation without requiring a // production database connection or an authenticated platform session. func WithDocs(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/open-api": redirectDocs(w, r, SimpleDocsPath) case "/open-api/swagger": redirectDocs(w, r, SwaggerUIPath) case "/open-api/docs": redirectDocs(w, r, SimpleDocsPath) case OpenAPISpecPath: serveDocsAsset(w, r, "application/yaml; charset=utf-8", openAPISpec, "") case SwaggerUIPath: serveDocsAsset(w, r, "text/html; charset=utf-8", swaggerHTML, "default-src 'none'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src 'self'; font-src https://cdn.jsdelivr.net; base-uri 'none'; frame-ancestors 'none'; form-action 'none'") case swaggerInitJSPath: serveDocsAsset(w, r, "application/javascript; charset=utf-8", swaggerInitJS, "") case SimpleDocsPath: serveDocsAsset(w, r, "text/html; charset=utf-8", simpleDocsHTML, "default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'") default: next.ServeHTTP(w, r) } }) } func redirectDocs(w http.ResponseWriter, r *http.Request, target string) { if r.Method != http.MethodGet && r.Method != http.MethodHead { w.Header().Set("Allow", "GET, HEAD") http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } http.Redirect(w, r, target, http.StatusPermanentRedirect) } func serveDocsAsset(w http.ResponseWriter, r *http.Request, contentType string, body []byte, csp string) { if r.Method != http.MethodGet && r.Method != http.MethodHead { w.Header().Set("Allow", "GET, HEAD") http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } w.Header().Set("Content-Type", contentType) w.Header().Set("Cache-Control", "no-store") w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Referrer-Policy", "no-referrer") if strings.TrimSpace(csp) != "" { w.Header().Set("Content-Security-Policy", csp) } w.Header().Set("Content-Length", strconv.Itoa(len(body))) w.WriteHeader(http.StatusOK) if r.Method == http.MethodGet { _, _ = w.Write(body) } }