diff --git a/backend/auth/handler.go b/backend/auth/handler.go index c35a0a56d..55b171bef 100644 --- a/backend/auth/handler.go +++ b/backend/auth/handler.go @@ -18,6 +18,8 @@ package auth import ( "context" + "crypto/rand" + "crypto/sha256" "encoding/base64" "encoding/json" "errors" @@ -85,6 +87,8 @@ func (ah *AuthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) { } } + logger.V(2).Info("AuthorizeRequest prepared", "authReq", authReq, "params", params) + if authReq.RedirectURL == "" || authReq.SessionID == "" { logger.Error(errors.New("missing required parameters"), "failed to authorize") ah.respondWithError(w, authReq.ClientType, "missing redirect_url or session_id", http.StatusBadRequest) @@ -94,20 +98,37 @@ func (ah *AuthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) { scopes := []string{"openid", "profile", "email", "offline_access", "groups"} dataCode, err := json.Marshal(authReq) if err != nil { - logger.Info("failed to marshal auth code", "error", err) + logger.Error(err, "failed to marshal auth code") ah.respondWithError(w, authReq.ClientType, err.Error(), http.StatusInternalServerError) return } provider, err := ah.oidc.GetOIDCProvider(r.Context()) if err != nil { - logger.Info("failed to get OIDC provider", "error", err) + logger.Error(err, "failed to get OIDC provider") ah.respondWithError(w, authReq.ClientType, err.Error(), http.StatusInternalServerError) return } encoded := base64.URLEncoding.EncodeToString(dataCode) - authURL := provider.OIDCProviderConfig(scopes).AuthCodeURL(encoded) + + verifier, challenge, err := generatePKCE() + if err != nil { + logger.Error(err, "failed to generate PKCE") + ah.respondWithError(w, authReq.ClientType, "failed to generate PKCE", http.StatusInternalServerError) + return + } + if err := ah.sessionStore.SavePKCEVerifier(authReq.SessionID, verifier); err != nil { + logger.Error(err, "failed to store PKCE verifier") + ah.respondWithError(w, authReq.ClientType, "failed to store PKCE verifier", http.StatusInternalServerError) + return + } + + opts := []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("code_challenge", challenge), + oauth2.SetAuthURLParam("code_challenge_method", "S256"), + } + authURL := provider.OIDCProviderConfig(scopes).AuthCodeURL(encoded, opts...) http.Redirect(w, r, authURL, http.StatusFound) } @@ -153,10 +174,11 @@ func (ah *AuthHandler) HandleCallback(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } + logger.V(2).Info("HandleCallback state unmarshaled", "authCode", authCode) provider, err := ah.oidc.GetOIDCProvider(r.Context()) if err != nil { - logger.Info("failed to get OIDC provider", "error", err) + logger.Error(err, "failed to get OIDC provider") ah.respondWithError(w, authCode.ClientType, err.Error(), http.StatusInternalServerError) return } @@ -172,7 +194,16 @@ func (ah *AuthHandler) HandleCallback(w http.ResponseWriter, r *http.Request) { ctx = context.WithValue(ctx, oauth2.HTTPClient, client) } - token, err := provider.OIDCProviderConfig(nil).Exchange(ctx, code) + verifier, err := ah.sessionStore.LoadAndDeletePKCEVerifier(authCode.SessionID) + if err != nil || verifier == "" { + logger.Error(err, "PKCE verifier not found for session; cannot exchange code", "sessionID", authCode.SessionID) + msg := "PKCE verifier not found. If you run multiple backend instances, use a shared session store (e.g. Redis) so the instance handling the callback can read the verifier stored at authorize time." + ah.respondWithError(w, authCode.ClientType, msg, http.StatusBadRequest) + return + } + + exchangeOpts := []oauth2.AuthCodeOption{oauth2.VerifierOption(verifier)} + token, err := provider.OIDCProviderConfig(nil).Exchange(ctx, code, exchangeOpts...) if err != nil { logger.Error(err, "failed to exchange token") http.Error(w, "internal error", http.StatusInternalServerError) @@ -204,6 +235,7 @@ func (ah *AuthHandler) HandleCallback(w http.ResponseWriter, r *http.Request) { sessionState.SessionID, sessionState.ClusterID, sessionState.RedirectURL, + sessionState.Token.Groups, 24*time.Hour, // 24 hours expiration ) if err != nil { @@ -326,3 +358,14 @@ func (ah *AuthHandler) unwrapJWT(p string) ([]byte, error) { } return payload, nil } + +func generatePKCE() (string, string, error) { + data := make([]byte, 32) + if _, err := rand.Read(data); err != nil { + return "", "", err + } + verifier := base64.RawURLEncoding.EncodeToString(data) + hash := sha256.Sum256([]byte(verifier)) + challenge := base64.RawURLEncoding.EncodeToString(hash[:]) + return verifier, challenge, nil +} diff --git a/backend/auth/jwt.go b/backend/auth/jwt.go index 0dab65183..473956bff 100644 --- a/backend/auth/jwt.go +++ b/backend/auth/jwt.go @@ -32,11 +32,12 @@ type JWTService struct { } type Claims struct { - Subject string `json:"sub"` - Issuer string `json:"iss"` - SessionID string `json:"sid"` - ClusterID string `json:"cid"` - RedirectURL string `json:"red,omitempty"` + Subject string `json:"sub"` + Issuer string `json:"iss"` + SessionID string `json:"sid"` + ClusterID string `json:"cid"` + Groups []string `json:"groups,omitempty"` + RedirectURL string `json:"red,omitempty"` jwt.RegisteredClaims } @@ -53,13 +54,14 @@ func NewJWTService(issuer string) (*JWTService, error) { }, nil } -func (js *JWTService) GenerateToken(subject, oidcIssuer, sessionID, clusterID, redirectURL string, expiration time.Duration) (string, error) { +func (js *JWTService) GenerateToken(subject, oidcIssuer, sessionID, clusterID, redirectURL string, groups []string, expiration time.Duration) (string, error) { now := time.Now() claims := &Claims{ Subject: subject, Issuer: oidcIssuer, SessionID: sessionID, ClusterID: clusterID, + Groups: groups, RedirectURL: redirectURL, RegisteredClaims: jwt.RegisteredClaims{ Subject: subject, diff --git a/backend/auth/middleware.go b/backend/auth/middleware.go index 32c9b088f..920cdf02f 100644 --- a/backend/auth/middleware.go +++ b/backend/auth/middleware.go @@ -19,6 +19,7 @@ package auth import ( "context" "encoding/json" + "fmt" "net/http" "strings" "time" @@ -111,6 +112,7 @@ func (am *AuthMiddleware) authenticate(next http.Handler) http.Handler { Token: session.TokenInfo{ Subject: claims.Subject, Issuer: claims.Issuer, + Groups: claims.Groups, }, SessionID: claims.SessionID, ClusterID: claims.ClusterID, @@ -219,7 +221,8 @@ func (am *AuthMiddleware) authorizeK8S(next http.Handler) http.Handler { if err != nil { logger.V(2).Info("Kubernetes RBAC authorization failed", "error", err) statusCode, code, details := mapErrorToCode(err) - writeErrorResponse(w, statusCode, code, "Cluster authorization failed. Missing required permissions in the cluster to access bindings.", details) + hint := fmt.Sprintf("%s Start the backend with --oidc-allowed-users=%s or --oidc-allowed-groups= (user must be in one of the allowed groups).", details, authCtx.SessionState.Token.Subject) + writeErrorResponse(w, statusCode, code, "Cluster authorization failed. Missing required permissions in the cluster to access bindings.", hint) return } diff --git a/backend/auth/types.go b/backend/auth/types.go index 7bb93b566..70fc19a21 100644 --- a/backend/auth/types.go +++ b/backend/auth/types.go @@ -121,11 +121,14 @@ func NewOIDCServiceProviderWithTLS( func (o *OIDCServiceProvider) OIDCProviderConfig(scopes []string) *oauth2.Config { config := &oauth2.Config{ - ClientID: o.clientID, - ClientSecret: o.clientSecret, - Endpoint: o.provider.Endpoint(), - RedirectURL: o.redirectURI, - Scopes: scopes, + ClientID: o.clientID, + Endpoint: o.provider.Endpoint(), + RedirectURL: o.redirectURI, + Scopes: scopes, + } + + if o.clientSecret != "" { + config.ClientSecret = o.clientSecret } return config @@ -134,3 +137,15 @@ func (o *OIDCServiceProvider) OIDCProviderConfig(scopes []string) *oauth2.Config func (o *OIDCServiceProvider) GetTLSConfig() *tls.Config { return o.tlsConfig } + +func (o *OIDCServiceProvider) ClientID() string { + return o.clientID +} + +func (o *OIDCServiceProvider) ClientSecret() string { + return o.clientSecret +} + +func (o *OIDCServiceProvider) IssuerURL() string { + return o.issuerURL +} diff --git a/backend/options/oidc.go b/backend/options/oidc.go index 311de002b..5797a2932 100644 --- a/backend/options/oidc.go +++ b/backend/options/oidc.go @@ -112,9 +112,6 @@ func (options *OIDC) Validate() error { if options.IssuerClientID == "" { return fmt.Errorf("OIDC issuer client ID cannot be empty") } - if options.IssuerClientSecret == "" && os.Getenv("OIDC_CLIENT_SECRET") == "" { - return fmt.Errorf("OIDC issuer client secret cannot be empty") - } if os.Getenv("OIDC_CLIENT_SECRET") != "" && options.Type == string(kubebindv1alpha2.OIDCProviderTypeEmbedded) { return fmt.Errorf("OIDC issuer client secret cannot be provided via environment variable when using embedded OIDC provider") } diff --git a/backend/server.go b/backend/server.go index 0773b5f2b..f8faecb33 100644 --- a/backend/server.go +++ b/backend/server.go @@ -270,22 +270,33 @@ func NewServer(ctx context.Context, c *Config) (*Server, error) { func (s *Server) initializeOIDCProvider(ctx context.Context, callback string) (*auth.OIDCServiceProvider, error) { logger := klog.FromContext(ctx) logger.Info("Initializing OIDC Service Provider", "issuerURL", s.Config.Options.OIDC.IssuerURL) - if s.Config.Options.OIDC.TLSConfig != nil { + + clientID := s.Config.Options.OIDC.IssuerClientID + clientSecret := s.Config.Options.OIDC.IssuerClientSecret + issuerURL := s.Config.Options.OIDC.IssuerURL + tlsConfig := s.Config.Options.OIDC.TLSConfig + + if clientSecret != "" { + logger.Info("WARNING: OIDC client secret is configured. For CLI applications, consider using PKCE.") + } + + if tlsConfig != nil { return auth.NewOIDCServiceProviderWithTLS( ctx, - s.Config.Options.OIDC.IssuerClientID, - s.Config.Options.OIDC.IssuerClientSecret, + clientID, + clientSecret, callback, - s.Config.Options.OIDC.IssuerURL, - s.Config.Options.OIDC.TLSConfig, + issuerURL, + tlsConfig, ) } + return auth.NewOIDCServiceProvider( ctx, - s.Config.Options.OIDC.IssuerClientID, - s.Config.Options.OIDC.IssuerClientSecret, + clientID, + clientSecret, callback, - s.Config.Options.OIDC.IssuerURL, + issuerURL, ) } diff --git a/backend/session/store.go b/backend/session/store.go index 0a36cd046..c70a8710f 100644 --- a/backend/session/store.go +++ b/backend/session/store.go @@ -17,26 +17,32 @@ limitations under the License. package session import ( + "errors" "fmt" "sync" ) var ErrSessionNotFound = fmt.Errorf("session not found") +var ErrPKCEVerifierNotFound = fmt.Errorf("pkce verifier not found") type Store interface { Save(state *State) error Load(sessionID string) (*State, error) Delete(sessionID string) error + SavePKCEVerifier(sessionID, verifier string) error + LoadAndDeletePKCEVerifier(sessionID string) (string, error) } type InMemoryStore struct { - lock sync.RWMutex - sessions map[string]*State + lock sync.RWMutex + sessions map[string]*State + pkceVerifiers map[string]string } func NewInMemoryStore() *InMemoryStore { return &InMemoryStore{ - sessions: make(map[string]*State), + sessions: make(map[string]*State), + pkceVerifiers: make(map[string]string), } } @@ -63,3 +69,27 @@ func (s *InMemoryStore) Delete(sessionID string) error { delete(s.sessions, sessionID) return nil } + +func (s *InMemoryStore) SavePKCEVerifier(sessionID, verifier string) error { + if sessionID == "" || verifier == "" { + return errors.New("sessionID and verifier cannot be empty") + } + s.lock.Lock() + defer s.lock.Unlock() + s.pkceVerifiers[sessionID] = verifier + return nil +} + +func (s *InMemoryStore) LoadAndDeletePKCEVerifier(sessionID string) (string, error) { + if sessionID == "" { + return "", ErrPKCEVerifierNotFound + } + s.lock.Lock() + defer s.lock.Unlock() + verifier, ok := s.pkceVerifiers[sessionID] + if !ok { + return "", ErrPKCEVerifierNotFound + } + delete(s.pkceVerifiers, sessionID) + return verifier, nil +} diff --git a/cli/pkg/kubectl/bind/plugin/authenticate_test.go b/cli/pkg/kubectl/bind/plugin/authenticate_test.go index ed8f33a7f..8c90cad2e 100644 --- a/cli/pkg/kubectl/bind/plugin/authenticate_test.go +++ b/cli/pkg/kubectl/bind/plugin/authenticate_test.go @@ -30,8 +30,8 @@ func TestValidateVersion(t *testing.T) { {"v0.0.0", "v0.0.0", false}, {"development version", "v0.0.0-master+$Format:%H$", false}, {"old", "v0.2.3", true}, - {"minimum", "v0.3.0", false}, - {"newer minor", "v0.3.5", false}, + {"minimum", "v0.6.0", false}, + {"newer minor", "v0.6.1", false}, {"newer major", "v1.2.5", false}, } for _, tt := range tests { diff --git a/web/dist/assets/index.4561ca6e.css b/web/dist/assets/index.acf75b09.css similarity index 96% rename from web/dist/assets/index.4561ca6e.css rename to web/dist/assets/index.acf75b09.css index 164494a24..efa15bfd5 100644 --- a/web/dist/assets/index.4561ca6e.css +++ b/web/dist/assets/index.acf75b09.css @@ -1,8 +1,10 @@ -#app[data-v-99283ff2] { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; +#app[data-v-0b535f4a] { + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", + "Cantarell", sans-serif; } -.header[data-v-99283ff2] { +.header[data-v-0b535f4a] { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-bottom: 1px solid rgba(255, 255, 255, 0.1); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); @@ -10,7 +12,7 @@ top: 0; z-index: 100; } -.header-content[data-v-99283ff2] { +.header-content[data-v-0b535f4a] { max-width: 1200px; margin: 0 auto; display: flex; @@ -18,30 +20,30 @@ align-items: center; padding: 1rem 2rem; } -.brand[data-v-99283ff2] { +.brand[data-v-0b535f4a] { display: flex; align-items: center; gap: 0.75rem; } -.logo[data-v-99283ff2] { +.logo[data-v-0b535f4a] { color: rgba(255, 255, 255, 0.9); display: flex; align-items: center; justify-content: center; } -.header h1[data-v-99283ff2] { +.header h1[data-v-0b535f4a] { margin: 0; color: white; font-size: 1.5rem; font-weight: 600; letter-spacing: -0.025em; } -.user-section[data-v-99283ff2] { +.user-section[data-v-0b535f4a] { display: flex; align-items: center; gap: 1.5rem; } -.user-info[data-v-99283ff2] { +.user-info[data-v-0b535f4a] { display: flex; align-items: center; gap: 0.5rem; @@ -49,26 +51,27 @@ font-size: 0.875rem; font-weight: 500; } -.status-indicator[data-v-99283ff2] { +.status-indicator[data-v-0b535f4a] { width: 8px; height: 8px; background: #10b981; border-radius: 50%; box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.3); - animation: pulse-99283ff2 2s infinite; + animation: pulse-0b535f4a 2s infinite; } -@keyframes pulse-99283ff2 { -0%, 100% { +@keyframes pulse-0b535f4a { +0%, + 100% { opacity: 1; } 50% { opacity: 0.5; } } -.welcome-text[data-v-99283ff2] { +.welcome-text[data-v-0b535f4a] { color: rgba(255, 255, 255, 0.8); } -.logout-btn[data-v-99283ff2] { +.logout-btn[data-v-0b535f4a] { display: flex; align-items: center; gap: 0.5rem; @@ -83,18 +86,18 @@ transition: all 0.2s ease; backdrop-filter: blur(10px); } -.logout-btn[data-v-99283ff2]:hover { +.logout-btn[data-v-0b535f4a]:hover { background: rgba(255, 255, 255, 0.2); color: white; border-color: rgba(255, 255, 255, 0.3); transform: translateY(-1px); } -.main[data-v-99283ff2] { +.main[data-v-0b535f4a] { min-height: calc(100vh - 80px); background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 0; } -.auth-placeholder[data-v-99283ff2] { +.auth-placeholder[data-v-0b535f4a] { display: flex; flex-direction: column; align-items: center; @@ -103,7 +106,7 @@ padding: 4rem 2rem; min-height: calc(100vh - 200px); } -.auth-placeholder h2[data-v-99283ff2] { +.auth-placeholder h2[data-v-0b535f4a] { color: #1f2937; margin-bottom: 1rem; font-size: 2rem; @@ -113,14 +116,14 @@ -webkit-text-fill-color: transparent; background-clip: text; } -.auth-placeholder p[data-v-99283ff2] { +.auth-placeholder p[data-v-0b535f4a] { color: #6b7280; margin-bottom: 2rem; font-size: 1.125rem; max-width: 500px; line-height: 1.6; } -.auth-btn[data-v-99283ff2] { +.auth-btn[data-v-0b535f4a] { display: inline-flex; align-items: center; gap: 0.5rem; @@ -135,12 +138,12 @@ transition: all 0.2s ease; box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); } -.auth-btn[data-v-99283ff2]:hover { +.auth-btn[data-v-0b535f4a]:hover { background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%); transform: translateY(-2px); box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4); } -.auth-error[data-v-99283ff2] { +.auth-error[data-v-0b535f4a] { display: flex; align-items: flex-start; gap: 1rem; @@ -153,18 +156,18 @@ text-align: left; box-shadow: 0 2px 8px rgba(239, 68, 68, 0.1); } -.error-icon[data-v-99283ff2] { +.error-icon[data-v-0b535f4a] { font-size: 1.5rem; line-height: 1; margin-top: 0.125rem; } -.error-content h3[data-v-99283ff2] { +.error-content h3[data-v-0b535f4a] { margin: 0 0 0.5rem 0; color: #dc2626; font-size: 1rem; font-weight: 600; } -.error-content p[data-v-99283ff2] { +.error-content p[data-v-0b535f4a] { margin: 0; color: #991b1b; font-size: 0.875rem; diff --git a/web/dist/assets/index.b10aa2d7.js b/web/dist/assets/index.b95c154b.js similarity index 97% rename from web/dist/assets/index.b10aa2d7.js rename to web/dist/assets/index.b95c154b.js index 5ef5df4d7..8ff308ecd 100644 --- a/web/dist/assets/index.b10aa2d7.js +++ b/web/dist/assets/index.b95c154b.js @@ -98,7 +98,7 @@ var __yieldStar = (value) => { }; var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it); var require_index_001 = __commonJS({ - "assets/index.b10aa2d7.js"(exports) { + "assets/index.b95c154b.js"(exports) { (function polyfill() { const relList = document.createElement("link").relList; if (relList && relList.supports && relList.supports("modulepreload")) { @@ -8480,7 +8480,12 @@ var require_index_001 = __commonJS({ kind === "object" && isFunction$1(thing.toString) && thing.toString() === "[object FormData]")); }; const isURLSearchParams = kindOfTest("URLSearchParams"); - const [isReadableStream, isRequest, isResponse, isHeaders] = ["ReadableStream", "Request", "Response", "Headers"].map(kindOfTest); + const [isReadableStream, isRequest, isResponse, isHeaders] = [ + "ReadableStream", + "Request", + "Response", + "Headers" + ].map(kindOfTest); const trim = (str) => str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); function forEach(obj, fn, { allOwnKeys = false } = {}) { if (obj === null || typeof obj === "undefined") { @@ -8534,6 +8539,9 @@ var require_index_001 = __commonJS({ const { caseless, skipUndefined } = isContextDefined(this) && this || {}; const result = {}; const assignValue = (val, key) => { + if (key === "__proto__" || key === "constructor" || key === "prototype") { + return; + } const targetKey = caseless && findKey(result, key) || key; if (isPlainObject(result[targetKey]) && isPlainObject(val)) { result[targetKey] = merge(result[targetKey], val); @@ -8551,13 +8559,27 @@ var require_index_001 = __commonJS({ return result; } const extend = (a, b, thisArg, { allOwnKeys } = {}) => { - forEach(b, (val, key) => { - if (thisArg && isFunction$1(val)) { - a[key] = bind(val, thisArg); - } else { - a[key] = val; - } - }, { allOwnKeys }); + forEach( + b, + (val, key) => { + if (thisArg && isFunction$1(val)) { + Object.defineProperty(a, key, { + value: bind(val, thisArg), + writable: true, + enumerable: true, + configurable: true + }); + } else { + Object.defineProperty(a, key, { + value: val, + writable: true, + enumerable: true, + configurable: true + }); + } + }, + { allOwnKeys } + ); return a; }; const stripBOM = (content) => { @@ -8566,9 +8588,17 @@ var require_index_001 = __commonJS({ } return content; }; - const inherits = (constructor, superConstructor, props, descriptors2) => { - constructor.prototype = Object.create(superConstructor.prototype, descriptors2); - constructor.prototype.constructor = constructor; + const inherits = (constructor, superConstructor, props, descriptors) => { + constructor.prototype = Object.create( + superConstructor.prototype, + descriptors + ); + Object.defineProperty(constructor.prototype, "constructor", { + value: constructor, + writable: true, + enumerable: false, + configurable: true + }); Object.defineProperty(constructor, "super", { value: superConstructor.prototype }); @@ -8643,19 +8673,16 @@ var require_index_001 = __commonJS({ }; const isHTMLForm = kindOfTest("HTMLFormElement"); const toCamelCase = (str) => { - return str.toLowerCase().replace( - /[-_\s]([a-z\d])(\w*)/g, - function replacer2(m, p1, p2) { - return p1.toUpperCase() + p2; - } - ); + return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, function replacer2(m, p1, p2) { + return p1.toUpperCase() + p2; + }); }; const hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype); const isRegExp = kindOfTest("RegExp"); const reduceDescriptors = (obj, reducer) => { - const descriptors2 = Object.getOwnPropertyDescriptors(obj); + const descriptors = Object.getOwnPropertyDescriptors(obj); const reducedDescriptors = {}; - forEach(descriptors2, (descriptor, name) => { + forEach(descriptors, (descriptor, name) => { let ret; if ((ret = reducer(descriptor, name, obj)) !== false) { reducedDescriptors[name] = ret || descriptor; @@ -8733,20 +8760,21 @@ var require_index_001 = __commonJS({ return setImmediate; } return postMessageSupported ? ((token, callbacks) => { - _global.addEventListener("message", ({ source, data }) => { - if (source === _global && data === token) { - callbacks.length && callbacks.shift()(); - } - }, false); + _global.addEventListener( + "message", + ({ source, data }) => { + if (source === _global && data === token) { + callbacks.length && callbacks.shift()(); + } + }, + false + ); return (cb) => { callbacks.push(cb); _global.postMessage(token, "*"); }; })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb); - })( - typeof setImmediate === "function", - isFunction$1(_global.postMessage) - ); + })(typeof setImmediate === "function", isFunction$1(_global.postMessage)); const asap = typeof queueMicrotask !== "undefined" ? queueMicrotask.bind(_global) : typeof process !== "undefined" && process.nextTick || _setImmediate; const isIterable = (thing) => thing != null && isFunction$1(thing[iterator]); const utils$1 = { @@ -8809,25 +8837,38 @@ var require_index_001 = __commonJS({ asap, isIterable }; - function AxiosError(message, code, config, request, response) { - Error.call(this); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } else { - this.stack = new Error().stack; + class AxiosError extends Error { + static from(error, code, config, request, response, customProps) { + const axiosError = new AxiosError(error.message, code || error.code, config, request, response); + axiosError.cause = error; + axiosError.name = error.name; + customProps && Object.assign(axiosError, customProps); + return axiosError; } - this.message = message; - this.name = "AxiosError"; - code && (this.code = code); - config && (this.config = config); - request && (this.request = request); - if (response) { - this.response = response; - this.status = response.status ? response.status : null; - } - } - utils$1.inherits(AxiosError, Error, { - toJSON: function toJSON() { + /** + * Create an Error with the specified message, config, error code, request and response. + * + * @param {string} message The error message. + * @param {string} [code] The error code (for example, 'ECONNABORTED'). + * @param {Object} [config] The config. + * @param {Object} [request] The request. + * @param {Object} [response] The response. + * + * @returns {Error} The created error. + */ + constructor(message, code, config, request, response) { + super(message); + this.name = "AxiosError"; + this.isAxiosError = true; + code && (this.code = code); + config && (this.config = config); + request && (this.request = request); + if (response) { + this.response = response; + this.status = response.status; + } + } + toJSON() { return { // Standard message: this.message, @@ -8846,45 +8887,20 @@ var require_index_001 = __commonJS({ status: this.status }; } - }); - const prototype$1 = AxiosError.prototype; - const descriptors = {}; - [ - "ERR_BAD_OPTION_VALUE", - "ERR_BAD_OPTION", - "ECONNABORTED", - "ETIMEDOUT", - "ERR_NETWORK", - "ERR_FR_TOO_MANY_REDIRECTS", - "ERR_DEPRECATED", - "ERR_BAD_RESPONSE", - "ERR_BAD_REQUEST", - "ERR_CANCELED", - "ERR_NOT_SUPPORT", - "ERR_INVALID_URL" - // eslint-disable-next-line func-names - ].forEach((code) => { - descriptors[code] = { value: code }; - }); - Object.defineProperties(AxiosError, descriptors); - Object.defineProperty(prototype$1, "isAxiosError", { value: true }); - AxiosError.from = (error, code, config, request, response, customProps) => { - const axiosError = Object.create(prototype$1); - utils$1.toFlatObject(error, axiosError, function filter(obj) { - return obj !== Error.prototype; - }, (prop) => { - return prop !== "isAxiosError"; - }); - const msg = error && error.message ? error.message : "Error"; - const errCode = code == null && error ? error.code : code; - AxiosError.call(axiosError, msg, errCode, config, request, response); - if (error && axiosError.cause == null) { - Object.defineProperty(axiosError, "cause", { value: error, configurable: true }); - } - axiosError.name = error && error.name || "Error"; - customProps && Object.assign(axiosError, customProps); - return axiosError; - }; + } + AxiosError.ERR_BAD_OPTION_VALUE = "ERR_BAD_OPTION_VALUE"; + AxiosError.ERR_BAD_OPTION = "ERR_BAD_OPTION"; + AxiosError.ECONNABORTED = "ECONNABORTED"; + AxiosError.ETIMEDOUT = "ETIMEDOUT"; + AxiosError.ERR_NETWORK = "ERR_NETWORK"; + AxiosError.ERR_FR_TOO_MANY_REDIRECTS = "ERR_FR_TOO_MANY_REDIRECTS"; + AxiosError.ERR_DEPRECATED = "ERR_DEPRECATED"; + AxiosError.ERR_BAD_RESPONSE = "ERR_BAD_RESPONSE"; + AxiosError.ERR_BAD_REQUEST = "ERR_BAD_REQUEST"; + AxiosError.ERR_CANCELED = "ERR_CANCELED"; + AxiosError.ERR_NOT_SUPPORT = "ERR_NOT_SUPPORT"; + AxiosError.ERR_INVALID_URL = "ERR_INVALID_URL"; + const AxiosError$1 = AxiosError; const httpAdapter = null; function isVisitable(thing) { return utils$1.isPlainObject(thing) || utils$1.isArray(thing); @@ -8937,7 +8953,7 @@ var require_index_001 = __commonJS({ return value.toString(); } if (!useBlob && utils$1.isBlob(value)) { - throw new AxiosError("Blob is not supported. Use a Buffer instead."); + throw new AxiosError$1("Blob is not supported. Use a Buffer instead."); } if (utils$1.isArrayBuffer(value) || utils$1.isTypedArray(value)) { return useBlob && typeof Blob === "function" ? new Blob([value]) : Buffer.from(value); @@ -9039,17 +9055,15 @@ var require_index_001 = __commonJS({ return url; } const _encode = options && options.encode || encode; - if (utils$1.isFunction(options)) { - options = { - serialize: options - }; - } - const serializeFn = options && options.serialize; + const _options = utils$1.isFunction(options) ? { + serialize: options + } : options; + const serializeFn = _options && _options.serialize; let serializedParams; if (serializeFn) { - serializedParams = serializeFn(params, options); + serializedParams = serializeFn(params, _options); } else { - serializedParams = utils$1.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams(params, options).toString(_encode); + serializedParams = utils$1.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams(params, _options).toString(_encode); } if (serializedParams) { const hashmarkIndex = url.indexOf("#"); @@ -9069,6 +9083,7 @@ var require_index_001 = __commonJS({ * * @param {Function} fulfilled The function to handle `then` for a `Promise` * @param {Function} rejected The function to handle `reject` for a `Promise` + * @param {Object} options The options for the interceptor, synchronous and runWhen * * @return {Number} An ID used to remove interceptor later */ @@ -9086,7 +9101,7 @@ var require_index_001 = __commonJS({ * * @param {Number} id The ID that was returned by `use` * - * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise + * @returns {void} */ eject(id) { if (this.handlers[id]) { @@ -9125,7 +9140,8 @@ var require_index_001 = __commonJS({ const transitionalDefaults = { silentJSONParsing: true, forcedJSONParsing: true, - clarifyTimeoutError: false + clarifyTimeoutError: false, + legacyInterceptorReqResOrdering: true }; const URLSearchParams$1 = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams; const FormData$1 = typeof FormData !== "undefined" ? FormData : null; @@ -9290,7 +9306,7 @@ var require_index_001 = __commonJS({ } catch (e) { if (strictJSONParsing) { if (e.name === "SyntaxError") { - throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response); + throw AxiosError$1.from(e, AxiosError$1.ERR_BAD_RESPONSE, this, null, this.response); } throw e; } @@ -9610,21 +9626,31 @@ var require_index_001 = __commonJS({ function isCancel(value) { return !!(value && value.__CANCEL__); } - function CanceledError(message, config, request) { - AxiosError.call(this, message == null ? "canceled" : message, AxiosError.ERR_CANCELED, config, request); - this.name = "CanceledError"; + class CanceledError extends AxiosError$1 { + /** + * A `CanceledError` is an object that is thrown when an operation is canceled. + * + * @param {string=} message The message. + * @param {Object=} config The config. + * @param {Object=} request The request. + * + * @returns {CanceledError} The created error. + */ + constructor(message, config, request) { + super(message == null ? "canceled" : message, AxiosError$1.ERR_CANCELED, config, request); + this.name = "CanceledError"; + this.__CANCEL__ = true; + } } - utils$1.inherits(CanceledError, AxiosError, { - __CANCEL__: true - }); + const CanceledError$1 = CanceledError; function settle(resolve2, reject, response) { const validateStatus = response.config.validateStatus; if (!response.status || !validateStatus || validateStatus(response.status)) { resolve2(response); } else { - reject(new AxiosError( + reject(new AxiosError$1( "Request failed with status code " + response.status, - [AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], + [AxiosError$1.ERR_BAD_REQUEST, AxiosError$1.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], response.config, response.request, response @@ -9743,20 +9769,35 @@ var require_index_001 = __commonJS({ const cookies = platform.hasStandardBrowserEnv ? ( // Standard browser envs support document.cookie { - write(name, value, expires, path, domain, secure) { - const cookie = [name + "=" + encodeURIComponent(value)]; - utils$1.isNumber(expires) && cookie.push("expires=" + new Date(expires).toGMTString()); - utils$1.isString(path) && cookie.push("path=" + path); - utils$1.isString(domain) && cookie.push("domain=" + domain); - secure === true && cookie.push("secure"); + write(name, value, expires, path, domain, secure, sameSite) { + if (typeof document === "undefined") + return; + const cookie = [`${name}=${encodeURIComponent(value)}`]; + if (utils$1.isNumber(expires)) { + cookie.push(`expires=${new Date(expires).toUTCString()}`); + } + if (utils$1.isString(path)) { + cookie.push(`path=${path}`); + } + if (utils$1.isString(domain)) { + cookie.push(`domain=${domain}`); + } + if (secure === true) { + cookie.push("secure"); + } + if (utils$1.isString(sameSite)) { + cookie.push(`SameSite=${sameSite}`); + } document.cookie = cookie.join("; "); }, read(name) { - const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)")); - return match ? decodeURIComponent(match[3]) : null; + if (typeof document === "undefined") + return null; + const match = document.cookie.match(new RegExp("(?:^|; )" + name + "=([^;]*)")); + return match ? decodeURIComponent(match[1]) : null; }, remove(name) { - this.write(name, "", Date.now() - 864e5); + this.write(name, "", Date.now() - 864e5, "/"); } } ) : ( @@ -9772,6 +9813,9 @@ var require_index_001 = __commonJS({ } ); function isAbsoluteURL(url) { + if (typeof url !== "string") { + return false; + } return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); } function combineURLs(baseURL, relativeURL) { @@ -9855,11 +9899,16 @@ var require_index_001 = __commonJS({ validateStatus: mergeDirectKeys, headers: (a, b, prop) => mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true) }; - utils$1.forEach(Object.keys(__spreadValues(__spreadValues({}, config1), config2)), function computeConfigValue(prop) { - const merge2 = mergeMap[prop] || mergeDeepProperties; - const configValue = merge2(config1[prop], config2[prop], prop); - utils$1.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue); - }); + utils$1.forEach( + Object.keys(__spreadValues(__spreadValues({}, config1), config2)), + function computeConfigValue(prop) { + if (prop === "__proto__" || prop === "constructor" || prop === "prototype") + return; + const merge2 = utils$1.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties; + const configValue = merge2(config1[prop], config2[prop], prop); + utils$1.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue); + } + ); return config; } const resolveConfig = (config) => { @@ -9958,12 +10007,12 @@ var require_index_001 = __commonJS({ if (!request) { return; } - reject(new AxiosError("Request aborted", AxiosError.ECONNABORTED, config, request)); + reject(new AxiosError$1("Request aborted", AxiosError$1.ECONNABORTED, config, request)); request = null; }; request.onerror = function handleError2(event) { const msg = event && event.message ? event.message : "Network Error"; - const err = new AxiosError(msg, AxiosError.ERR_NETWORK, config, request); + const err = new AxiosError$1(msg, AxiosError$1.ERR_NETWORK, config, request); err.event = event || null; reject(err); request = null; @@ -9974,9 +10023,9 @@ var require_index_001 = __commonJS({ if (_config.timeoutErrorMessage) { timeoutErrorMessage = _config.timeoutErrorMessage; } - reject(new AxiosError( + reject(new AxiosError$1( timeoutErrorMessage, - transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, + transitional.clarifyTimeoutError ? AxiosError$1.ETIMEDOUT : AxiosError$1.ECONNABORTED, config, request )); @@ -10008,7 +10057,7 @@ var require_index_001 = __commonJS({ if (!request) { return; } - reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel); + reject(!cancel || cancel.type ? new CanceledError$1(null, config, request) : cancel); request.abort(); request = null; }; @@ -10019,7 +10068,7 @@ var require_index_001 = __commonJS({ } const protocol = parseProtocol(_config.url); if (protocol && platform.protocols.indexOf(protocol) === -1) { - reject(new AxiosError("Unsupported protocol " + protocol + ":", AxiosError.ERR_BAD_REQUEST, config)); + reject(new AxiosError$1("Unsupported protocol " + protocol + ":", AxiosError$1.ERR_BAD_REQUEST, config)); return; } request.send(requestData || null); @@ -10035,12 +10084,12 @@ var require_index_001 = __commonJS({ aborted = true; unsubscribe(); const err = reason instanceof Error ? reason : this.reason; - controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err)); + controller.abort(err instanceof AxiosError$1 ? err : new CanceledError$1(err instanceof Error ? err.message : err)); } }; let timer = timeout && setTimeout(() => { timer = null; - onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT)); + onabort(new AxiosError$1(`timeout of ${timeout}ms exceeded`, AxiosError$1.ETIMEDOUT)); }, timeout); const unsubscribe = () => { if (signals) { @@ -10207,7 +10256,7 @@ var require_index_001 = __commonJS({ if (method) { return method.call(res); } - throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config); + throw new AxiosError$1(`Response type '${type}' is not supported`, AxiosError$1.ERR_NOT_SUPPORT, config); }); }); })(); @@ -10331,19 +10380,19 @@ var require_index_001 = __commonJS({ unsubscribe && unsubscribe(); if (err && err.name === "TypeError" && /Load failed|fetch/i.test(err.message)) { throw Object.assign( - new AxiosError("Network Error", AxiosError.ERR_NETWORK, config, request), + new AxiosError$1("Network Error", AxiosError$1.ERR_NETWORK, config, request, err && err.response), { cause: err.cause || err } ); } - throw AxiosError.from(err, err && err.code, config, request); + throw AxiosError$1.from(err, err && err.code, config, request, err && err.response); } }); }; const seedCache = /* @__PURE__ */ new Map(); const getFetch = (config) => { - let env = config ? config.env : {}; + let env = config && config.env || {}; const { fetch: fetch2, Request, Response } = env; const seeds = [ Request, @@ -10378,40 +10427,49 @@ var require_index_001 = __commonJS({ }); const renderReason = (reason) => `- ${reason}`; const isResolvedHandle = (adapter) => utils$1.isFunction(adapter) || adapter === null || adapter === false; - const adapters = { - getAdapter: (adapters2, config) => { - adapters2 = utils$1.isArray(adapters2) ? adapters2 : [adapters2]; - const { length } = adapters2; - let nameOrAdapter; - let adapter; - const rejectedReasons = {}; - for (let i = 0; i < length; i++) { - nameOrAdapter = adapters2[i]; - let id; - adapter = nameOrAdapter; - if (!isResolvedHandle(nameOrAdapter)) { - adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; - if (adapter === void 0) { - throw new AxiosError(`Unknown adapter '${id}'`); - } - } - if (adapter && (utils$1.isFunction(adapter) || (adapter = adapter.get(config)))) { - break; - } - rejectedReasons[id || "#" + i] = adapter; - } - if (!adapter) { - const reasons = Object.entries(rejectedReasons).map( - ([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build") - ); - let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified"; - throw new AxiosError( - `There is no suitable adapter to dispatch the request ` + s, - "ERR_NOT_SUPPORT" - ); + function getAdapter(adapters2, config) { + adapters2 = utils$1.isArray(adapters2) ? adapters2 : [adapters2]; + const { length } = adapters2; + let nameOrAdapter; + let adapter; + const rejectedReasons = {}; + for (let i = 0; i < length; i++) { + nameOrAdapter = adapters2[i]; + let id; + adapter = nameOrAdapter; + if (!isResolvedHandle(nameOrAdapter)) { + adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; + if (adapter === void 0) { + throw new AxiosError$1(`Unknown adapter '${id}'`); + } + } + if (adapter && (utils$1.isFunction(adapter) || (adapter = adapter.get(config)))) { + break; } - return adapter; - }, + rejectedReasons[id || "#" + i] = adapter; + } + if (!adapter) { + const reasons = Object.entries(rejectedReasons).map( + ([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build") + ); + let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified"; + throw new AxiosError$1( + `There is no suitable adapter to dispatch the request ` + s, + "ERR_NOT_SUPPORT" + ); + } + return adapter; + } + const adapters = { + /** + * Resolve an adapter from a list of adapter names or functions. + * @type {Function} + */ + getAdapter, + /** + * Exposes all known adapters + * @type {Object} + */ adapters: knownAdapters }; function throwIfCancellationRequested(config) { @@ -10419,7 +10477,7 @@ var require_index_001 = __commonJS({ config.cancelToken.throwIfRequested(); } if (config.signal && config.signal.aborted) { - throw new CanceledError(null, config); + throw new CanceledError$1(null, config); } } function dispatchRequest(config) { @@ -10457,7 +10515,7 @@ var require_index_001 = __commonJS({ return Promise.reject(reason); }); } - const VERSION = "1.12.2"; + const VERSION = "1.13.5"; const validators$1 = {}; ["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => { validators$1[type] = function validator2(thing) { @@ -10471,9 +10529,9 @@ var require_index_001 = __commonJS({ } return (value, opt, opts) => { if (validator2 === false) { - throw new AxiosError( + throw new AxiosError$1( formatMessage(opt, " has been removed" + (version2 ? " in " + version2 : "")), - AxiosError.ERR_DEPRECATED + AxiosError$1.ERR_DEPRECATED ); } if (version2 && !deprecatedWarnings[opt]) { @@ -10496,7 +10554,7 @@ var require_index_001 = __commonJS({ }; function assertOptions(options, schema, allowUnknown) { if (typeof options !== "object") { - throw new AxiosError("options must be an object", AxiosError.ERR_BAD_OPTION_VALUE); + throw new AxiosError$1("options must be an object", AxiosError$1.ERR_BAD_OPTION_VALUE); } const keys = Object.keys(options); let i = keys.length; @@ -10507,12 +10565,12 @@ var require_index_001 = __commonJS({ const value = options[opt]; const result = value === void 0 || validator2(value, opt, options); if (result !== true) { - throw new AxiosError("option " + opt + " must be " + result, AxiosError.ERR_BAD_OPTION_VALUE); + throw new AxiosError$1("option " + opt + " must be " + result, AxiosError$1.ERR_BAD_OPTION_VALUE); } continue; } if (allowUnknown !== true) { - throw new AxiosError("Unknown option " + opt, AxiosError.ERR_BAD_OPTION); + throw new AxiosError$1("Unknown option " + opt, AxiosError$1.ERR_BAD_OPTION); } } } @@ -10572,7 +10630,8 @@ var require_index_001 = __commonJS({ validator.assertOptions(transitional, { silentJSONParsing: validators.transitional(validators.boolean), forcedJSONParsing: validators.transitional(validators.boolean), - clarifyTimeoutError: validators.transitional(validators.boolean) + clarifyTimeoutError: validators.transitional(validators.boolean), + legacyInterceptorReqResOrdering: validators.transitional(validators.boolean) }, false); } if (paramsSerializer != null) { @@ -10617,7 +10676,13 @@ var require_index_001 = __commonJS({ return; } synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; - requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + const transitional2 = config.transitional || transitionalDefaults; + const legacyInterceptorReqResOrdering = transitional2 && transitional2.legacyInterceptorReqResOrdering; + if (legacyInterceptorReqResOrdering) { + requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + } else { + requestInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); + } }); const responseInterceptorChain = []; this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { @@ -10727,7 +10792,7 @@ var require_index_001 = __commonJS({ if (token.reason) { return; } - token.reason = new CanceledError(message, config, request); + token.reason = new CanceledError$1(message, config, request); resolvePromise(token.reason); }); } @@ -10861,7 +10926,13 @@ var require_index_001 = __commonJS({ InsufficientStorage: 507, LoopDetected: 508, NotExtended: 510, - NetworkAuthenticationRequired: 511 + NetworkAuthenticationRequired: 511, + WebServerIsDown: 521, + ConnectionTimedOut: 522, + OriginIsUnreachable: 523, + TimeoutOccurred: 524, + SslHandshakeFailed: 525, + InvalidSslCertificate: 526 }; Object.entries(HttpStatusCode).forEach(([key, value]) => { HttpStatusCode[value] = key; @@ -10879,12 +10950,12 @@ var require_index_001 = __commonJS({ } const axios = createInstance(defaults$1); axios.Axios = Axios$1; - axios.CanceledError = CanceledError; + axios.CanceledError = CanceledError$1; axios.CancelToken = CancelToken$1; axios.isCancel = isCancel; axios.VERSION = VERSION; axios.toFormData = toFormData; - axios.AxiosError = AxiosError; + axios.AxiosError = AxiosError$1; axios.Cancel = axios.CanceledError; axios.all = function all(promises) { return Promise.all(promises); @@ -11051,7 +11122,11 @@ var require_index_001 = __commonJS({ const authCheckUrl = clusterId ? `/ping?cluster_id=${clusterId}` : "/ping"; const response = yield httpClient.get(authCheckUrl); const isAuth = response.status === 200; - console.log("Auth check:", { clusterId, status: response.status, isAuth }); + console.log("Auth check:", { + clusterId, + status: response.status, + isAuth + }); return { isAuthenticated: isAuth }; } catch (error) { if (error instanceof StructuredError) { @@ -11064,7 +11139,9 @@ var require_index_001 = __commonJS({ } } if (((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status) === 401 || ((_b = error == null ? void 0 : error.response) == null ? void 0 : _b.status) === 403) { - console.log("Auth check failed with authentication error but no structured response"); + console.log( + "Auth check failed with authentication error but no structured response" + ); return { isAuthenticated: false, error: "Authentication required" @@ -11096,7 +11173,10 @@ var require_index_001 = __commonJS({ if (currentParams.has("cluster_id")) { paramsToPreserve.cluster_id = currentParams.get("cluster_id"); } - sessionStorage.setItem(PRESERVED_PARAMS_STORAGE_KEY, JSON.stringify(paramsToPreserve)); + sessionStorage.setItem( + PRESERVED_PARAMS_STORAGE_KEY, + JSON.stringify(paramsToPreserve) + ); const params = new URLSearchParams({ session_id: sessionId, redirect_url, @@ -11135,7 +11215,9 @@ var require_index_001 = __commonJS({ if (urlParams.has("redirect_url")) { return true; } - const preservedParams = sessionStorage.getItem(PRESERVED_PARAMS_STORAGE_KEY); + const preservedParams = sessionStorage.getItem( + PRESERVED_PARAMS_STORAGE_KEY + ); if (preservedParams) { try { const params = JSON.parse(preservedParams); @@ -11152,7 +11234,9 @@ var require_index_001 = __commonJS({ let sessionId = urlParams.get("session_id"); let consumerId = urlParams.get("consumer_id"); if (!redirectUrl) { - const preservedParams = sessionStorage.getItem(PRESERVED_PARAMS_STORAGE_KEY); + const preservedParams = sessionStorage.getItem( + PRESERVED_PARAMS_STORAGE_KEY + ); if (preservedParams) { try { const params = JSON.parse(preservedParams); @@ -11180,9 +11264,11 @@ var require_index_001 = __commonJS({ } } restorePreservedParams() { - const preservedParamsJson = sessionStorage.getItem(PRESERVED_PARAMS_STORAGE_KEY); + const preservedParamsJson = sessionStorage.getItem( + PRESERVED_PARAMS_STORAGE_KEY + ); if (!preservedParamsJson) { - return; + return false; } try { const preservedParams = JSON.parse(preservedParamsJson); @@ -11198,12 +11284,15 @@ var require_index_001 = __commonJS({ sessionStorage.removeItem(PRESERVED_PARAMS_STORAGE_KEY); const newUrl = `${window.location.pathname}?${currentParams.toString()}`; window.location.replace(newUrl); + return true; } else { sessionStorage.removeItem(PRESERVED_PARAMS_STORAGE_KEY); + return false; } } catch (error) { console.error("Failed to restore preserved params:", error); sessionStorage.removeItem(PRESERVED_PARAMS_STORAGE_KEY); + return false; } } } @@ -11295,7 +11384,9 @@ var require_index_001 = __commonJS({ return Math.random().toString(36).substring(2) + Date.now().toString(36); }; onMounted(() => { - authService.restorePreservedParams(); + if (authService.restorePreservedParams()) { + return; + } checkAuthStatus(); window.addEventListener("auth-expired", () => { console.log("Received auth-expired event, updating authentication status"); @@ -11303,10 +11394,14 @@ var require_index_001 = __commonJS({ authStatus.value.error = "Session expired. Please re-authenticate."; const hasRequiredParams = route.query.cluster_id || route.query.session_id; if (hasRequiredParams && !hasAttemptedAuth.value) { - console.log("Auto-redirecting to authentication due to auth-expired event"); + console.log( + "Auto-redirecting to authentication due to auth-expired event" + ); authenticate(); } else if (!hasRequiredParams) { - console.log("No cluster_id or session_id parameters found, requiring manual authentication"); + console.log( + "No cluster_id or session_id parameters found, requiring manual authentication" + ); } else { console.log("Authentication already attempted, preventing hot loop"); } @@ -11317,7 +11412,7 @@ var require_index_001 = __commonJS({ return openBlock(), createElementBlock("div", _hoisted_1$4, [ createBaseVNode("header", _hoisted_2$4, [ createBaseVNode("div", _hoisted_3$4, [ - _cache[2] || (_cache[2] = createStaticVNode('

Kube Bind

', 1)), + _cache[2] || (_cache[2] = createStaticVNode('

Kube Bind

', 1)), authStatus.value.isAuthenticated ? (openBlock(), createElementBlock("div", _hoisted_4$4, [ _cache[1] || (_cache[1] = createBaseVNode("div", { class: "user-info" }, [ createBaseVNode("div", { class: "status-indicator" }), @@ -11387,7 +11482,7 @@ var require_index_001 = __commonJS({ }; } }); - const App_vue_vue_type_style_index_0_scoped_99283ff2_lang = ""; + const App_vue_vue_type_style_index_0_scoped_0b535f4a_lang = ""; const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { @@ -11395,7 +11490,7 @@ var require_index_001 = __commonJS({ } return target; }; - const App = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-99283ff2"]]); + const App = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-0b535f4a"]]); var __async$2 = (__this, __arguments, generator) => { return new Promise((resolve2, reject) => { var fulfilled = (value) => { diff --git a/web/dist/index.html b/web/dist/index.html index 61aad12aa..4e631f5d2 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -5,8 +5,8 @@ Kube Bind - - + +
diff --git a/web/package-lock.json b/web/package-lock.json index 05276fd1f..a94f6a564 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -651,6 +651,7 @@ "integrity": "sha512-W3bqcbLsRdFDVcmAM5l6oLlcl67vjevn8j1FPZ4nx+K5jNoWCh+FC/btxFoBPnvQlrHHDwfjp1kjIEDfwJ0Mog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -704,6 +705,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -1075,6 +1077,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1522,6 +1525,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -1578,6 +1582,7 @@ "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", @@ -2914,6 +2919,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2952,6 +2958,7 @@ "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -3007,6 +3014,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.21", "@vue/compiler-sfc": "3.5.21", diff --git a/web/src/App.vue b/web/src/App.vue index 8672ef9ef..8d171a795 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -4,10 +4,31 @@

Kube Bind

@@ -18,10 +39,34 @@ Connected
@@ -40,9 +85,15 @@

Please authenticate to access resources.

- @@ -52,92 +103,100 @@