@redocly/redoc 0.139.4 → 0.140.0-next.10
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.
- package/CHANGELOG.md +401 -201
- package/dist/api-schemas/mcp-fetch-count.d.ts +2 -18
- package/dist/api-schemas/otel-traces.d.ts +7 -1345
- package/dist/api-schemas/otel-traces.js +1 -1
- package/dist/api-schemas/search-facets.d.ts +3 -31
- package/dist/api-schemas/search-facets.js +1 -1
- package/dist/api-schemas/search.d.ts +7 -52
- package/dist/api-schemas/search.js +1 -1
- package/dist/cli/eject/resolveEjectParams.js +1 -1
- package/dist/cli/generate/get-schema-template.js +1 -1
- package/dist/client/app/hooks/markdown/useMarkdocRenderer.js +1 -1
- package/dist/client/app/hooks/markdown/useMarkdownText.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +2 -0
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/use-markdown-adapter.d.ts +1 -33
- package/dist/client/app/useGlobalData.d.ts +1 -1
- package/dist/client/providers/post-message/use-post-message.d.ts +1 -1
- package/dist/compiled/@redocly/pii/index.mjs +1 -0
- package/dist/compiled/@redocly/pii/package.json +1 -0
- package/dist/compiled/svgo/svgo-node.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/markdoc/attributes/definition-path.d.ts +1 -1
- package/dist/markdoc/attributes/json-example-ref.d.ts +1 -1
- package/dist/markdoc/attributes/json-schema-ref.d.ts +1 -1
- package/dist/markdoc/attributes/parsed-yaml.d.ts +1 -1
- package/dist/markdoc/attributes/raw-content.d.ts +1 -1
- package/dist/markdoc/attributes/sample-from-json-schema.d.ts +1 -1
- package/dist/markdoc/helpers/extract-rbac-from-condition-node.d.ts +1 -1
- package/dist/markdoc/helpers/get-inner-text.d.ts +1 -1
- package/dist/markdoc/helpers/get-node-attribute.d.ts +1 -1
- package/dist/markdoc/helpers/get-variable.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-conditional-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-function.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-prompt-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-tag.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-variable.d.ts +1 -1
- package/dist/markdoc/helpers/parse-partials.d.ts +1 -1
- package/dist/markdoc/helpers/parse-partials.js +1 -1
- package/dist/markdoc/helpers/remove-markdoc-tags.js +1 -1
- package/dist/markdoc/helpers/set-node-attribute-value.d.ts +1 -1
- package/dist/markdoc/nodes/fence/index.d.ts +1 -1
- package/dist/markdoc/nodes/fence/index.js +1 -1
- package/dist/markdoc/nodes/gfm-list-item.d.ts +1 -1
- package/dist/markdoc/nodes/gfm-list-item.js +1 -1
- package/dist/markdoc/nodes/heading.d.ts +1 -1
- package/dist/markdoc/nodes/heading.js +1 -1
- package/dist/markdoc/nodes/index.d.ts +6 -165
- package/dist/markdoc/nodes/index.js +1 -1
- package/dist/markdoc/nodes/table.d.ts +1 -1
- package/dist/markdoc/nodes/table.js +1 -1
- package/dist/markdoc/nodes/text.d.ts +1 -1
- package/dist/markdoc/tags/json-example.js +1 -1
- package/dist/markdoc/tags/openapi-code-sample.js +1 -1
- package/dist/server/config/env-config.d.ts +26 -24
- package/dist/server/config/env-schema.d.ts +87 -326
- package/dist/server/config/env-schemas/api-urls.d.ts +2 -14
- package/dist/server/config/env-schemas/auth.d.ts +10 -32
- package/dist/server/config/env-schemas/catalog.d.ts +6 -9
- package/dist/server/config/env-schemas/database.d.ts +2 -8
- package/dist/server/config/env-schemas/environment-detection.d.ts +20 -18
- package/dist/server/config/env-schemas/feature-flags.d.ts +29 -33
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/config/env-schemas/organization-project.d.ts +3 -21
- package/dist/server/config/env-schemas/scorecards.d.ts +2 -6
- package/dist/server/config/env-schemas/search.d.ts +9 -15
- package/dist/server/config/env-schemas/server-config.d.ts +6 -31
- package/dist/server/config/env-schemas/site.d.ts +1 -5
- package/dist/server/config/env-schemas/ssr.d.ts +7 -12
- package/dist/server/config/env-schemas/telemetry.d.ts +1 -7
- package/dist/server/constants/common.d.ts +3 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/esbuild/plugins/dependency-resolver.js +1 -1
- package/dist/server/esbuild/plugins/themes-resolver.js +3 -3
- package/dist/server/external-plugins/resolve-external-plugins.js +1 -1
- package/dist/server/plugins/api-docs/definition-access.d.ts +22 -0
- package/dist/server/plugins/api-docs/definition-access.js +1 -0
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/loader.d.ts +1 -1
- package/dist/server/plugins/api-docs/options.js +1 -1
- package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/config-parser/index.js +1 -1
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
- package/dist/server/plugins/dev-onboarding/api/middlewares/auth.d.ts +2 -4
- package/dist/server/plugins/dev-onboarding/api/middlewares/integrations.d.ts +2 -4
- package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/filesets-resolver.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/index.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-code-snippet-from-file.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-href.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-source-attribute.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-gallery.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src-set.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-schema-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-native-md-link.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-nav-links.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-response-samples.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-parsed-yaml.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-raw-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-or-cdn-icon.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-path.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-sample-from-json-schema.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.js +2 -2
- package/dist/server/plugins/markdown/attribute-resolvers/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/compiler.d.ts +1 -1
- package/dist/server/plugins/markdown/compiler.js +1 -1
- package/dist/server/plugins/markdown/errors.d.ts +1 -1
- package/dist/server/plugins/markdown/get-server-props.js +1 -1
- package/dist/server/plugins/markdown/html/normalize-html-headings.d.ts +1 -1
- package/dist/server/plugins/markdown/html/normalize-html-headings.js +1 -1
- package/dist/server/plugins/markdown/markdoc/functions/concat.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +5 -165
- package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
- package/dist/server/plugins/markdown/markdoc/partials.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/headings.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/reparse-example-fences.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/reparse-example-fences.js +1 -1
- package/dist/server/plugins/markdown/runtime-transform.d.ts +2 -2
- package/dist/server/plugins/markdown/runtime-transform.js +1 -1
- package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
- package/dist/server/plugins/markdown/search/nodes/section-node.d.ts +1 -1
- package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
- package/dist/server/plugins/markdown/search/to-markdown.d.ts +1 -1
- package/dist/server/plugins/markdown/search/walk-sections.d.ts +1 -1
- package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
- package/dist/server/plugins/markdown/utils/stringify-tag-children-objects.d.ts +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +4 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -2
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/errors.d.ts +0 -5
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.js +2 -2
- package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +2 -2
- package/dist/server/plugins/scorecard-classic/compute-scorecard.js +1 -1
- package/dist/server/plugins/scorecard-classic/index.js +1 -1
- package/dist/server/plugins/scorecard-classic/shared-utils.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +3 -3
- package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
- package/dist/server/plugins/search/engines/typesense/index.js +1 -1
- package/dist/server/store.d.ts +1 -1
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/formatter.js +3 -3
- package/dist/server/tools/notifiers/helpers/colors.d.ts +1 -1
- package/dist/server/types/plugins/common.d.ts +1 -1
- package/dist/server/utils/codeframes/codeframes.d.ts +1 -1
- package/dist/server/utils/codeframes/yaml-ast.d.ts +1 -1
- package/dist/server/utils/decode-request-path.d.ts +2 -0
- package/dist/server/utils/decode-request-path.js +1 -0
- package/dist/server/utils/envs/env-boolean-string.d.ts +9 -3
- package/dist/server/utils/envs/load-env-variables.js +1 -1
- package/dist/server/utils/errors.d.ts +3 -0
- package/dist/server/utils/errors.js +1 -1
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.js +1 -1
- package/dist/server/utils/rbac-expand.js +1 -1
- package/dist/server/utils/rbac.d.ts +5 -1
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/utils/report-all-errors.js +1 -1
- package/dist/server/web-server/auth.d.ts +2 -0
- package/dist/server/web-server/auth.js +2 -2
- package/dist/server/web-server/middleware/jsonValidatorMiddleware.d.ts +5 -325
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/error.js +1 -1
- package/dist/server/web-server/routes/feedback.d.ts +2 -8
- package/dist/server/web-server/routes/helpers/process-redirects.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.d.ts +2 -2
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.js +18 -18
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/utils/ssrf-safe-lookup.d.ts +2 -1
- package/dist/server/web-server/utils/ssrf-safe-lookup.js +1 -1
- package/dist/server/web-server/utils.d.ts +1 -3
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/markdoc.d.ts +1 -1
- package/package.json +12 -12
- package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.d.ts +0 -6
- package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.js +0 -1
- package/dist/server/plugins/markdown/html/process-html-tokens.d.ts +0 -2
- package/dist/server/plugins/markdown/html/process-html-tokens.js +0 -1
- package/dist/server/plugins/markdown/source.d.ts +0 -4
- package/dist/server/plugins/markdown/source.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.d.ts +0 -13
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.d.ts +0 -36
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as
|
|
1
|
+
import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as ne}from"xml-crypto";import re from"xpath";import{deflateSync as oe,inflateSync as se}from"fflate";import{createHash as ie}from"crypto";import{ulid as ae}from"ulid";import{AuthProviderType as p,DEFAULT_TEAM_CLAIM_NAME as U}from"@redocly/config";import{ALTERNATIVE_AUD_CLAIM_NAME as ce,AUTH_URL as V,JWT_SECRET_KEY as y,MAX_AUTH_TOKEN_COOKIE_BYTES as ue}from"../constants/common.js";import{ensureArray as O}from"../../utils/array/ensure-array.js";import{envConfig as de}from"../config/env-config.js";import{decryptClaimValue as le}from"../utils/crypto/decrypt-claim-value.js";import{decryptAesGcm as fe}from"../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as me}from"../utils/crypto/encrypt-aes-gcm.js";import{getPathPrefix as pe,withPathPrefix as he,withoutPathPrefix as ye}from"@redocly/theme/core/utils";import{ServerRoutes as K}from"../../constants/api.js";import{AuthCookieNames as I,DEFAULT_AUTHENTICATED_TEAM as Ae,REQUIRED_OIDC_SCOPES as $}from"../../constants/common.js";import{appendQueryParams as we}from"../../utils/url/append-query-params.js";import{parsePreviewUrl as B}from"../../utils/url/parse-preview-url.js";import{logger as E}from"../tools/notifiers/logger.js";import{OidcDiscoveryError as F}from"../utils/errors.js";import{randomString as _e}from"../utils/crypto/random-string.js";import{randomUUID as M}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as l,JwtTokenExpired as Se}from"./jwt/types.js";import*as m from"./jwt/jwt.js";import{InternalTokenTypes as g}from"./jwt/token-types.js";import{parseTeamClaimToArray as Te}from"../utils/index.js";import{parseTeamNameTemplate as ge}from"../utils/rbac-expand.js";import{arrayBufferToBase64 as xe,decodeBase64 as H,encodeBase64URL as Ie,urlSafeBase64 as z}from"./jwt/encode.js";import{formatSamlCertificate as Ee}from"./utils/format-saml-certificate.js";const ke=new Set(Object.values(g));function x(e){return e?.type===p.OIDC}function Re(e){return e?.type===p.SAML2}async function Ct(e,t){if(x(t))return Oe(e,t);if(Re(t))return Me(e,t)}async function Oe(e,t){const n=await X(e,t),r=new Set((t.scopes||[]).concat($)),o=t.authorizationRequestCustomParams||{};return{type:p.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function Me(e,t){return{type:p.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function W(e){return Array.from(new Set((e.scopes||[]).concat($))).join(" ")}async function J(e,t,n){return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:t.clientId,...t.clientSecret?{client_secret:t.clientSecret}:{},...n}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(r=>r.json())}async function bt(e,t,n,r,o={}){return await J(e,r,{scope:W(r),code:t,redirect_uri:q(n),grant_type:"authorization_code",...o})}async function vt(e,t,n){return await J(e,n,{scope:W(n),grant_type:"refresh_token",refresh_token:t})}function De(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:i,pkce:c},d,h,u){if(!t||!n||!r||!o)return{loginUrl:void 0};const a=new URL(t),w=u?.redirectUriOverride??`${e}${he(K.OIDC_CALLBACK)}`,S={state:M(),idpId:i,redirectUri:w,redirectTo:d,branch:u?.branchOverride??be(e),inviteCode:h,source:u?.sourceOverride??"portal",uiLocales:u?.uiLocales},T={};if(c){const A=z(_e(50)),k=z(ie("sha256").update(A).digest("base64")),R="S256";a.searchParams.append("code_challenge",k),a.searchParams.append("code_challenge_method",R),T.code_verifier={value:A,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:pe()||"/"}}}a.searchParams.append("client_id",n),a.searchParams.append("scope",o),a.searchParams.append("response_type",r),a.searchParams.append("redirect_uri",q(w)),a.searchParams.append("state",Ie(JSON.stringify(S))),u?.uiLocales&&a.searchParams.append("ui_locales",u.uiLocales);for(const A in s)s[A]!==void 0&&a.searchParams.append(A,s[A]);return{loginUrl:a.toString(),cookies:T}}function Pt(e,t,n,r){const o=new URL(e);return n&&(o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n)),o.toString()}function Le(e,t){const n=O(t?.audience??[]);return!n.length||Y(e,n)}function Y(e,t){const n=[e.aud,e[ce]].flat();return t.some(r=>r!==""&&n.includes(r))}function Ne(e,t){return!t||!x(t)?!0:Le(e,t)&&Ce(e,t)}function Ce(e,t){return!x(t)||!Qe(t)||!t.clientId?!0:O(e.aud||[]).includes(t.clientId)}function jt(e){if(!e)return!1;try{return m.decode(e).header.alg===l.RS256}catch{return!1}}async function Ut(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return m.sign({type:g.MCP_AUTHORIZATION_CODE,client_id:e.clientId,redirect_uri:e.redirectUri,id_token_enc:me(e.idToken,y),...e.idpId?{idp_id:e.idpId}:{},...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},y,l.HS256)}async function Vt(e){await m.verify(e,y,l.HS256);const{payload:t}=m.decode(e);if(t.type!==g.MCP_AUTHORIZATION_CODE)throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");if(typeof t.id_token_enc!="string")throw new Error("Authorization code missing session");return{...t,id_token:fe(t.id_token_enc,y)}}async function Kt(e){const t=Math.floor(Date.now()/1e3);return m.sign({type:g.MCP_REFRESH_TOKEN,client_id:e.clientId,...e.idpId?{idp_id:e.idpId}:{},claims:e.claims,...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},session_exp:e.sessionExp,iat:t,exp:e.sessionExp,jti:M()},y,l.HS256)}async function $t(e){await m.verify(e,y,l.HS256);const{payload:t}=m.decode(e);if(t.type!==g.MCP_REFRESH_TOKEN)throw new Error("Invalid refresh token type");if(!t.client_id||typeof t.claims!="object"||t.claims===null)throw new Error("Refresh token missing required claims");if(typeof t.session_exp!="number")throw new Error("Refresh token missing session expiry");return t}function Bt(e){const t=e||ae(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function q(e){const t=B(e);if(!t)return e;const n=ve(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,G(e,t);const r=Q(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,G(e,t)):e}function be(e){const t=B(e);if(t)return Q(t.hostname)?.previewBranch}function G(e,t){const n=e.replace(/^https?:\/\/[^/?#]+/i,"");return`${t.protocol}//${t.host}${ye(n)}`}function Q(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const s=n.slice(0,o),i=n.slice(o+2);return!s||!i||i.includes(".")?null:{projectSlug:s,previewBranch:i,after:r}}function ve(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const s=t===-1?"":e.slice(t);return{previewBranch:o,after:s}}function Pe(e){return e.type===p.OIDC}function je(e){return e.type===p.SAML2}function Ft(e,t,n,r,o){return Pe(e)?De(t,e,n,r,{uiLocales:o}):je(e)?Ue(t,e,n,r,o):{}}function Ue(e,t,n,r,o){const i=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
|
2
2
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
3
3
|
Version="2.0"
|
|
4
4
|
ID="_${M()}"
|
|
@@ -9,4 +9,4 @@ import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";im
|
|
|
9
9
|
<samlp:NameIDPolicy
|
|
10
10
|
AllowCreate="true"
|
|
11
11
|
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
|
|
12
|
-
</samlp:AuthnRequest>`,c=
|
|
12
|
+
</samlp:AuthnRequest>`,c=Ve(i);return{loginUrl:we(t.ssoUrl,{SAMLRequest:c,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function Ve(e){return xe(oe(new TextEncoder().encode(e)).buffer)}function Ht(e){const t=H(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=se(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function zt(e){try{return JSON.parse(H(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function Wt(e){const t=new j().parseFromString(e,"application/xml"),r=f(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=f(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",i=f(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],c=i&&i.nodeValue||void 0,d=f(t,"//*[local-name(.)='Audience']/text()")[0],h=d&&d.nodeValue||void 0,a=f(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",w=f(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=w&&w.nodeValue||"",T=f(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],A=T&&T.nodeValue||"",k=f(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],R=Ke(k),N={},C=f(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const b of C){const v=f(b,"./@Name")[0];if(v.nodeValue){const P=f(b,"./*[local-name(.)='AttributeValue']/text()")[0];P?.nodeValue&&(N[v.nodeValue]=P.nodeValue)}}return{uid:S,success:r,expiresAt:R,issuerId:c,entityId:h,attrs:N,cert:a,nameFormat:A,destination:s}}function Ke(e){const t=typeof e?.nodeValue=="string"&&D(Date.parse(e.nodeValue)),n=D(Date.now()),r=D(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function D(e){return Math.floor(e/1e3)}const L={},_={jwks:{},missedAt:{}},$e=6e4;function Be(e){const t=_.jwks[e];return t===void 0?!0:t===null&&Date.now()-(_.missedAt[e]??0)>=$e}async function X(e,t){if(!L[e]){const n=t.configurationUrl?await ee(t.configurationUrl):t.configuration;L[e]=Fe()?ze(n):n}return L[e]}function Fe(){const e=de.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}const He=["authorization_endpoint","end_session_endpoint"];function ze(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){if(He.includes(String(n)))continue;const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}const We=["kty","n","e","crv","x","y"];function Je(e,t){return We.every(n=>e[n]===t[n])}async function Ye(e){const t={};for(const n of Object.keys(e)){const r=e[n];if(!x(r))continue;const o=await X(n,r);if(o.jwks_uri){const s=await ee(o.jwks_uri);for(const i of s.keys){const c=t[i.kid],d=c&&Je(c,i)?[...c.idpIds,n]:[n];t[i.kid]={...i,idpIds:d},_.jwks[i.kid]=t[i.kid]}}}}function qe(e,t,n){const r=_.jwks[e]?.idpIds??[];return r.find(o=>{const s=n[o];if(!x(s))return!1;const i=O(s.audience??[]);return Y(t,i.length?i:[s.clientId])})??r.at(-1)}const Ge=6e4,Z={};async function ee(e){const t=Z[e];if(t&&Date.now()-t.failedAt<Ge)throw t.error;const n=await fetch(e,{headers:{Accept:"application/json"}}),r=n.ok?await n.json().catch(()=>{}):void 0;if(r===void 0){const o=new F(e,n.status,n.headers.get("content-type"));throw Z[e]={error:o,failedAt:Date.now()},o}return r}async function Jt(e){return fetch(`${V}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}async function Yt(e){return fetch(`${V}/api/auth/organization-session/login-code/exchange`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({code:e})}).then(t=>t.status===200?t.json():void 0).then(t=>typeof t?.token=="string"?t.token:void 0).catch(()=>{})}function Qe(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com"].some(r=>Xe(t.hostname,r))}function Xe(e,t){return e===t||e.endsWith(`.${t}`)}async function qt(e,t){const n=new j().parseFromString(e,"application/xml"),r=f(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=Ee(t),s=new ne({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function Ze(e){const t=new Set,n=r=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[o,s]of Object.entries(r))typeof s=="string"?t.add(o):n(s)};return n(e),t}function et(e,t,n){if(!t)return e;const r=Ze(t),o=s=>{const i=n?.[s]||s;return r.has(i)||!!ge(t,i)};return[...e.filter(o),...e.filter(s=>!o(s))]}async function Gt(e,t,n,r){const o=n?e[n]:void 0,s=Array.isArray(o)?et(o.map(String),r?.rbacConfig,r?.teamsMapping):[];let i=s.length;const c=s.length+1;for(let d=0;d<c;d++){const h={...e,idpId:t};n&&s.length&&(h[n]=s.slice(0,i));const u=await m.sign(h,y,l.HS256),a=Buffer.byteLength(u)-ue;if(a<=0)return{token:u,teamsTotal:s.length,teamsKept:i,droppedTeams:s.slice(i)};if(i===0)return null;const w=Buffer.byteLength(JSON.stringify(s.slice(0,i))),S=Math.max(1,w/i*4/3);i=Math.max(0,i-Math.max(1,Math.ceil(a/S)))}return null}function Qt(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/^.+@.+/m)&&(o=e);const s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],i=s?.match(/^.+@.+/m);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(i?s:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||s,email:o,email_verified:!0,teams:r?Te(n[r]):[]}}function te(e,t={}){return e.map(n=>t[n]||n)}async function Xt(e,t){if(!t)return{};const n=t[I.AUTHORIZATION];if(!n)return{};try{const r=m.decode(n);if(typeof r.payload.type=="string"&&ke.has(r.payload.type))return{};if(r.header.alg===l.RS256){const h=Be(r.header.kid);h&&await Ye(e);const u=_.jwks[r.header.kid];if(!u)return h&&(_.missedAt[r.header.kid]=Date.now()),_.jwks[r.header.kid]=null,{};await m.verify(n,u,l.RS256)}else await m.verify(n,y,l.HS256);const s=r.header.alg===l.RS256?qe(r.header.kid,r.payload,e):r.payload.idpId,i=e[s]||{};if(r.header.alg===l.RS256&&typeof r.payload.exp!="number")return E.warn("Rejected id_token: it has no exp claim"),{};if(r.header.alg===l.RS256&&!Ne(r.payload,i))return E.warn("Rejected id_token: it was issued for another project"),{};const c=rt(i),d=nt(i);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:s,teams:Array.from(new Set([...te(r.payload.teams||[],d),..."defaultTeams"in i&&i.defaultTeams||[],...te("teamsClaimName"in i&&r.payload[c||""]||[],d),Ae])),name:tt(r.payload),isAuthenticated:!0,idpAccessToken:le(r.payload.idp_access_token,y)||t[I.IDP_ACCESS_TOKEN],federatedAccessToken:t[I.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[I.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof Se||(r instanceof F?E.error(r.message):E.error("Malformed JWT token: %s",r.message))}return{}}function tt(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function nt(e){switch(e.type){case p.SAML2:return e.teamsAttributeMap;case p.OIDC:return e.teamsClaimMap;default:return}}function rt(e){switch(e.type){case p.SAML2:return e.teamsAttributeName??U;case p.OIDC:return e.teamsClaimName;default:return U}}function f(e,t){return re.select(t,e)||[]}export{Ge as OIDC_DISCOVERY_RETRY_MS,$e as UNKNOWN_KID_RETRY_MS,Ft as buildLoginUrl,De as buildOidcLoginUrl,Pt as buildOidcLogoutUrl,Ue as buildSAML2LoginUrl,Ut as createMcpAuthorizationCode,Kt as createMcpRefreshToken,Bt as createMcpSessionResource,Ht as decodeSamlResponse,Ye as discoverJwks,Ve as encodeSAML2,Yt as exchangeTokenLoginCode,Qt as extractUserClaims,Ct as getAuthProviderLoginParams,Oe as getOidcLoginParams,X as getOidcMetadata,Jt as getRedoclyTokenPayload,Me as getSaml2LoginParams,Xt as getUserParamsFromCookies,tt as getUsernameFromPayload,Le as idTokenAudienceIsAllowed,Ne as idTokenIsForThisProject,jt as isIdpIssuedToken,x as isOidcProviderConfig,Qe as isRedoclySso,Re as isSaml2ProviderConfig,bt as oidcExchangeCodeForToken,_ as oidcJwksCache,L as oidcMetadataCache,vt as oidcRefreshTokenGrant,et as orderTeamsRbacFirst,zt as parseOidcState,be as parsePreviewBranch,Wt as parseSamlResponse,q as rewritePreviewAuthRedirectUri,Gt as signTokenWithinCookieSizeLimit,Vt as verifyMcpAuthorizationCode,$t as verifyMcpRefreshToken,qt as verifySAMLResponse};
|
|
@@ -4,333 +4,13 @@ import type { ZodSchema } from 'zod';
|
|
|
4
4
|
* in the 400 response only in develop mode.
|
|
5
5
|
*/
|
|
6
6
|
export declare function jsonValidatorMiddleware<T extends ZodSchema>(schema: T): import("hono").MiddlewareHandler<import("hono").Env, string, {
|
|
7
|
-
in: (undefined extends (T extends
|
|
8
|
-
json?: ([T extends
|
|
7
|
+
in: (undefined extends (T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) ? true : false) extends true ? {
|
|
8
|
+
json?: ([T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never] extends [any] ? T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never : [Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, undefined>] extends [never] ? {} : [Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, undefined>] extends [object] ? undefined extends (T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) ? (((Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, (T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) & undefined> extends infer T_3 ? { [K in keyof T_3]: ([Exclude<T_3[K], undefined>] extends [string] ? [string & Exclude<T_3[K], undefined>] extends [import("hono/utils/types").UnionToIntersection<string & Exclude<T_3[K], undefined>>] ? false : true : false) extends true ? T_3[K] : ([unknown] extends [T_3[K]] ? false : undefined extends T_3[K] ? true : false) extends true ? T_3[K] : Target extends "form" ? T$1 | T$1[] : Target extends "query" ? string | string[] : Target extends "param" ? string : Target extends "header" ? string : Target extends "cookie" ? string : unknown; } : never) extends infer T_2 ? { [K in keyof T_2]: T_2[K]; } : never) extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never) | ((T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) & undefined) : (((T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) extends infer T_6 ? { [K in keyof T_6]: ([Exclude<T_6[K], undefined>] extends [string] ? [string & Exclude<T_6[K], undefined>] extends [import("hono/utils/types").UnionToIntersection<string & Exclude<T_6[K], undefined>>] ? false : true : false) extends true ? T_6[K] : ([unknown] extends [T_6[K]] ? false : undefined extends T_6[K] ? true : false) extends true ? T_6[K] : Target extends "form" ? T$1 | T$1[] : Target extends "query" ? string | string[] : Target extends "param" ? string : Target extends "header" ? string : Target extends "cookie" ? string : unknown; } : never) extends infer T_5 ? { [K in keyof T_5]: T_5[K]; } : never) extends infer T_4 ? { [K in keyof T_4]: T_4[K]; } : never : {}) | undefined;
|
|
9
9
|
} : {
|
|
10
|
-
json: [T extends
|
|
10
|
+
json: [T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never] extends [any] ? T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never : [Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, undefined>] extends [never] ? {} : [Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, undefined>] extends [object] ? undefined extends (T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) ? (((Exclude<T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never, (T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) & undefined> extends infer T_3 ? { [K in keyof T_3]: ([Exclude<T_3[K], undefined>] extends [string] ? [string & Exclude<T_3[K], undefined>] extends [import("hono/utils/types").UnionToIntersection<string & Exclude<T_3[K], undefined>>] ? false : true : false) extends true ? T_3[K] : ([unknown] extends [T_3[K]] ? false : undefined extends T_3[K] ? true : false) extends true ? T_3[K] : Target extends "form" ? T$1 | T$1[] : Target extends "query" ? string | string[] : Target extends "param" ? string : Target extends "header" ? string : Target extends "cookie" ? string : unknown; } : never) extends infer T_2 ? { [K in keyof T_2]: T_2[K]; } : never) extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never) | ((T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) & undefined) : (((T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").input<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod/v4/core").input<T> : never) extends infer T_6 ? { [K in keyof T_6]: ([Exclude<T_6[K], undefined>] extends [string] ? [string & Exclude<T_6[K], undefined>] extends [import("hono/utils/types").UnionToIntersection<string & Exclude<T_6[K], undefined>>] ? false : true : false) extends true ? T_6[K] : ([unknown] extends [T_6[K]] ? false : undefined extends T_6[K] ? true : false) extends true ? T_6[K] : Target extends "form" ? T$1 | T$1[] : Target extends "query" ? string | string[] : Target extends "param" ? string : Target extends "header" ? string : Target extends "cookie" ? string : unknown; } : never) extends infer T_5 ? { [K in keyof T_5]: T_5[K]; } : never) extends infer T_4 ? { [K in keyof T_4]: T_4[K]; } : never : {};
|
|
11
11
|
};
|
|
12
12
|
out: {
|
|
13
|
-
json: T extends
|
|
13
|
+
json: T extends import("zod/v3").ZodType<any, import("zod/v3").ZodTypeDef, any> ? import("zod/v3").output<T> : T extends import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>> ? import("zod").infer<T> : never;
|
|
14
14
|
};
|
|
15
|
-
},
|
|
16
|
-
success: boolean;
|
|
17
|
-
error: ({
|
|
18
|
-
path: (string | number)[];
|
|
19
|
-
message: string;
|
|
20
|
-
code: "custom";
|
|
21
|
-
params?: {
|
|
22
|
-
[x: string]: any;
|
|
23
|
-
} | undefined;
|
|
24
|
-
fatal?: boolean | undefined;
|
|
25
|
-
} | {
|
|
26
|
-
path: (string | number)[];
|
|
27
|
-
message: string;
|
|
28
|
-
code: "invalid_arguments";
|
|
29
|
-
argumentsError: {
|
|
30
|
-
name: string;
|
|
31
|
-
stack?: string;
|
|
32
|
-
cause?: import("hono/utils/types").JSONValue | undefined;
|
|
33
|
-
issues: ({
|
|
34
|
-
path: (string | number)[];
|
|
35
|
-
message: string;
|
|
36
|
-
code: "custom";
|
|
37
|
-
params?: {
|
|
38
|
-
[x: string]: any;
|
|
39
|
-
} | undefined;
|
|
40
|
-
fatal?: boolean | undefined;
|
|
41
|
-
} | /*elided*/ any | {
|
|
42
|
-
path: (string | number)[];
|
|
43
|
-
message: string;
|
|
44
|
-
code: "invalid_date";
|
|
45
|
-
fatal?: boolean | undefined;
|
|
46
|
-
} | {
|
|
47
|
-
path: (string | number)[];
|
|
48
|
-
message: string;
|
|
49
|
-
received: string | number;
|
|
50
|
-
code: "invalid_enum_value";
|
|
51
|
-
options: (string | number)[];
|
|
52
|
-
fatal?: boolean | undefined;
|
|
53
|
-
} | {
|
|
54
|
-
path: (string | number)[];
|
|
55
|
-
message: string;
|
|
56
|
-
code: "invalid_intersection_types";
|
|
57
|
-
fatal?: boolean | undefined;
|
|
58
|
-
} | {
|
|
59
|
-
path: (string | number)[];
|
|
60
|
-
message: string;
|
|
61
|
-
code: "invalid_literal";
|
|
62
|
-
expected: import("hono/utils/types").JSONValue;
|
|
63
|
-
received: import("hono/utils/types").JSONValue;
|
|
64
|
-
fatal?: boolean | undefined;
|
|
65
|
-
} | {
|
|
66
|
-
path: (string | number)[];
|
|
67
|
-
message: string;
|
|
68
|
-
code: "invalid_return_type";
|
|
69
|
-
returnTypeError: /*elided*/ any;
|
|
70
|
-
fatal?: boolean | undefined;
|
|
71
|
-
} | {
|
|
72
|
-
path: (string | number)[];
|
|
73
|
-
message: string;
|
|
74
|
-
code: "invalid_string";
|
|
75
|
-
validation: import("zod").StringValidation;
|
|
76
|
-
fatal?: boolean | undefined;
|
|
77
|
-
} | {
|
|
78
|
-
path: (string | number)[];
|
|
79
|
-
message: string;
|
|
80
|
-
code: "invalid_type";
|
|
81
|
-
expected: import("zod").ZodParsedType;
|
|
82
|
-
received: import("zod").ZodParsedType;
|
|
83
|
-
fatal?: boolean | undefined;
|
|
84
|
-
} | {
|
|
85
|
-
path: (string | number)[];
|
|
86
|
-
message: string;
|
|
87
|
-
code: "invalid_union_discriminator";
|
|
88
|
-
options: (string | number | boolean | null)[];
|
|
89
|
-
fatal?: boolean | undefined;
|
|
90
|
-
} | {
|
|
91
|
-
path: (string | number)[];
|
|
92
|
-
message: string;
|
|
93
|
-
code: "invalid_union";
|
|
94
|
-
unionErrors: /*elided*/ any[];
|
|
95
|
-
fatal?: boolean | undefined;
|
|
96
|
-
} | {
|
|
97
|
-
path: (string | number)[];
|
|
98
|
-
message: string;
|
|
99
|
-
code: "not_finite";
|
|
100
|
-
fatal?: boolean | undefined;
|
|
101
|
-
} | {
|
|
102
|
-
path: (string | number)[];
|
|
103
|
-
message: string;
|
|
104
|
-
code: "not_multiple_of";
|
|
105
|
-
multipleOf: number;
|
|
106
|
-
fatal?: boolean | undefined;
|
|
107
|
-
} | {
|
|
108
|
-
path: (string | number)[];
|
|
109
|
-
message: string;
|
|
110
|
-
code: "too_big";
|
|
111
|
-
maximum: number;
|
|
112
|
-
inclusive: boolean;
|
|
113
|
-
exact?: boolean;
|
|
114
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
115
|
-
fatal?: boolean | undefined;
|
|
116
|
-
} | {
|
|
117
|
-
path: (string | number)[];
|
|
118
|
-
message: string;
|
|
119
|
-
code: "too_small";
|
|
120
|
-
minimum: number;
|
|
121
|
-
inclusive: boolean;
|
|
122
|
-
exact?: boolean;
|
|
123
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
124
|
-
fatal?: boolean | undefined;
|
|
125
|
-
} | {
|
|
126
|
-
path: (string | number)[];
|
|
127
|
-
message: string;
|
|
128
|
-
code: "unrecognized_keys";
|
|
129
|
-
keys: string[];
|
|
130
|
-
fatal?: boolean | undefined;
|
|
131
|
-
})[];
|
|
132
|
-
readonly errors: ({
|
|
133
|
-
path: (string | number)[];
|
|
134
|
-
message: string;
|
|
135
|
-
code: "custom";
|
|
136
|
-
params?: {
|
|
137
|
-
[x: string]: any;
|
|
138
|
-
} | undefined;
|
|
139
|
-
fatal?: boolean | undefined;
|
|
140
|
-
} | /*elided*/ any | {
|
|
141
|
-
path: (string | number)[];
|
|
142
|
-
message: string;
|
|
143
|
-
code: "invalid_date";
|
|
144
|
-
fatal?: boolean | undefined;
|
|
145
|
-
} | {
|
|
146
|
-
path: (string | number)[];
|
|
147
|
-
message: string;
|
|
148
|
-
received: string | number;
|
|
149
|
-
code: "invalid_enum_value";
|
|
150
|
-
options: (string | number)[];
|
|
151
|
-
fatal?: boolean | undefined;
|
|
152
|
-
} | {
|
|
153
|
-
path: (string | number)[];
|
|
154
|
-
message: string;
|
|
155
|
-
code: "invalid_intersection_types";
|
|
156
|
-
fatal?: boolean | undefined;
|
|
157
|
-
} | {
|
|
158
|
-
path: (string | number)[];
|
|
159
|
-
message: string;
|
|
160
|
-
code: "invalid_literal";
|
|
161
|
-
expected: import("hono/utils/types").JSONValue;
|
|
162
|
-
received: import("hono/utils/types").JSONValue;
|
|
163
|
-
fatal?: boolean | undefined;
|
|
164
|
-
} | {
|
|
165
|
-
path: (string | number)[];
|
|
166
|
-
message: string;
|
|
167
|
-
code: "invalid_return_type";
|
|
168
|
-
returnTypeError: any;
|
|
169
|
-
fatal?: boolean | undefined;
|
|
170
|
-
} | {
|
|
171
|
-
path: (string | number)[];
|
|
172
|
-
message: string;
|
|
173
|
-
code: "invalid_string";
|
|
174
|
-
validation: import("zod").StringValidation;
|
|
175
|
-
fatal?: boolean | undefined;
|
|
176
|
-
} | {
|
|
177
|
-
path: (string | number)[];
|
|
178
|
-
message: string;
|
|
179
|
-
code: "invalid_type";
|
|
180
|
-
expected: import("zod").ZodParsedType;
|
|
181
|
-
received: import("zod").ZodParsedType;
|
|
182
|
-
fatal?: boolean | undefined;
|
|
183
|
-
} | {
|
|
184
|
-
path: (string | number)[];
|
|
185
|
-
message: string;
|
|
186
|
-
code: "invalid_union_discriminator";
|
|
187
|
-
options: (string | number | boolean | null)[];
|
|
188
|
-
fatal?: boolean | undefined;
|
|
189
|
-
} | {
|
|
190
|
-
path: (string | number)[];
|
|
191
|
-
message: string;
|
|
192
|
-
code: "invalid_union";
|
|
193
|
-
unionErrors: any[];
|
|
194
|
-
fatal?: boolean | undefined;
|
|
195
|
-
} | {
|
|
196
|
-
path: (string | number)[];
|
|
197
|
-
message: string;
|
|
198
|
-
code: "not_finite";
|
|
199
|
-
fatal?: boolean | undefined;
|
|
200
|
-
} | {
|
|
201
|
-
path: (string | number)[];
|
|
202
|
-
message: string;
|
|
203
|
-
code: "not_multiple_of";
|
|
204
|
-
multipleOf: number;
|
|
205
|
-
fatal?: boolean | undefined;
|
|
206
|
-
} | {
|
|
207
|
-
path: (string | number)[];
|
|
208
|
-
message: string;
|
|
209
|
-
code: "too_big";
|
|
210
|
-
maximum: number;
|
|
211
|
-
inclusive: boolean;
|
|
212
|
-
exact?: boolean;
|
|
213
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
214
|
-
fatal?: boolean | undefined;
|
|
215
|
-
} | {
|
|
216
|
-
path: (string | number)[];
|
|
217
|
-
message: string;
|
|
218
|
-
code: "too_small";
|
|
219
|
-
minimum: number;
|
|
220
|
-
inclusive: boolean;
|
|
221
|
-
exact?: boolean;
|
|
222
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
223
|
-
fatal?: boolean | undefined;
|
|
224
|
-
} | {
|
|
225
|
-
path: (string | number)[];
|
|
226
|
-
message: string;
|
|
227
|
-
code: "unrecognized_keys";
|
|
228
|
-
keys: string[];
|
|
229
|
-
fatal?: boolean | undefined;
|
|
230
|
-
})[];
|
|
231
|
-
readonly message: string;
|
|
232
|
-
readonly isEmpty: boolean;
|
|
233
|
-
addIssue: never;
|
|
234
|
-
addIssues: never;
|
|
235
|
-
readonly formErrors: {
|
|
236
|
-
formErrors: string[];
|
|
237
|
-
fieldErrors: {
|
|
238
|
-
[x: string]: string[] | undefined;
|
|
239
|
-
[x: number]: string[] | undefined;
|
|
240
|
-
};
|
|
241
|
-
};
|
|
242
|
-
};
|
|
243
|
-
fatal?: boolean | undefined;
|
|
244
|
-
} | {
|
|
245
|
-
path: (string | number)[];
|
|
246
|
-
message: string;
|
|
247
|
-
code: "invalid_date";
|
|
248
|
-
fatal?: boolean | undefined;
|
|
249
|
-
} | {
|
|
250
|
-
path: (string | number)[];
|
|
251
|
-
message: string;
|
|
252
|
-
received: string | number;
|
|
253
|
-
code: "invalid_enum_value";
|
|
254
|
-
options: (string | number)[];
|
|
255
|
-
fatal?: boolean | undefined;
|
|
256
|
-
} | {
|
|
257
|
-
path: (string | number)[];
|
|
258
|
-
message: string;
|
|
259
|
-
code: "invalid_intersection_types";
|
|
260
|
-
fatal?: boolean | undefined;
|
|
261
|
-
} | {
|
|
262
|
-
path: (string | number)[];
|
|
263
|
-
message: string;
|
|
264
|
-
code: "invalid_literal";
|
|
265
|
-
expected: import("hono/utils/types").JSONValue;
|
|
266
|
-
received: import("hono/utils/types").JSONValue;
|
|
267
|
-
fatal?: boolean | undefined;
|
|
268
|
-
} | {
|
|
269
|
-
path: (string | number)[];
|
|
270
|
-
message: string;
|
|
271
|
-
code: "invalid_return_type";
|
|
272
|
-
returnTypeError: any;
|
|
273
|
-
fatal?: boolean | undefined;
|
|
274
|
-
} | {
|
|
275
|
-
path: (string | number)[];
|
|
276
|
-
message: string;
|
|
277
|
-
code: "invalid_string";
|
|
278
|
-
validation: import("zod").StringValidation;
|
|
279
|
-
fatal?: boolean | undefined;
|
|
280
|
-
} | {
|
|
281
|
-
path: (string | number)[];
|
|
282
|
-
message: string;
|
|
283
|
-
code: "invalid_type";
|
|
284
|
-
expected: import("zod").ZodParsedType;
|
|
285
|
-
received: import("zod").ZodParsedType;
|
|
286
|
-
fatal?: boolean | undefined;
|
|
287
|
-
} | {
|
|
288
|
-
path: (string | number)[];
|
|
289
|
-
message: string;
|
|
290
|
-
code: "invalid_union_discriminator";
|
|
291
|
-
options: (string | number | boolean | null)[];
|
|
292
|
-
fatal?: boolean | undefined;
|
|
293
|
-
} | {
|
|
294
|
-
path: (string | number)[];
|
|
295
|
-
message: string;
|
|
296
|
-
code: "invalid_union";
|
|
297
|
-
unionErrors: any[];
|
|
298
|
-
fatal?: boolean | undefined;
|
|
299
|
-
} | {
|
|
300
|
-
path: (string | number)[];
|
|
301
|
-
message: string;
|
|
302
|
-
code: "not_finite";
|
|
303
|
-
fatal?: boolean | undefined;
|
|
304
|
-
} | {
|
|
305
|
-
path: (string | number)[];
|
|
306
|
-
message: string;
|
|
307
|
-
code: "not_multiple_of";
|
|
308
|
-
multipleOf: number;
|
|
309
|
-
fatal?: boolean | undefined;
|
|
310
|
-
} | {
|
|
311
|
-
path: (string | number)[];
|
|
312
|
-
message: string;
|
|
313
|
-
code: "too_big";
|
|
314
|
-
maximum: number;
|
|
315
|
-
inclusive: boolean;
|
|
316
|
-
exact?: boolean;
|
|
317
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
318
|
-
fatal?: boolean | undefined;
|
|
319
|
-
} | {
|
|
320
|
-
path: (string | number)[];
|
|
321
|
-
message: string;
|
|
322
|
-
code: "too_small";
|
|
323
|
-
minimum: number;
|
|
324
|
-
inclusive: boolean;
|
|
325
|
-
exact?: boolean;
|
|
326
|
-
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
|
327
|
-
fatal?: boolean | undefined;
|
|
328
|
-
} | {
|
|
329
|
-
path: (string | number)[];
|
|
330
|
-
message: string;
|
|
331
|
-
code: "unrecognized_keys";
|
|
332
|
-
keys: string[];
|
|
333
|
-
fatal?: boolean | undefined;
|
|
334
|
-
})[];
|
|
335
|
-
}, 400, "json">)>;
|
|
15
|
+
}, Response>;
|
|
336
16
|
//# sourceMappingURL=jsonValidatorMiddleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{setCookie as L,deleteCookie as P}from"hono/cookie";import{AuthProviderType as Y,DEFAULT_TEAM_CLAIM_NAME as Q}from"@redocly/config";import{withPathPrefix as w,getPathPrefix as A}from"@redocly/theme/core/utils";import{compareURIs as x}from"../../../utils/url/compare-uris.js";import{ensureArray as ee}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as re,JWT_SECRET_KEY as U,MAX_AUTH_TOKEN_COOKIE_BYTES as N,ORG_SLUG as oe,ORG_ID as te}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as k}from"../../../constants/api.js";import{AuthCookieNames as _,DEFAULT_COOKIE_EXPIRATION as B}from"../../../constants/common.js";import{sanitizeRedirectPathname as H}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as y}from"../../telemetry/index.js";import{envConfig as K}from"../../config/env-config.js";import{fetchWithClient as ie}from"../../utils/fetch-with-client.js";import{clearAuthCookies as z,clearPostLogoutCookie as v,hasPostLogoutCookie as se,setPostLogoutCookie as j}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ae,isOidcProviderConfig as b,isSaml2ProviderConfig as de,oidcExchangeCodeForToken as le,buildLoginUrl as ce,decodeSamlResponse as ue,extractUserClaims as pe,parseSamlResponse as ge,parseOidcState as fe,verifySAMLResponse as me,getUsernameFromPayload as he,buildOidcLogoutUrl as Ce,isIdpIssuedToken as Ie,getOidcMetadata as J,getRedoclyTokenPayload as _e,idTokenAudienceIsAllowed as Ae,isRedoclySso as Oe,rewritePreviewAuthRedirectUri as Re,parsePreviewBranch as Te,buildOidcLoginUrl as Le,createMcpSessionResource as M,signTokenWithinCookieSizeLimit as G}from"../auth.js";import*as $ from"../jwt/jwt.js";import{AlgorithmTypes as E}from"../jwt/types.js";import{handleErrorPageRender as we}from"../utils.js";import{encodeBase64URL as ye}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as Me}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ge(n,e){if(!e.devLogin||K.isProductionEnv)return n.newResponse(null,404,{});const{password:r,...a}=await n.req.json(),o=await $.sign({...a,name:a.username||a.email||"Unknown"},U,E.HS256);return L(n,_.AUTHORIZATION,o,{path:A()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),v(n),n.newResponse(null,200,{})}function Ze(){return async n=>{const e=n.get("logger"),r=encodeURIComponent(n.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${k.LOGIN}/?error=${encodeURIComponent(r)}`;return n.newResponse(null,301,{Location:a})}}function Z(n){if(!n||!n.includes(k.MCP_CALLBACK))return null;try{const e=n.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function Ve(n){return async e=>{const r=e.get("logger"),a=n.getConfig().ssoDirect;let o;try{o=fe(e.req.query("state"))}catch{return r.warn("OIDC login error: Invalid OAuth2 state"),e.text("Bad request: Invalid OAuth2 state",400)}const C=o.idpId,i=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(k.MCP_CALLBACK),u=i?Z(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,s=a?.[C];if(!b(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const p=await J(C,s);if(a&&!p.token_endpoint){const m="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${m}`),e.text(m,500)}try{const m=p.token_endpoint,f=e.req.query("code"),h=e.req.query("error");if(h)return i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),we(e,n,{slug:"/"},403,"403OIDC");if(!f){const g="Code is expected but not present";return r.error(`OIDC login error: ${g}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:g,error_details:null}]),new Response(`Forbidden: ${g}`,{status:403})}const R=typeof o.redirectUri=="string"?o.redirectUri:new URL(w(k.OIDC_CALLBACK),e.req.url).toString(),I=e.get("cookies")?.code_verifier,d=await le(m,f,R,s,{...s.tokenRequestCustomParams,...I?{code_verifier:I}:{}});if(d.error)return r.error(`Error from OIDC provider: "${d.error}"`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:`Token exchange error: ${d.error}`,error_details:d.error_description||null}]),e.text(`Forbidden: ${d.error_description||d.error}`,403);if(!d?.id_token){const g="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${g}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:g,error_details:null}]),new Response(`Forbidden: ${g}`,{status:403})}const{payload:l,header:T}=$.decode(d.id_token),t=T.alg===E.RS256;if(!Ae(l,s)){const g="No valid audience found in id_token";return r.error(`OIDC login error: ${g}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:g,error_details:null}]),new Response(`Forbidden: ${g}`,{status:403})}let c=t?d.id_token:await $.sign({...l,idpId:C},U,E.HS256);if(Buffer.byteLength(c)>N){const g=await G(l,C,s.teamsClaimName,{rbacConfig:n.getConfig().access?.rbac,teamsMapping:s.teamsClaimMap});if(!g){const S=`The id_token claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(l))} bytes of claims`;return r.error(`OIDC login error: ${S}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:S,error_details:null}]),e.text(`Forbidden: ${S}`,403)}g.teamsKept<g.teamsTotal&&r.warn(`OIDC login: the "${s.teamsClaimName}" claim is too large for the session cookie size limit; kept ${g.teamsKept} of ${g.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(g.droppedTeams)}`),c=g.token}he(l)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:l.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const g=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:d.access_token})});if(g.ok){const q=(await g.json()).ext?.federatedIdentity;q&&(L(e,_.FEDERATED_ACCESS_TOKEN,q.access_token||"",{path:A()||"/",httpOnly:!1,expires:new Date(D)}),L(e,_.FEDERATED_ID_TOKEN,q.id_token||"",{path:A()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${g.statusText}`)}if(L(e,_.AUTHORIZATION,c,{path:A()||"/",httpOnly:!0,expires:new Date(D)}),c!==d.id_token&&Buffer.byteLength(d.id_token)<=N?L(e,_.IDP_ID_TOKEN,d.id_token||"",{path:A()||"/",httpOnly:!0,expires:new Date(D)}):P(e,_.IDP_ID_TOKEN,{path:A()||"/"}),L(e,_.IDP_ACCESS_TOKEN,d.access_token||"",{path:A()||"/",httpOnly:!0,expires:new Date(D)}),d.refresh_token?L(e,_.IDP_REFRESH_TOKEN,d.refresh_token,{path:A()||"/",httpOnly:!0,expires:new Date(D)}):P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),P(e,"code_verifier",{path:A()||"/"}),v(e),i&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(k.MCP_CALLBACK)){const S=`${e.req.url.split("?")[0].replace(k.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:S})}const V=typeof o.redirectTo=="string"?o.redirectTo:void 0,W=H(new URL(V||"/",e.req.url).pathname),X=e.newResponse(null,302,{Location:W});return r.updateContext({email:l.email,subject:l.sub}),r.info("OIDC login successful"),X}catch(m){const f=m instanceof Error?m.message:String(m),h=m instanceof Error?m.stack:String(m);if(r.error(`OIDC login error: ${f}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:f,error_details:h}]),m.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const O="Something went wrong";return r.error(`OIDC login error: ${O}`),i&&y.sendMcpAuthorizationFailedMessage([{...M(u),error:O,error_details:null}]),e.text(O,500)}}function We(n){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,i=n.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return b(i)||(z(e),j(e)),r.info("Logout successful"),e.newResponse(null,200,{});let u;if(b(i)){const s=(await J(o,i)).end_session_endpoint;if(s){const p=new URL(e.req.url),O=e.req.header("x-forwarded-proto")||p.protocol.slice(0,-1)||"https",m=e.req.header("x-forwarded-host")||p.host,f=`${O}://${m}`,h=Te(f),R=h?ye(JSON.stringify({branch:h,postLogoutRedirectUri:`${f}${w(k.POST_LOGOUT)}`})):void 0,I=h?`${Re(f)}/${ne}/logout`:`${f}${w(k.POST_LOGOUT)}`,d=e.get("cookies"),l=d?.[_.AUTHORIZATION],T=d?.[_.IDP_ID_TOKEN]||(Ie(l)?l:void 0);u=Ce(s,I,T,R)}}return r.info("Logout successful"),z(e),j(e),e.newResponse(null,302,{Location:u||w("/")})}}function Xe(n){return async e=>{const r=n.getConfig().access?.logoutReturnUrl,a=r||w("/");return e.newResponse(null,302,{Location:a})}}function Ye(n){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=K.BH_API_URL,C=(i,u,s)=>i&&u?`${i} ${u.charAt(0)}`:s;try{if(!o)throw new Error("BH_API_URL is not set");const i=n.getConfig().ssoDirect;if(!i||!Object.keys(i).length)return r.warn("Invite no sso configured to handle"),e.redirect(w("/"));const u=await ie(`${o}/public-user-invites/${a}`);if(!u.ok)return u.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(w("/"))):(r.error("Invite error",await u.text()),e.redirect(w("/")));const s=await u.json(),p=new URL(w("/invite"),e.req.url);return p.searchParams.set("code",a),p.searchParams.set("org",s.organization.name),p.searchParams.set("invitedBy",C(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:p.toString()})}catch(i){return r.error("Error processing invite",{error:i,inviteCode:a}),e.text(i.message||"Failed to process invite",400)}}}function Qe(n){return async e=>{const r=e.get("logger"),a=n.getConfig().ssoDirect,o=new URL(e.req.url),C=e.req.query("inviteCode"),i=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",u=e.req.header("x-forwarded-host")||o.host,s=`${i}://${u}`;let p=o.searchParams.get("idpId");const O=o.searchParams.get("redirectTo"),m=Object.keys(a||{})[0];p=p||m;const f=o.searchParams.get("mcp_redirect_uri"),h=!!f;if(!a?.[p]){const c="Invalid idpId";if(r.error(`IdP login error: ${c}`),h){const F=Z(O||void 0);y.sendMcpAuthorizationFailedMessage([{...M(F),error:c,error_details:null}])}return e.text(`Forbidden: ${c}`,403)}const I=Me({localePrefixParam:o.searchParams.get("localePrefix"),l10n:n.getGlobalData()?.l10n}),d=p&&a?await ae(p,a[p]):void 0,l={};for(const c of Object.keys(d?.extraParams||{}))l[c]=o.searchParams.get(c)||d?.extraParams?.[c]||void 0;se(e)&&(l.prompt="login",l.post_logout="1");let T,t={};if(h&&f&&d&&d.type===Y.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${f}`);const c=Le("",{...d,extraParams:l},O,C,{redirectUriOverride:f,sourceOverride:"mcp",branchOverride:void 0,uiLocales:I});T=c.loginUrl,t=c.cookies||{}}else if(d){const c=ce({...d,extraParams:l},s,O,C,I);T=c.loginUrl,t=c.cookies||{}}return Object.keys(t).forEach(c=>{L(e,c,t[c].value,t[c].options)}),r.info(`IdP login initiated for ID '${p}'`),e.newResponse(null,302,{Location:T||new URL(e.req.url).pathname})}}function xe(n){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),C=a.get("RelayState");if(typeof o!="string"||typeof C!="string"){const t="SAMLResponse is required";return r.error(`SAML2 login error: ${t}`),e.text(`Bad request: ${t}`,400)}const i=ue(o),{success:u,uid:s,nameFormat:p,attrs:O,issuerId:m,expiresAt:f}=ge(i),{idpId:h,redirectTo:R}=JSON.parse(C);if(!u){const t="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!f||Math.ceil(Date.now()/1e3)>=f){const t="SAML2 Token Expired";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const I=n.getConfig().ssoDirect?.[h];if(!I||!de(I)){const t="Cannot find valid IdP";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!(I.issuerId&&m&&x(I.issuerId,m))){const t="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!await me(i,I.x509PublicCert)){const t="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const l=pe(s,p,O,I.teamsAttributeName??Q);if(!l.sub){const t="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}if(!l.email){const t="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}let T=await $.sign({...l,idpId:h},U,E.HS256);if(Buffer.byteLength(T)>N){const t=await G({...l},h,"teams",{rbacConfig:n.getConfig().access?.rbac,teamsMapping:I.teamsAttributeMap});if(!t){const c=`The SAML2 claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(l))} bytes of claims`;return r.error(`SAML2 login error: ${c}`),e.text(`Forbidden: ${c}`,403)}t.teamsKept<t.teamsTotal&&r.warn(`SAML2 login: the "teams" claim is too large for the session cookie size limit; kept ${t.teamsKept} of ${t.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(t.droppedTeams)}`),T=t.token}return L(e,_.AUTHORIZATION,T,{path:A()||"/",httpOnly:!0,expires:new Date(f*1e3)}),P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),v(e),r.updateContext({email:l.email,subject:l.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:R||"/"})}}function er(n){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=w(H(a.pathname)),C=n.getConfig().ssoDirect,i=Object.entries(C||{}).find(([,R])=>b(R)&&Oe(R));if(!(C&&i))return e.newResponse(null,302,{Location:o});const s=e.req.query("token"),p=s&&await _e(s);if(!p)return e.newResponse(null,302,{Location:o});if(!ee(p[re]||[]).some(R=>R===oe||R===te))return e.newResponse(null,302,{Location:o});const f=await $.sign({...p,idpId:i?.at(0)},U,E.HS256),h=Date.now()+B*1e3;return L(e,_.AUTHORIZATION,f,{path:A()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),v(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ge as authorizeHandler,Qe as idpLoginHandler,Ye as inviteHandler,We as logoutHandler,Ve as oidcCallbackHandler,Xe as postLogoutHandler,Ze as redoclyLoginCallbackHandler,er as redoclyTokenLoginHandler,xe as samlCallbackHandler};
|
|
1
|
+
import{setCookie as T,deleteCookie as P}from"hono/cookie";import{AuthProviderType as Y,DEFAULT_TEAM_CLAIM_NAME as Q}from"@redocly/config";import{withPathPrefix as L,getPathPrefix as O}from"@redocly/theme/core/utils";import{compareURIs as x}from"../../../utils/url/compare-uris.js";import{ensureArray as ee}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as re,JWT_SECRET_KEY as U,MAX_AUTH_TOKEN_COOKIE_BYTES as N,ORG_SLUG as oe,ORG_ID as te}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as M}from"../../../constants/api.js";import{AuthCookieNames as A,DEFAULT_COOKIE_EXPIRATION as B}from"../../../constants/common.js";import{sanitizeRedirectPathname as H}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as w}from"../../telemetry/index.js";import{envConfig as K}from"../../config/env-config.js";import{fetchWithClient as ie}from"../../utils/fetch-with-client.js";import{clearAuthCookies as z,clearPostLogoutCookie as v,hasPostLogoutCookie as se,setPostLogoutCookie as j}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ae,isOidcProviderConfig as b,isSaml2ProviderConfig as de,oidcExchangeCodeForToken as ce,buildLoginUrl as le,decodeSamlResponse as ue,extractUserClaims as pe,parseSamlResponse as ge,parseOidcState as fe,verifySAMLResponse as me,getUsernameFromPayload as he,buildOidcLogoutUrl as Ce,isIdpIssuedToken as Ie,getOidcMetadata as J,exchangeTokenLoginCode as _e,getRedoclyTokenPayload as Ae,idTokenAudienceIsAllowed as Oe,isRedoclySso as Re,rewritePreviewAuthRedirectUri as Te,parsePreviewBranch as Le,buildOidcLoginUrl as we,createMcpSessionResource as y,signTokenWithinCookieSizeLimit as G}from"../auth.js";import*as $ from"../jwt/jwt.js";import{AlgorithmTypes as E}from"../jwt/types.js";import{handleErrorPageRender as ye}from"../utils.js";import{encodeBase64URL as ke}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as Me}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ze(n,e){if(!e.devLogin||K.isProductionEnv)return n.newResponse(null,404,{});const{password:r,...a}=await n.req.json(),o=await $.sign({...a,name:a.username||a.email||"Unknown"},U,E.HS256);return T(n,A.AUTHORIZATION,o,{path:O()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),v(n),n.newResponse(null,200,{})}function Ve(){return async n=>{const e=n.get("logger"),r=encodeURIComponent(n.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${M.LOGIN}/?error=${encodeURIComponent(r)}`;return n.newResponse(null,301,{Location:a})}}function Z(n){if(!n||!n.includes(M.MCP_CALLBACK))return null;try{const e=n.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function We(n){return async e=>{const r=e.get("logger"),a=n.getConfig().ssoDirect;let o;try{o=fe(e.req.query("state"))}catch{return r.warn("OIDC login error: Invalid OAuth2 state"),e.text("Bad request: Invalid OAuth2 state",400)}const I=o.idpId,i=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(M.MCP_CALLBACK),u=i?Z(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,s=a?.[I];if(!b(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const g=await J(I,s);if(a&&!g.token_endpoint){const m="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${m}`),e.text(m,500)}try{const m=g.token_endpoint,h=e.req.query("code"),C=e.req.query("error");if(C)return i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:`OIDC error: ${C}`,error_details:e.req.query("error_description")||null}]),ye(e,n,{slug:"/"},403,"403OIDC");if(!h){const p="Code is expected but not present";return r.error(`OIDC login error: ${p}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:p,error_details:null}]),new Response(`Forbidden: ${p}`,{status:403})}const k=typeof o.redirectUri=="string"?o.redirectUri:new URL(L(M.OIDC_CALLBACK),e.req.url).toString(),f=e.get("cookies")?.code_verifier,d=await ce(m,h,k,s,{...s.tokenRequestCustomParams,...f?{code_verifier:f}:{}});if(d.error)return r.error(`Error from OIDC provider: "${d.error}"`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:`Token exchange error: ${d.error}`,error_details:d.error_description||null}]),e.text(`Forbidden: ${d.error_description||d.error}`,403);if(!d?.id_token){const p="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${p}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:p,error_details:null}]),new Response(`Forbidden: ${p}`,{status:403})}const{payload:c,header:R}=$.decode(d.id_token),t=R.alg===E.RS256;if(!Oe(c,s)){const p="No valid audience found in id_token";return r.error(`OIDC login error: ${p}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:p,error_details:null}]),new Response(`Forbidden: ${p}`,{status:403})}let l=t?d.id_token:await $.sign({...c,idpId:I},U,E.HS256);if(Buffer.byteLength(l)>N){const p=await G(c,I,s.teamsClaimName,{rbacConfig:n.getConfig().access?.rbac,teamsMapping:s.teamsClaimMap});if(!p){const S=`The id_token claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(c))} bytes of claims`;return r.error(`OIDC login error: ${S}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:S,error_details:null}]),e.text(`Forbidden: ${S}`,403)}p.teamsKept<p.teamsTotal&&r.warn(`OIDC login: the "${s.teamsClaimName}" claim is too large for the session cookie size limit; kept ${p.teamsKept} of ${p.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(p.droppedTeams)}`),l=p.token}he(c)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:c.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const p=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:d.access_token})});if(p.ok){const q=(await p.json()).ext?.federatedIdentity;q&&(T(e,A.FEDERATED_ACCESS_TOKEN,q.access_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(D)}),T(e,A.FEDERATED_ID_TOKEN,q.id_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${p.statusText}`)}if(T(e,A.AUTHORIZATION,l,{path:O()||"/",httpOnly:!0,expires:new Date(D)}),l!==d.id_token&&Buffer.byteLength(d.id_token)<=N?T(e,A.IDP_ID_TOKEN,d.id_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(D)}):P(e,A.IDP_ID_TOKEN,{path:O()||"/"}),T(e,A.IDP_ACCESS_TOKEN,d.access_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(D)}),d.refresh_token?T(e,A.IDP_REFRESH_TOKEN,d.refresh_token,{path:O()||"/",httpOnly:!0,expires:new Date(D)}):P(e,A.IDP_REFRESH_TOKEN,{path:O()||"/"}),P(e,"code_verifier",{path:O()||"/"}),v(e),i&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(M.MCP_CALLBACK)){const S=`${e.req.url.split("?")[0].replace(M.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:S})}const V=typeof o.redirectTo=="string"?o.redirectTo:void 0,W=H(new URL(V||"/",e.req.url).pathname),X=e.newResponse(null,302,{Location:W});return r.updateContext({email:c.email,subject:c.sub}),r.info("OIDC login successful"),X}catch(m){const h=m instanceof Error?m.message:String(m),C=m instanceof Error?m.stack:String(m);if(r.error(`OIDC login error: ${h}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:h,error_details:C}]),m.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const _="Something went wrong";return r.error(`OIDC login error: ${_}`),i&&w.sendMcpAuthorizationFailedMessage([{...y(u),error:_,error_details:null}]),e.text(_,500)}}function Xe(n){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,i=n.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return b(i)||(z(e),j(e)),r.info("Logout successful"),e.newResponse(null,200,{});let u;if(b(i)){const s=(await J(o,i)).end_session_endpoint;if(s){const g=new URL(e.req.url),_=e.req.header("x-forwarded-proto")||g.protocol.slice(0,-1)||"https",m=e.req.header("x-forwarded-host")||g.host,h=`${_}://${m}`,C=Le(h),k=C?ke(JSON.stringify({branch:C,postLogoutRedirectUri:`${h}${L(M.POST_LOGOUT)}`})):void 0,f=C?`${Te(h)}/${ne}/logout`:`${h}${L(M.POST_LOGOUT)}`,d=e.get("cookies"),c=d?.[A.AUTHORIZATION],R=d?.[A.IDP_ID_TOKEN]||(Ie(c)?c:void 0);u=Ce(s,f,R,k)}}return r.info("Logout successful"),z(e),j(e),e.newResponse(null,302,{Location:u||L("/")})}}function Ye(n){return async e=>{const r=n.getConfig().access?.logoutReturnUrl,a=r||L("/");return e.newResponse(null,302,{Location:a})}}function Qe(n){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=K.BH_API_URL,I=(i,u,s)=>i&&u?`${i} ${u.charAt(0)}`:s;try{if(!o)throw new Error("BH_API_URL is not set");const i=n.getConfig().ssoDirect;if(!i||!Object.keys(i).length)return r.warn("Invite no sso configured to handle"),e.redirect(L("/"));const u=await ie(`${o}/public-user-invites/${a}`);if(!u.ok)return u.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(L("/"))):(r.error("Invite error",await u.text()),e.redirect(L("/")));const s=await u.json(),g=new URL(L("/invite"),e.req.url);return g.searchParams.set("code",a),g.searchParams.set("org",s.organization.name),g.searchParams.set("invitedBy",I(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:g.toString()})}catch(i){return r.error("Error processing invite",{error:i,inviteCode:a}),e.text(i.message||"Failed to process invite",400)}}}function xe(n){return async e=>{const r=e.get("logger"),a=n.getConfig().ssoDirect,o=new URL(e.req.url),I=e.req.query("inviteCode"),i=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",u=e.req.header("x-forwarded-host")||o.host,s=`${i}://${u}`;let g=o.searchParams.get("idpId");const _=o.searchParams.get("redirectTo"),m=Object.keys(a||{})[0];g=g||m;const h=o.searchParams.get("mcp_redirect_uri"),C=!!h;if(!a?.[g]){const l="Invalid idpId";if(r.error(`IdP login error: ${l}`),C){const F=Z(_||void 0);w.sendMcpAuthorizationFailedMessage([{...y(F),error:l,error_details:null}])}return e.text(`Forbidden: ${l}`,403)}const f=Me({localePrefixParam:o.searchParams.get("localePrefix"),l10n:n.getGlobalData()?.l10n}),d=g&&a?await ae(g,a[g]):void 0,c={};for(const l of Object.keys(d?.extraParams||{}))c[l]=o.searchParams.get(l)||d?.extraParams?.[l]||void 0;se(e)&&(c.prompt="login",c.post_logout="1");let R,t={};if(C&&h&&d&&d.type===Y.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${h}`);const l=we("",{...d,extraParams:c},_,I,{redirectUriOverride:h,sourceOverride:"mcp",branchOverride:void 0,uiLocales:f});R=l.loginUrl,t=l.cookies||{}}else if(d){const l=le({...d,extraParams:c},s,_,I,f);R=l.loginUrl,t=l.cookies||{}}return Object.keys(t).forEach(l=>{T(e,l,t[l].value,t[l].options)}),r.info(`IdP login initiated for ID '${g}'`),e.newResponse(null,302,{Location:R||new URL(e.req.url).pathname})}}function er(n){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),I=a.get("RelayState");if(typeof o!="string"||typeof I!="string"){const t="SAMLResponse is required";return r.error(`SAML2 login error: ${t}`),e.text(`Bad request: ${t}`,400)}const i=ue(o),{success:u,uid:s,nameFormat:g,attrs:_,issuerId:m,expiresAt:h}=ge(i),{idpId:C,redirectTo:k}=JSON.parse(I);if(!u){const t="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!h||Math.ceil(Date.now()/1e3)>=h){const t="SAML2 Token Expired";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const f=n.getConfig().ssoDirect?.[C];if(!f||!de(f)){const t="Cannot find valid IdP";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!(f.issuerId&&m&&x(f.issuerId,m))){const t="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!await me(i,f.x509PublicCert)){const t="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const c=pe(s,g,_,f.teamsAttributeName??Q);if(!c.sub){const t="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}if(!c.email){const t="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}let R=await $.sign({...c,idpId:C},U,E.HS256);if(Buffer.byteLength(R)>N){const t=await G({...c},C,"teams",{rbacConfig:n.getConfig().access?.rbac,teamsMapping:f.teamsAttributeMap});if(!t){const l=`The SAML2 claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(c))} bytes of claims`;return r.error(`SAML2 login error: ${l}`),e.text(`Forbidden: ${l}`,403)}t.teamsKept<t.teamsTotal&&r.warn(`SAML2 login: the "teams" claim is too large for the session cookie size limit; kept ${t.teamsKept} of ${t.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(t.droppedTeams)}`),R=t.token}return T(e,A.AUTHORIZATION,R,{path:O()||"/",httpOnly:!0,expires:new Date(h*1e3)}),P(e,A.IDP_REFRESH_TOKEN,{path:O()||"/"}),v(e),r.updateContext({email:c.email,subject:c.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:k||"/"})}}function rr(n){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=L(H(a.pathname)),I=n.getConfig().ssoDirect,i=Object.entries(I||{}).find(([,f])=>b(f)&&Re(f));if(!(I&&i))return e.newResponse(null,302,{Location:o});const s=e.req.query("code"),g=s?await _e(s):e.req.query("token"),_=g&&await Ae(g);if(!_)return e.newResponse(null,302,{Location:o});if(!ee(_[re]||[]).some(f=>f===oe||f===te))return e.newResponse(null,302,{Location:o});const C=await $.sign({..._,idpId:i?.at(0)},U,E.HS256),k=Date.now()+B*1e3;return T(e,A.AUTHORIZATION,C,{path:O()||"/",httpOnly:!0,expires:new Date(k),sameSite:"None",secure:!0,partitioned:!0}),P(e,A.IDP_REFRESH_TOKEN,{path:O()||"/"}),v(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ze as authorizeHandler,xe as idpLoginHandler,Qe as inviteHandler,Xe as logoutHandler,We as oidcCallbackHandler,Ye as postLogoutHandler,Ve as redoclyLoginCallbackHandler,rr as redoclyTokenLoginHandler,er as samlCallbackHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import m from"path";import{realpath as
|
|
1
|
+
import m from"path";import{realpath as G}from"fs/promises";import{REDOCLY_ROUTE_RBAC as z,REDOCLY_TEAMS_RBAC as j}from"@redocly/config";import{combineUrls as V,withoutPathPrefix as ie,withPathPrefix as R}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as W,CACHE_CONTROL_PUBLIC_HTML as ae,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as se,DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as ce,PAGE_DATA_FOLDER as le,PUBLIC_API_DEFINITIONS_FOLDER as me,PUBLIC_ASSETS_FOLDER as ue,STATIC_DATA_FOLDER as de,X_REDOCLY_CACHE_CONTROL_HEADER as fe,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as ge}from"../../constants/common.js";import{removeTrailingSlash as Z}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as pe}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as he}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as Re}from"../../config/env-config.js";import{addLeadingSlash as Ae}from"../../../utils/url/add-leading-slash.js";import{isPathInFolder as D}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as Ee}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{resolveLlmsTxtMd as J}from"../../utils/llmstxt/resolve-llms-txt-md.js";import{removeLeadingSlash as I}from"../../../utils/url/remove-leading-slash.js";import{decodeRequestPath as Ce}from"../../utils/decode-request-path.js";import{AI_INDEX_EXPORT_FOLDER as _e,SEARCH_DATA_EXPORT_FOLDER as Le}from"../../constants/plugins/search.js";import{processRedirects as Te}from"./helpers/process-redirects.js";import{renderPage as Pe,getServerProps as Oe}from"../../ssr/index.js";import{canAccessAsset as we,canAccessResource as K}from"../../utils/rbac.js";import{handleErrorPageRender as A,handleUnauthorized as Q,handleUnauthorizedAsset as x}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as De,MIME_TYPES as Ie}from"../mime-types.js";import{fileExistsAsync as Se}from"../../utils/index.js";import{isAiAgentRequest as ye}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as Ue}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as ee}from"../utils/content-type.js";import{telemetry as be}from"../../../cli/telemetry/index.js";import{telemetry as Me}from"../../telemetry/index.js";const Fe=[Le,_e,de,I(me),I(ce),le];async function qe(e,E){try{const[C,u]=await Promise.all([G(e),G(E)]);return Fe.some(t=>D(C,m.join(u,t)))}catch{return!1}}function mt(e,E,C,u){return async t=>{const S=t.get("logger"),i=t.req,c=new URL(i.url),_=c.pathname.replace(/\/{2,}/g,"/"),y=Ce(_);if(y===void 0)return t.text("Bad Request",400);const d=Re.isProductionEnv?301:302;if(_!==c.pathname)return t.newResponse(null,d,{Location:_+c.search});const r=ie(y),U=m.parse(r).ext.toLowerCase()===".md",b=ye({accept:i.header("accept"),signatureAgent:i.header("signature-agent"),signature:i.header("signature"),signatureInput:i.header("signature-input"),userAgent:i.header("user-agent")}),a=Ae(Z(r)),o=(i.method==="GET"||i.method==="HEAD")&&!U?e.getRouteBySlug(a,{followRedirect:!1})||pe(e.routesBySlug?.values(),n=>n.hasClientRoutes&&(r===n.slug||r.startsWith(n.slug+"/"))):void 0,M=e.getRedirect(a);if(M){const n=Te({redirect:M,reqUrlSearch:c.search});return Me.sendRedirectMessage([{id:a,object:"redirect",uri:`urn:redocly:realm:api:redirect:${a}`,from:a,templateId:n.type.toString()}]),t.newResponse(null,n.type,{Location:n.location})}if(o?.metadata?.type==="openapi"){const n=Ue(c.pathname);if(n)return S.info("Legacy OpenAPI docs redirect from "+c.pathname),t.newResponse(null,d,{Location:encodeURI(n)});if(r.match(/[A-Z]/))return S.warn("Redirect to lowercase route to avoid 404 error"),t.newResponse(null,d,{Location:encodeURI(R(r.toLowerCase()))})}if(r.endsWith("/")&&r!=="/"){const n=he(new URL(a||"/",t.req.url).pathname);return t.newResponse(null,d,{Location:R((n==="/"?"/":Z(n))+c.search)})}const{isAuthenticated:f,teams:L,claims:{email:T}}=t.get("auth");if(o&&!K(o,{isAuthenticated:f,email:T,teams:L},e.config.access?.rbac,e.config.access?.requiresLogin))return f?A(t,e,{slug:o.slug,[j]:o[j],[z]:o[z]},403):Q(t,e,o.slug);const g=o&&b?Ee(o.slug):void 0,F=g?await J(g,e,u):void 0,P=F?.exists??!1;if(o&&(!b||!P)){const n=await E(o),N=await Oe(o,t,n,e),{html:ne,statusCode:X,error:oe}=await Pe(o,N,t,e,be),Y=e.config.access?.rbac,$=!e.config.access?.requiresLogin&&(!Y||!Object.keys(Y).length),k=X>=400||!!oe||!!e.compilationErrors?.length,re=$&&!k;let h;return k?h=W:$?h=ae:h="private",t.html(ne,X,{"Cache-Control":h,...re&&{[fe]:ge}})}const p=g&&P?g:r,te=I(p),s=m.resolve(e.outdir,te);if(!D(s,e.outdir))return x(t);const q=U?await J(r,e,u):void 0,l=q?.route;if(l&&!K(l,{isAuthenticated:f,email:T,teams:L},e.config.access?.rbac,e.config.access?.requiresLogin))return Q(t,e,r);if(!P&&!l){if(await qe(s,e.outdir))return A(t,e,{slug:a},404);const n=e.getGlobalConfig("access");if(!we(p,n?.rbac||{},n?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:f,email:T,teams:L}))return D(p,ue)?x(t):A(t,e,{slug:a},404)}const O=Ie[m.extname(s)]||"text/plain",w=s.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||s.match(/runtime\/chunks\/.*/)?se:De[O],H=w?{"Cache-Control":`public, max-age=${w}, immutable`,Expires:new Date(Date.now()+w*1e3).toUTCString()}:{"Cache-Control":W},B=i.query("download")!=null,v=F?.content??q?.content;if(v!==void 0)return t.newResponse(v,200,{"Content-Type":ee(O),"Access-Control-Allow-Origin":"*",...H,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${V(e.config.seo.siteUrl,R(l.slug))}>; rel="canonical"`}},...B&&{"Content-Disposition":`attachment; filename="${m.basename(p)}"`}});if(await Se(s)){const n=await C(s);return t.newResponse(n,200,{"Content-Type":ee(O),"Access-Control-Allow-Origin":"*",...H,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${V(e.config.seo.siteUrl,R(l.slug))}>; rel="canonical"`}},...B&&{"Content-Disposition":`attachment; filename="${m.basename(s)}"`}})}else return A(t,e,{slug:a},404)}}export{mt as dynamicRouteHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{context as s,SpanStatusCode as n,trace as
|
|
1
|
+
import{context as s,SpanStatusCode as n,trace as o}from"@opentelemetry/api";import{HTTPException as a}from"hono/http-exception";import{envConfig as i}from"../../config/env-config.js";import{logger as r}from"../../tools/notifiers/logger.js";import{OidcDiscoveryError as f}from"../../utils/errors.js";const g=e=>{const t=o?.getSpan(s.active());return e instanceof Error&&"name"in e&&e.name==="URIError"?(t&&(t.setStatus({code:n.OK}),t.end()),new Response("Malformed URL",{status:400})):e instanceof SyntaxError?(t&&(t.setStatus({code:n.OK}),t.end()),new Response("Invalid JSON",{status:400})):e instanceof a&&e.status<500?(t&&(t.setStatus({code:n.OK}),t.end()),e.getResponse()):(t&&(t.setStatus({code:n.ERROR,message:e.message}),t.recordException(e),t.end()),e instanceof f?(r.error(e.message),new Response("Bad gateway: the identity provider returned an invalid response",{status:502})):i.isDevelopMode&&e?.name==="PageMissingDefaultExportError"?new Response(e.message,{status:200}):new Response("Internal Server Error",{status:500}))};export{g as errorHandler};
|