@redocly/realm 0.134.0-next.3 → 0.134.0-next.5

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.
Files changed (196) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/cli/eject/ejectComponent.d.ts +1 -1
  3. package/dist/cli/eject/ejectTheme.d.ts +1 -1
  4. package/dist/cli/eject/themeOperations.d.ts +2 -2
  5. package/dist/cli/telemetry/index.d.ts +1 -1
  6. package/dist/client/ErrorBoundary.d.ts +1 -1
  7. package/dist/client/TestProvider.d.ts +1 -1
  8. package/dist/client/app/CircularProgress.d.ts +1 -1
  9. package/dist/client/app/ConditionalLink.d.ts +2 -2
  10. package/dist/client/app/Link.js +1 -1
  11. package/dist/client/app/Sidebar/useSidebarItems.d.ts +2 -2
  12. package/dist/client/app/hooks/catalog/useCatalogFilter.d.ts +12 -12
  13. package/dist/client/app/hooks/catalog/useCatalogSort.d.ts +2 -2
  14. package/dist/client/app/hooks/catalog/useFetchCatalogEntities.d.ts +1 -1
  15. package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.d.ts +2 -2
  16. package/dist/client/app/hooks/catalog/useFetchCatalogEntityRevisions.d.ts +1 -1
  17. package/dist/client/app/hooks/catalog/useSearchTracker.d.ts +1 -1
  18. package/dist/client/app/hooks/products/useProducts.d.ts +3 -3
  19. package/dist/client/app/hooks/useUserClaims.js +1 -1
  20. package/dist/client/app/l10n/index.d.ts +1 -1
  21. package/dist/client/app/markdoc/custom-components/openapi/get-operation/get-operation.d.ts +1 -1
  22. package/dist/client/app/markdoc/custom-components/styled.elements.d.ts +2 -4
  23. package/dist/client/app/pages/DevLogin/DevLoginForm.d.ts +1 -1
  24. package/dist/client/app/pages/DevLogin/styled.d.ts +3 -3
  25. package/dist/client/app/search/useSearch.d.ts +2 -0
  26. package/dist/client/app/search/useSearch.js +1 -1
  27. package/dist/client/app/useGlobalData.d.ts +1 -1
  28. package/dist/client/app/utils/loadAndNavigate.d.ts +1 -1
  29. package/dist/client/browser-entry.d.ts +0 -1
  30. package/dist/client/browser-entry.js +3 -3
  31. package/dist/client/constants/ai-search.d.ts +7 -7
  32. package/dist/client/providers/page-data/hooks.d.ts +3 -3
  33. package/dist/client/templates/asyncapi-docs/helpers.d.ts +4 -181
  34. package/dist/client/templates/asyncapi-docs/helpers.js +1 -1
  35. package/dist/client/templates/openapi-docs/helpers.d.ts +1 -1
  36. package/dist/client/templates/openapi-docs/helpers.js +2 -2
  37. package/dist/client/templates/openapi-docs/mock-server-config.d.ts +3 -3
  38. package/dist/client/templates/openapi-docs/template.d.ts +1 -1
  39. package/dist/client/types/sidebar.d.ts +4 -4
  40. package/dist/constants/common.d.ts +73 -66
  41. package/dist/constants/common.js +1 -1
  42. package/dist/constants/l10n/langs/ar.js +1 -1
  43. package/dist/constants/l10n/langs/de.js +1 -1
  44. package/dist/constants/l10n/langs/en.js +1 -1
  45. package/dist/constants/l10n/langs/es.js +1 -1
  46. package/dist/constants/l10n/langs/fr.js +1 -1
  47. package/dist/constants/l10n/langs/hi.js +1 -1
  48. package/dist/constants/l10n/langs/it.js +1 -1
  49. package/dist/constants/l10n/langs/ja.js +1 -1
  50. package/dist/constants/l10n/langs/ko.js +1 -1
  51. package/dist/constants/l10n/langs/pl.js +1 -1
  52. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  53. package/dist/constants/l10n/langs/pt.js +1 -1
  54. package/dist/constants/l10n/langs/ru.js +1 -1
  55. package/dist/constants/l10n/langs/uk.js +1 -1
  56. package/dist/constants/l10n/langs/zh.js +1 -1
  57. package/dist/markdoc/helpers/normalize-custom-tags.d.ts +2 -0
  58. package/dist/markdoc/helpers/normalize-custom-tags.js +1 -0
  59. package/dist/markdoc/nodes/index.d.ts +6 -6
  60. package/dist/markdoc/tags/index.d.ts +2 -48
  61. package/dist/server/api-routes/helpers/read-stream-with-size-limit.d.ts +1 -1
  62. package/dist/server/api-routes/run-api-routes-worker.d.ts +1 -1
  63. package/dist/server/config/env-config.d.ts +17 -17
  64. package/dist/server/config/env-schema.d.ts +46 -46
  65. package/dist/server/config/env-schemas/auth.d.ts +4 -4
  66. package/dist/server/config/env-schemas/catalog.d.ts +2 -2
  67. package/dist/server/config/env-schemas/environment-detection.d.ts +8 -8
  68. package/dist/server/config/env-schemas/feature-flags.d.ts +10 -10
  69. package/dist/server/config/env-schemas/search.d.ts +3 -3
  70. package/dist/server/config/env-schemas/server-config.d.ts +2 -2
  71. package/dist/server/fs/content-fs.d.ts +1 -1
  72. package/dist/server/persistence/cache/mappers/create-cache-db-record.d.ts +1 -1
  73. package/dist/server/persistence/file-hashes/mappers/create-file-hash-db-record.d.ts +1 -1
  74. package/dist/server/persistence/kv/mappers/create-kv-db-record.d.ts +1 -1
  75. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.d.ts +5 -5
  76. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-attributes-db-record.d.ts +1 -1
  77. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-db-record.d.ts +1 -1
  78. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-db-record-from-file-schema.d.ts +1 -1
  79. package/dist/server/plugins/catalog-entities/database/mappers/field-transformations.d.ts +2 -2
  80. package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.d.ts +3 -3
  81. package/dist/server/plugins/catalog-entities/database/repositories/bffEntities/bff-entities-read-repository.d.ts +2 -2
  82. package/dist/server/plugins/catalog-entities/database/repositories/common/filters-repository.d.ts +1 -1
  83. package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.d.ts +1 -1
  84. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-read-repository.d.ts +1 -1
  85. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.d.ts +2 -2
  86. package/dist/server/plugins/catalog-entities/database/repositories/entityAttributes/entity-attributes-write-repository.d.ts +1 -1
  87. package/dist/server/plugins/catalog-entities/database/repositories/relations/relations-read-repository.d.ts +2 -2
  88. package/dist/server/plugins/catalog-entities/database/repositories/utils.d.ts +4 -4
  89. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +2 -2
  90. package/dist/server/plugins/catalog-entities/extensions/extractors/fs-entities-extractor.d.ts +1 -1
  91. package/dist/server/plugins/catalog-entities/schemas/database-schemas.d.ts +78 -78
  92. package/dist/server/plugins/catalog-entities/schemas/dto-schemas.d.ts +28 -28
  93. package/dist/server/plugins/catalog-entities/utils/get-not-accessible-catalog-resources.d.ts +1 -1
  94. package/dist/server/plugins/catalog-entities/utils/is-predefined-catalog-type.d.ts +1 -1
  95. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.d.ts +1 -1
  96. package/dist/server/plugins/config-parser/normalize-redirect-sources.d.ts +1 -1
  97. package/dist/server/plugins/default-theme/resolve-products-config.d.ts +1 -1
  98. package/dist/server/plugins/dev-onboarding/index.d.ts +1 -1
  99. package/dist/server/plugins/dev-onboarding/template/App.d.ts +1 -1
  100. package/dist/server/plugins/dev-onboarding/template/components/ApiKeyItem.d.ts +62 -4
  101. package/dist/server/plugins/dev-onboarding/template/components/ApiKeyProductStatus.js +2 -2
  102. package/dist/server/plugins/dev-onboarding/template/components/ApiKeySecret.js +2 -2
  103. package/dist/server/plugins/dev-onboarding/template/components/ApiKeys.d.ts +8 -2
  104. package/dist/server/plugins/dev-onboarding/template/components/ApiLogItem.js +1 -1
  105. package/dist/server/plugins/dev-onboarding/template/components/CharacterCounter.d.ts +1 -1
  106. package/dist/server/plugins/dev-onboarding/template/components/Container.d.ts +14 -2
  107. package/dist/server/plugins/dev-onboarding/template/components/DialogStyledComponents.d.ts +31 -11
  108. package/dist/server/plugins/dev-onboarding/template/components/MenuItemButton.d.ts +1 -1
  109. package/dist/server/plugins/dev-onboarding/template/components/Paper.d.ts +15 -3
  110. package/dist/server/plugins/dev-onboarding/template/components/PopupMenuUl.d.ts +1 -1
  111. package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.d.ts +2 -2
  112. package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.js +1 -1
  113. package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.d.ts +2 -2
  114. package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.js +1 -1
  115. package/dist/server/plugins/dev-onboarding/template/components/ShadowButton.d.ts +1 -1
  116. package/dist/server/plugins/dev-onboarding/template/components/ShadowButton.js +2 -2
  117. package/dist/server/plugins/dev-onboarding/template/components/StatusBadge.d.ts +1 -3
  118. package/dist/server/plugins/dev-onboarding/template/components/useSortableData.d.ts +2 -2
  119. package/dist/server/plugins/graphql-docs/constants.d.ts +1 -1
  120. package/dist/server/plugins/graphql-docs/search/ai/utils.d.ts +1 -1
  121. package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +36 -18
  122. package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
  123. package/dist/server/plugins/markdown/search/get-ai-search-documents.d.ts +1 -1
  124. package/dist/server/plugins/markdown/search/nodes/tag-node.d.ts +1 -1
  125. package/dist/server/plugins/markdown/utils/resolve-markdown-template.d.ts +1 -1
  126. package/dist/server/plugins/mcp/constants.d.ts +1 -1
  127. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +8 -8
  128. package/dist/server/plugins/mcp/docs-mcp/tools/utils.d.ts +1 -1
  129. package/dist/server/plugins/mcp/docs-mcp/utils.d.ts +2 -2
  130. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  131. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  132. package/dist/server/plugins/mcp/servers/docs-server.d.ts +1 -1
  133. package/dist/server/plugins/mcp/utils/jwt.js +1 -1
  134. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  135. package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +1 -1
  136. package/dist/server/plugins/scorecard-classic/get-scorecard-config.d.ts +63 -63
  137. package/dist/server/plugins/scorecard-classic/index.d.ts +1 -1
  138. package/dist/server/plugins/scorecard-classic/lint.d.ts +3 -3
  139. package/dist/server/plugins/scorecard-classic/template/Gauge.d.ts +1 -1
  140. package/dist/server/plugins/scorecard-classic/template/components.d.ts +1 -1
  141. package/dist/server/plugins/scorecard-classic/template/index.styles.d.ts +61 -33
  142. package/dist/server/plugins/scorecard-classic/template/useData.d.ts +58 -58
  143. package/dist/server/plugins/scorecard-classic/template/utils.d.ts +1 -1
  144. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.d.ts +1 -1
  145. package/dist/server/plugins/search/engines/search-engine.d.ts +1 -1
  146. package/dist/server/plugins/search/llmstxt/index.d.ts +1 -1
  147. package/dist/server/plugins/sidebars/index.d.ts +1 -1
  148. package/dist/server/providers/database/database-path-generator.d.ts +2 -2
  149. package/dist/server/providers/database/databases/sqlite-db/schemas/cache-table.d.ts +1 -1
  150. package/dist/server/providers/database/databases/sqlite-db/schemas/entities-attributes-table.d.ts +1 -1
  151. package/dist/server/providers/database/databases/sqlite-db/schemas/entities-relations-table.d.ts +1 -1
  152. package/dist/server/providers/database/databases/sqlite-db/schemas/entities-table.d.ts +1 -1
  153. package/dist/server/providers/database/databases/sqlite-db/schemas/file-hashes-table.d.ts +1 -1
  154. package/dist/server/providers/database/databases/sqlite-db/schemas/kv-table.d.ts +1 -1
  155. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-config-table.d.ts +1 -1
  156. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-evaluation-runs-table.d.ts +1 -1
  157. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-level-results-table.d.ts +1 -1
  158. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-levels-rules-results-table.d.ts +1 -1
  159. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-results-table.d.ts +1 -1
  160. package/dist/server/providers/database/databases/sqlite-db/schemas/scorecards-rule-results-table.d.ts +1 -1
  161. package/dist/server/providers/database/pagination/constants.d.ts +2 -2
  162. package/dist/server/providers/database/utils/storage-limit-validator.d.ts +1 -1
  163. package/dist/server/ssr/render.js +1 -1
  164. package/dist/server/ssr/server-side-props/get-default-static-props.d.ts +9 -9
  165. package/dist/server/ssr/server-side-props/get-server-props-from-user-handler.d.ts +1 -1
  166. package/dist/server/ssr/server-side-props/prepare-context-variables.d.ts +1 -1
  167. package/dist/server/ssr/template.d.ts +1 -1
  168. package/dist/server/store.d.ts +2 -2
  169. package/dist/server/tools/notifiers/reporter.d.ts +12 -12
  170. package/dist/server/utils/cookie.d.ts +1 -0
  171. package/dist/server/utils/cookie.js +1 -1
  172. package/dist/server/utils/envs/env-boolean-string.d.ts +3 -3
  173. package/dist/server/utils/product.d.ts +1 -1
  174. package/dist/server/utils/rbac.d.ts +33 -33
  175. package/dist/server/web-server/auth.d.ts +2 -2
  176. package/dist/server/web-server/auth.js +4 -4
  177. package/dist/server/web-server/middleware/catalogAuthMiddleware.d.ts +1 -1
  178. package/dist/server/web-server/routes/ask-ai.js +1 -1
  179. package/dist/server/web-server/routes/auth.js +1 -1
  180. package/dist/server/web-server/routes/catalog/helpers/create-entity-relation-update-schema.d.ts +12 -12
  181. package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +1967 -1967
  182. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +357 -357
  183. package/dist/server/web-server/routes/catalog/helpers/has-access-to-entity.d.ts +1 -1
  184. package/dist/server/web-server/routes/catalog/helpers/upsert-pages-stats.d.ts +1 -1
  185. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entities-relations.d.ts +7 -7
  186. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation-update-data.d.ts +7 -7
  187. package/dist/server/web-server/routes/catalog/parsers/relations/parse-entity-relation.d.ts +7 -7
  188. package/dist/server/web-server/routes/feedback.d.ts +1 -1
  189. package/dist/server/web-server/routes/helpers/process-redirects.d.ts +1 -1
  190. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  191. package/dist/server/web-server/utils/prepare-list-response.d.ts +1 -1
  192. package/dist/server/web-server/utils.d.ts +2 -2
  193. package/dist/utils/path/sanitize-path.js +1 -1
  194. package/dist/utils/should-forward-prop.d.ts +9 -0
  195. package/dist/utils/should-forward-prop.js +1 -0
  196. package/package.json +13 -12
@@ -62,34 +62,40 @@ export declare const isRbacConfigValid: (rbacConfig: unknown) => boolean;
62
62
  export declare const parseRbacConfig: (rbacConfig: RbacConfig | undefined) => Promise<RbacConfig | undefined>;
63
63
  export declare const normalizeRbacConfig: (rbacConfig: RbacConfig) => {
64
64
  [x: string]: unknown;
65
- reunite?: {
65
+ cms?: {
66
66
  [x: string]: string;
67
67
  } | undefined;
68
+ content?: {
69
+ [x: string]: unknown;
70
+ "**"?: {
71
+ [x: string]: string;
72
+ } | undefined;
73
+ } | undefined;
68
74
  entitiesCatalog?: {
69
75
  catalogs?: {
70
76
  [x: string]: unknown;
71
77
  all?: {
72
78
  [x: string]: string;
73
79
  } | undefined;
74
- services?: {
80
+ apiDescriptions?: {
75
81
  [x: string]: string;
76
82
  } | undefined;
77
- domains?: {
83
+ apiOperations?: {
78
84
  [x: string]: string;
79
85
  } | undefined;
80
- teams?: {
86
+ dataSchemas?: {
81
87
  [x: string]: string;
82
88
  } | undefined;
83
- users?: {
89
+ domains?: {
84
90
  [x: string]: string;
85
91
  } | undefined;
86
- apiDescriptions?: {
92
+ services?: {
87
93
  [x: string]: string;
88
94
  } | undefined;
89
- dataSchemas?: {
95
+ teams?: {
90
96
  [x: string]: string;
91
97
  } | undefined;
92
- apiOperations?: {
98
+ users?: {
93
99
  [x: string]: string;
94
100
  } | undefined;
95
101
  } | undefined;
@@ -99,56 +105,50 @@ export declare const normalizeRbacConfig: (rbacConfig: RbacConfig) => {
99
105
  [x: string]: string;
100
106
  } | undefined;
101
107
  } | undefined;
108
+ entitiesGroups?: {
109
+ config?: {
110
+ [x: string]: string;
111
+ } | undefined;
112
+ entities?: string[] | undefined;
113
+ }[] | undefined;
102
114
  entitiesTypes?: {
103
115
  [x: string]: unknown;
104
- user?: {
116
+ apiDescription?: {
105
117
  [x: string]: string;
106
118
  } | undefined;
107
- service?: {
119
+ apiOperation?: {
108
120
  [x: string]: string;
109
121
  } | undefined;
110
- domain?: {
122
+ dataSchema?: {
111
123
  [x: string]: string;
112
124
  } | undefined;
113
- team?: {
125
+ domain?: {
114
126
  [x: string]: string;
115
127
  } | undefined;
116
- apiDescription?: {
128
+ service?: {
117
129
  [x: string]: string;
118
130
  } | undefined;
119
- apiOperation?: {
131
+ team?: {
120
132
  [x: string]: string;
121
133
  } | undefined;
122
- dataSchema?: {
134
+ user?: {
123
135
  [x: string]: string;
124
136
  } | undefined;
125
137
  } | undefined;
126
- entitiesGroups?: {
127
- entities?: string[] | undefined;
128
- config?: {
129
- [x: string]: string;
130
- } | undefined;
131
- }[] | undefined;
132
138
  } | undefined;
133
- content?: {
134
- [x: string]: unknown;
135
- "**"?: {
139
+ features?: {
140
+ aiSearch?: {
136
141
  [x: string]: string;
137
142
  } | undefined;
138
143
  } | undefined;
139
- teamNamePatterns?: string[] | undefined;
140
- teamFolders?: string[] | undefined;
141
- teamFoldersBaseRoles?: {
144
+ reunite?: {
142
145
  [x: string]: string;
143
146
  } | undefined;
144
- cms?: {
147
+ teamFolders?: string[] | undefined;
148
+ teamFoldersBaseRoles?: {
145
149
  [x: string]: string;
146
150
  } | undefined;
147
- features?: {
148
- aiSearch?: {
149
- [x: string]: string;
150
- } | undefined;
151
- } | undefined;
151
+ teamNamePatterns?: string[] | undefined;
152
152
  };
153
153
  export declare function getRbacTeamsListForResource(resource: {
154
154
  fsPath?: string;
@@ -41,7 +41,7 @@ export declare function oidcExchangeCodeForToken(tokenUrl: string, code: string,
41
41
  error?: string;
42
42
  error_description?: string;
43
43
  }>;
44
- export declare function buildOidcLoginUrl(origin: string, { authorizationEndpoint, clientId, responseType, scope, extraParams, idpId, pkce, }: Partial<OidcLoginParams>, redirectTo: string | null, inviteCode?: string, options?: {
44
+ export declare function buildOidcLoginUrl(origin: string, { authorizationEndpoint, clientId, responseType, scope, extraParams, idpId, pkce }: Partial<OidcLoginParams>, redirectTo: string | null, inviteCode?: string, options?: {
45
45
  redirectUriOverride?: string;
46
46
  sourceOverride?: 'portal' | 'mcp';
47
47
  branchOverride?: string | undefined;
@@ -76,7 +76,7 @@ export declare function createMcpAuthorizationCode(params: {
76
76
  export declare function verifyMcpAuthorizationCode(code: string): Promise<McpAuthorizationCodePayload>;
77
77
  export declare function createMcpSessionResource(sessionId: string | null | undefined): {
78
78
  id: string;
79
- object: "mcp_session";
79
+ object: 'mcpSession';
80
80
  uri: string;
81
81
  };
82
82
  export declare function rewritePreviewAuthRedirectUri(redirectUri: string): string;
@@ -1,12 +1,12 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as b}from"@xmldom/xmldom";import{SignedXml as W}from"xml-crypto";import J from"xpath";import{deflateSync as q,inflateSync as K}from"fflate";import{createHash as Y}from"crypto";import{ulid as Q}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as X}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as L}from"../constants/common.js";import{envConfig as Z}from"../config/env-config.js";import{getPathPrefix as ee,withPathPrefix as te}from"@redocly/theme/core/utils";import{DEFAULT_AUTHENTICATED_TEAM as ne,REQUIRED_OIDC_SCOPES as D,ServerRoutes as v}from"../../constants/common.js";import{appendQueryParams as re}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as R}from"../../utils/url/parse-https-url.js";import{logger as oe}from"../tools/notifiers/logger.js";import{randomString as ae}from"../utils/crypto/random-string.js";import{randomUUID as U}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as w,JwtTokenExpired as se}from"./jwt/types.js";import*as f from"./jwt/jwt.js";import{parseTeamClaimToArray as ie}from"../utils/index.js";import{arrayBufferToBase64 as ce,decodeBase64 as N,encodeBase64URL as ue,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as le}from"./utils/format-saml-certificate.js";function E(e){return e?.type===u.OIDC}function de(e){return e?.type===u.SAML2}async function Qe(e,t){if(E(t))return me(e,t);if(de(t))return pe(e,t)}async function me(e,t){const n=await H(e,t),r=new Set((t.scopes||[]).concat(D)),o=t.authorizationRequestCustomParams||{};return{type:u.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 pe(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Xe(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(D));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:V(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function fe(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:l},m,A,p){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),h=p?.redirectUriOverride??`${e}${te(v.OIDC_CALLBACK)}`,_={state:U(),idpId:s,redirectUri:h,redirectTo:m,branch:p?.branchOverride??he(e),inviteCode:A,source:p?.sourceOverride??"portal",uiLocales:p?.uiLocales},y={};if(l){const d=j(ae(50)),g=j(Y("sha256").update(d).digest("base64")),x="S256";i.searchParams.append("code_challenge",g),i.searchParams.append("code_challenge_method",x),y.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:ee()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",V(h)),i.searchParams.append("state",ue(JSON.stringify(_))),p?.uiLocales&&i.searchParams.append("ui_locales",p.uiLocales);for(const d in a)a[d]!==void 0&&i.searchParams.append(d,a[d]);return{loginUrl:i.toString(),cookies:y}}function Ge(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function Ze(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return f.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpAccessToken?{idp_access_token:e.idpAccessToken}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},L,w.HS256)}async function et(e){await f.verify(e,L,w.HS256);const{payload:t}=f.decode(e);if(t.type!=="mcp_auth_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");return t}function tt(e){const t=e||Q(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcp_session",uri:`urn:redocly:realm:mcp:session:${n}`}}function V(e){const t=R(e);if(!t)return e;const n=ye(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,$(e,t);const r=B(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,$(e,t)):e}function he(e){const t=R(e);if(t)return B(t.hostname)?.previewBranch}function $(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function B(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 a=n.slice(0,o),s=n.slice(o+2);return!a||!s||s.includes(".")?null:{projectSlug:a,previewBranch:s,after:r}}function ye(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 a=t===-1?"":e.slice(t);return{previewBranch:o,after:a}}function we(e){return e.type===u.OIDC}function Se(e){return e.type===u.SAML2}function nt(e,t,n,r,o){return we(e)?fe(t,e,n,r,{uiLocales:o}):Se(e)?Ae(t,e,n,r,o):{}}function Ae(e,t,n,r,o){const s=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
1
+ import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as J}from"xml-crypto";import q from"xpath";import{deflateSync as K,inflateSync as Y}from"fflate";import{createHash as Q}from"crypto";import{ulid as X}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as Z}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as C}from"../constants/common.js";import{envConfig as ee}from"../config/env-config.js";import{getPathPrefix as te,withPathPrefix as ne}from"@redocly/theme/core/utils";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as N,ServerRoutes as R}from"../../constants/common.js";import{appendQueryParams as oe}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as b}from"../../utils/url/parse-https-url.js";import{logger as ae}from"../tools/notifiers/logger.js";import{randomString as se}from"../utils/crypto/random-string.js";import{randomUUID as v}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as w,JwtTokenExpired as ie}from"./jwt/types.js";import*as f from"./jwt/jwt.js";import{parseTeamClaimToArray as ce}from"../utils/index.js";import{arrayBufferToBase64 as ue,decodeBase64 as U,encodeBase64URL as le,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as de}from"./utils/format-saml-certificate.js";function V(e){return e?.type===u.OIDC}function me(e){return e?.type===u.SAML2}async function Xe(e,t){if(V(t))return pe(e,t);if(me(t))return fe(e,t)}async function pe(e,t){const n=await F(e,t),r=new Set((t.scopes||[]).concat(N)),o=t.authorizationRequestCustomParams||{};return{type:u.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 fe(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Ze(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(N));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:$(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function he(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:l},m,g,p){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),h=p?.redirectUriOverride??`${e}${ne(R.OIDC_CALLBACK)}`,_={state:v(),idpId:s,redirectUri:h,redirectTo:m,branch:p?.branchOverride??ye(e),inviteCode:g,source:p?.sourceOverride??"portal",uiLocales:p?.uiLocales},y={};if(l){const d=j(se(50)),x=j(Q("sha256").update(d).digest("base64")),I="S256";i.searchParams.append("code_challenge",x),i.searchParams.append("code_challenge_method",I),y.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:te()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",$(h)),i.searchParams.append("state",le(JSON.stringify(_))),p?.uiLocales&&i.searchParams.append("ui_locales",p.uiLocales);for(const d in a)a[d]!==void 0&&i.searchParams.append(d,a[d]);return{loginUrl:i.toString(),cookies:y}}function Ge(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function et(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return f.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpAccessToken?{idp_access_token:e.idpAccessToken}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},C,w.HS256)}async function tt(e){await f.verify(e,C,w.HS256);const{payload:t}=f.decode(e);if(t.type!=="mcp_auth_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");return t}function nt(e){const t=e||X(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function $(e){const t=b(e);if(!t)return e;const n=we(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,H(e,t);const r=B(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,H(e,t)):e}function ye(e){const t=b(e);if(t)return B(t.hostname)?.previewBranch}function H(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function B(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 a=n.slice(0,o),s=n.slice(o+2);return!a||!s||s.includes(".")?null:{projectSlug:a,previewBranch:s,after:r}}function we(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 a=t===-1?"":e.slice(t);return{previewBranch:o,after:a}}function Se(e){return e.type===u.OIDC}function Ae(e){return e.type===u.SAML2}function rt(e,t,n,r,o){return Se(e)?he(t,e,n,r,{uiLocales:o}):Ae(e)?ge(t,e,n,r,o):{}}function ge(e,t,n,r,o){const s=`<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
- ID="_${U()}"
4
+ ID="_${v()}"
5
5
  IssueInstant="${new Date().toISOString()}"
6
- AssertionConsumerServiceURL="${e}${v.SAML_CALLBACK}"
6
+ AssertionConsumerServiceURL="${e}${R.SAML_CALLBACK}"
7
7
  AttributeConsumingServiceIndex="0">
8
8
  <saml:Issuer>${t.entityId}</saml:Issuer>
9
9
  <samlp:NameIDPolicy
10
10
  AllowCreate="true"
11
11
  Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
12
- </samlp:AuthnRequest>`,l=_e(s);return{loginUrl:re(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ce(q(new TextEncoder().encode(e)).buffer)}function rt(e){const t=N(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=K(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function ot(e){try{return JSON.parse(N(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function at(e){const t=new b().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],A=m&&m.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=h&&h.nodeValue||"",y=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=y&&y.nodeValue||"",g=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],x=ge(g),C={},M=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(M.length)for(const O of M){const P=c(O,"./@Name")[0];if(P.nodeValue){const T=c(O,"./*[local-name(.)='AttributeValue']/text()")[0];T?.nodeValue&&(C[P.nodeValue]=T.nodeValue)}}return{uid:_,success:r,expiresAt:x,issuerId:l,entityId:A,attrs:C,cert:i,nameFormat:d,destination:a}}function ge(e){const t=typeof e?.nodeValue=="string"&&I(Date.parse(e.nodeValue)),n=I(Date.now()),r=I(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function I(e){return Math.floor(e/1e3)}const k={},S={jwks:{}};async function H(e,t){if(!k[e]){const n=t.configurationUrl?await z(t.configurationUrl):t.configuration;k[e]=xe()?Le(n):n}return k[e]}function xe(){const e=Z.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Le(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Ie(e){for(const t of Object.keys(e)){const n=e[t];if(!E(n))continue;const r=await H(t,n);if(r.jwks_uri){const o=await z(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function z(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function st(e){return fetch(`${G}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function it(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","cba.au.redocly.com"].some(r=>ke(t.hostname,r))}function ke(e,t){return e===t||e.endsWith(`.${t}`)}async function ct(e,t){const n=new b().parseFromString(e,"application/xml"),r=c(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=le(t),a=new W({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function ut(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(/.+@.+/)&&(o=e);const a=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a: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"]||a,email:o,email_verified:!0,teams:r?ie(n[r]):[]}}function F(e,t={}){return e.map(n=>t[n]||n)}async function lt(e,t){if(!t)return{};const n=t.authorization;if(!n)return{};try{const r=f.decode(n);if(r.header.alg===w.RS256){S.jwks[r.header.kid]===void 0&&await Ie(e);const m=S.jwks[r.header.kid];if(!m)return S.jwks[r.header.kid]=null,{};await f.verify(n,m,w.RS256)}else await f.verify(n,L,w.HS256);const o=r.payload.idpId||S.jwks[r.header.kid]?.idpId,a=e[o]||{},s=Oe(a),l=Me(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...F(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...F("teamsClaimName"in a&&r.payload[s||""]||[],l),ne])),name:Ce(r.payload),isAuthenticated:!0,idpAccessToken:r.payload.idp_access_token||t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:n}}catch(r){r instanceof se||oe.error("Malformed JWT token: %s",r.message)}return{}}function Ce(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Oe(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return X}}function c(e,t){return J.select(t,e)||[]}export{nt as buildLoginUrl,fe as buildOidcLoginUrl,Ge as buildOidcLogoutUrl,Ae as buildSAML2LoginUrl,Ze as createMcpAuthorizationCode,tt as createMcpSessionResource,rt as decodeSamlResponse,_e as encodeSAML2,ut as extractUserClaims,Qe as getAuthProviderLoginParams,me as getOidcLoginParams,H as getOidcMetadata,st as getRedoclyTokenPayload,pe as getSaml2LoginParams,lt as getUserParamsFromCookies,Ce as getUsernameFromPayload,E as isOidcProviderConfig,it as isRedoclySso,de as isSaml2ProviderConfig,Xe as oidcExchangeCodeForToken,S as oidcJwksCache,k as oidcMetadataCache,ot as parseOidcState,he as parsePreviewBranch,at as parseSamlResponse,V as rewritePreviewAuthRedirectUri,et as verifyMcpAuthorizationCode,ct as verifySAMLResponse};
12
+ </samlp:AuthnRequest>`,l=_e(s);return{loginUrl:oe(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ue(K(new TextEncoder().encode(e)).buffer)}function ot(e){const t=U(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=Y(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function at(e){try{return JSON.parse(U(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function st(e){const t=new P().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],g=m&&m.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=h&&h.nodeValue||"",y=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=y&&y.nodeValue||"",x=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=xe(x),O={},D=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(D.length)for(const M of D){const k=c(M,"./@Name")[0];if(k.nodeValue){const E=c(M,"./*[local-name(.)='AttributeValue']/text()")[0];E?.nodeValue&&(O[k.nodeValue]=E.nodeValue)}}return{uid:_,success:r,expiresAt:I,issuerId:l,entityId:g,attrs:O,cert:i,nameFormat:d,destination:a}}function xe(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const T={},S={jwks:{}};async function F(e,t){if(!T[e]){const n=t.configurationUrl?await z(t.configurationUrl):t.configuration;T[e]=Ie()?Ce(n):n}return T[e]}function Ie(){const e=ee.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ce(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!V(n))continue;const r=await F(t,n);if(r.jwks_uri){const o=await z(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function z(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function it(e){return fetch(`${G}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function ct(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","cba.au.redocly.com"].some(r=>Te(t.hostname,r))}function Te(e,t){return e===t||e.endsWith(`.${t}`)}async function ut(e,t){const n=new P().parseFromString(e,"application/xml"),r=c(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=de(t),a=new J({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function lt(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(/.+@.+/)&&(o=e);const a=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a: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"]||a,email:o,email_verified:!0,teams:r?ce(n[r]):[]}}function W(e,t={}){return e.map(n=>t[n]||n)}async function dt(e,t){if(!t)return{};const n=t[A.AUTHORIZATION];if(!n)return{};try{const r=f.decode(n);if(r.header.alg===w.RS256){S.jwks[r.header.kid]===void 0&&await Le(e);const m=S.jwks[r.header.kid];if(!m)return S.jwks[r.header.kid]=null,{};await f.verify(n,m,w.RS256)}else await f.verify(n,C,w.HS256);const o=r.payload.idpId||S.jwks[r.header.kid]?.idpId,a=e[o]||{},s=Me(a),l=De(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...W(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...W("teamsClaimName"in a&&r.payload[s||""]||[],l),re])),name:Oe(r.payload),isAuthenticated:!0,idpAccessToken:r.payload.idp_access_token||t[A.IDP_ACCESS_TOKEN],federatedAccessToken:t[A.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[A.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof ie||ae.error("Malformed JWT token: %s",r.message)}return{}}function Oe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function De(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return Z}}function c(e,t){return q.select(t,e)||[]}export{rt as buildLoginUrl,he as buildOidcLoginUrl,Ge as buildOidcLogoutUrl,ge as buildSAML2LoginUrl,et as createMcpAuthorizationCode,nt as createMcpSessionResource,ot as decodeSamlResponse,_e as encodeSAML2,lt as extractUserClaims,Xe as getAuthProviderLoginParams,pe as getOidcLoginParams,F as getOidcMetadata,it as getRedoclyTokenPayload,fe as getSaml2LoginParams,dt as getUserParamsFromCookies,Oe as getUsernameFromPayload,V as isOidcProviderConfig,ct as isRedoclySso,me as isSaml2ProviderConfig,Ze as oidcExchangeCodeForToken,S as oidcJwksCache,T as oidcMetadataCache,at as parseOidcState,ye as parsePreviewBranch,st as parseSamlResponse,$ as rewritePreviewAuthRedirectUri,tt as verifyMcpAuthorizationCode,ut as verifySAMLResponse};
@@ -1,5 +1,5 @@
1
1
  import type { Context, Next } from 'hono';
2
- export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods, }: {
2
+ export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods }: {
3
3
  serverOutDir: string;
4
4
  protectReadMethods?: boolean;
5
5
  }): (ctx: Context, next: Next) => Promise<Response | void>;
@@ -1 +1 @@
1
- import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as r}from"../../constants/common.js";import{canAccessFeature as u}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as h}from"../../plugins/search/utils.js";function C(a){return async e=>{if(!r)return e.newResponse(null,404);const t=a.getConfig();if(!h(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!u(p.AI_SEARCH,o,t.access?.rbac,t.access?.requiresLogin))return f(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const c=await e.req.json(),s=await fetch(r,{method:"POST",body:JSON.stringify(c),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{C as askAiHandler};
1
+ import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as a}from"../../constants/common.js";import{canAccessFeature as h}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as A}from"../../plugins/search/utils.js";function R(c){return async e=>{if(!a)return e.newResponse(null,404);const t=c.getConfig();if(!A(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!h(p.AI_SEARCH,o,t.access?.rbac,t.access?.requiresLogin))return f(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const r=e.req.header("Authorization");r&&(i.Authorization=r);const u=await e.req.json(),s=await fetch(a,{method:"POST",body:JSON.stringify(u),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{R as askAiHandler};
@@ -1 +1 @@
1
- import{setCookie as R,deleteCookie as b}from"hono/cookie";import{AuthProviderType as X}from"@redocly/config";import{withPathPrefix as I,getPathPrefix as _}from"@redocly/theme/core/utils";import{compareURIs as W}from"../../../utils/url/compare-uris.js";import{ensureArray as q}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as U,ORG_SLUG as Y,ORG_ID as Q}from"../../constants/common.js";import{AUTH_SEGMENT as Z,DEFAULT_COOKIE_EXPIRATION as B,ServerRoutes as O}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as k}from"../../telemetry/index.js";import{envConfig as H}from"../../config/env-config.js";import{getAuthProviderLoginParams as x,isOidcProviderConfig as $,isSaml2ProviderConfig as ee,oidcExchangeCodeForToken as re,buildLoginUrl as oe,decodeSamlResponse as ne,extractUserClaims as te,parseSamlResponse as ie,parseOidcState as se,verifySAMLResponse as ae,getUsernameFromPayload as de,buildOidcLogoutUrl as ce,getOidcMetadata as N,getRedoclyTokenPayload as le,isRedoclySso as ue,rewritePreviewAuthRedirectUri as pe,parsePreviewBranch as j,buildOidcLoginUrl as ge,createMcpSessionResource as A}from"../auth.js";import*as D from"../jwt/jwt.js";import{AlgorithmTypes as v}from"../jwt/types.js";import{handleErrorPageRender as fe}from"../utils.js";import{encodeBase64URL as me}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as he}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ue(i){if(H.isProductionEnv)return i.newResponse(null,404,{});const{password:e,...r}=await i.req.json(),a=await D.sign({...r,name:r.username||r.email||"Unknown"},U,v.HS256);return R(i,"authorization",a,{path:_()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),i.newResponse(null,200,{})}function $e(){return async i=>{const e=i.get("logger"),r=encodeURIComponent(i.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${O.LOGIN}/?error=${encodeURIComponent(r)}`;return i.newResponse(null,301,{Location:a})}}function G(i){if(!i||!i.includes(O.MCP_CALLBACK))return null;try{const e=i.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 Te(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,o=se(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(O.MCP_CALLBACK),c=t?G(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,s=a?.[m];if(!$(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await N(m,s);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),fe(e,i,{slug:"/"},403,"403OIDC");if(!u){const y="Code is expected but not present";return r.error(`OIDC login error: ${y}`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:y,error_details:null}]),new Response(`Forbidden: ${y}`,{status:403})}const C=typeof o.redirectUri=="string"?o.redirectUri:new URL(I(O.OIDC_CALLBACK),e.req.url).toString(),w=e.get("cookies")?.code_verifier,l=await re(p,u,C,s,{...s.tokenRequestCustomParams,...w?{code_verifier:w}:{}});if(l.error)return r.error(`Error from OIDC provider: "${l.error}"`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:`Token exchange error: ${l.error}`,error_details:l.error_description||null}]),e.text(`Forbidden: ${l.error_description||l.error}`,403);if(!l?.id_token){const y="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${y}`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:y,error_details:null}]),new Response(`Forbidden: ${y}`,{status:403})}const{payload:f,header:S}=D.decode(l.id_token),n=S.alg===v.RS256;if(s.audience?.length&&![...q(f.aud||[]),...q(f[F]||[])].some(M=>s.audience?.includes(M))){const M="No valid audience found in id_token";return r.error(`OIDC login error: ${M}`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:M,error_details:null}]),new Response(`Forbidden: ${M}`)}const g=n?l.id_token:await D.sign({...f,idpId:m},U,v.HS256);de(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const P=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const y=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(y.ok){const T=(await y.json()).ext?.federatedIdentity;T&&(R(e,"federated_access_token",T.access_token||"",{path:_()||"/",httpOnly:!1,expires:new Date(P)}),R(e,"federated_id_token",T.id_token||"",{path:_()||"/",httpOnly:!1,expires:new Date(P)}))}else r.warn(`OIDC introspect error: ${y.statusText}`)}if(R(e,"authorization",g,{path:_()||"/",httpOnly:!0,expires:new Date(P)}),g!==l.id_token&&R(e,"idp_id_token",l.id_token||"",{path:_()||"/",httpOnly:!0,expires:new Date(P)}),R(e,"idp_access_token",l.access_token||"",{path:_()||"/",httpOnly:!0,expires:new Date(P)}),b(e,"code_verifier",{path:_()||"/"}),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(O.MCP_CALLBACK)){const M=`${e.req.url.split("?")[0].replace(O.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:M})}const K=typeof o.redirectTo=="string"?o.redirectTo:void 0;let J=z(new URL(K||"/",e.req.url).pathname);const V=e.newResponse(null,302,{Location:J});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),V}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const L="Something went wrong";return r.error(`OIDC login error: ${L}`),t&&k.sendMcpAuthorizationFailedMessage([{...A(c),error:L,error_details:null}]),e.text(L,500)}}function be(i){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=i.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return $(t)||b(e,"authorization",{path:_()||"/"}),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const s=(await N(o,t)).end_session_endpoint;if(s){const d=new URL(e.req.url),L=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${L}://${p}`,h=j(u),C=h?me(JSON.stringify({branch:j(u)})):void 0,w=h?`${pe(u)}/${Z}/logout`:`${u}${I(O.POST_LOGOUT)}`;c=ce(s,w,e.get("cookies")?.idp_id_token||e.get("cookies")?.authorization||"",C)}}return r.info("Logout successful"),b(e,"authorization",{path:_()||"/"}),e.newResponse(null,302,{Location:c||I("/")})}}function qe(i){return async e=>{const r=i.getConfig().access?.logoutReturnUrl,a=r||I("/");return e.newResponse(null,302,{Location:a})}}function Ee(i){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=H.BH_API_URL,m=(t,c,s)=>t&&c?`${t} ${c.charAt(0)}`:s;try{if(!o)throw new Error("BH_API_URL is not set");const t=i.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(I("/"));const c=await fetch(`${o}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(I("/"))):(r.error("Invite error",await c.text()),e.redirect(I("/")));const s=await c.json(),d=new URL(I("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",s.organization.name),d.searchParams.set("invitedBy",m(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Fe(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||o.host,s=`${t}://${c}`;let d=o.searchParams.get("idpId");const L=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const E=G(L||void 0);k.sendMcpAuthorizationFailedMessage([{...A(E),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const w=he({localePrefixParam:o.searchParams.get("localePrefix"),l10n:i.getGlobalData()?.l10n}),l=d&&a?await x(d,a[d]):void 0,f={};for(const g of Object.keys(l?.extraParams||{}))f[g]=o.searchParams.get(g)||l?.extraParams?.[g]||void 0;let S,n={};if(h&&u&&l&&l.type===X.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=ge("",{...l,extraParams:f},L,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:w});S=g.loginUrl,n=g.cookies||{}}else if(l){const g=oe({...l,extraParams:f},s,L,m,w);S=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{R(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:S||new URL(e.req.url).pathname})}}function Be(i){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=ne(o),{success:c,uid:s,nameFormat:d,attrs:L,issuerId:p,expiresAt:u}=ie(t),{idpId:h,redirectTo:C}=JSON.parse(m);if(!c){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const w=i.getConfig().ssoDirect?.[h];if(!w||!ee(w)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(w.issuerId&&p&&W(w.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await ae(t,w.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=te(s,d,L,w.teamsAttributeName);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const S=await D.sign({...f,idpId:h},U,v.HS256);return R(e,"authorization",S,{path:_()||"/",httpOnly:!0,expires:new Date(u*1e3)}),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:C||"/"})}}function ze(i){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=I(z(a.pathname)),m=i.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,C])=>$(C)&&ue(C));if(!(m&&t))return e.newResponse(null,302,{Location:o});const s=e.req.query("token"),d=s&&await le(s);if(!d)return e.newResponse(null,302,{Location:o});if(!q(d[F]||[]).some(C=>C===Y||C===Q))return e.newResponse(null,302,{Location:o});const u=await D.sign({...d,idpId:t?.at(0)},U,v.HS256),h=Date.now()+B*1e3;return R(e,"authorization",u,{path:_()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ue as authorizeHandler,Fe as idpLoginHandler,Ee as inviteHandler,be as logoutHandler,Te as oidcCallbackHandler,qe as postLogoutHandler,$e as redoclyLoginCallbackHandler,ze as redoclyTokenLoginHandler,Be as samlCallbackHandler};
1
+ import{setCookie as y,deleteCookie as X}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as L,getPathPrefix as O}from"@redocly/theme/core/utils";import{compareURIs as Y}from"../../../utils/url/compare-uris.js";import{ensureArray as b}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as N,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as x}from"../../constants/common.js";import{AUTH_SEGMENT as ee,AuthCookieNames as A,DEFAULT_COOKIE_EXPIRATION as F,ServerRoutes as S}from"../../../constants/common.js";import{sanitizeRedirectPathname as H}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as B}from"../../config/env-config.js";import{clearAuthCookies as j}from"../../utils/cookie.js";import{getAuthProviderLoginParams as re,isOidcProviderConfig as $,isSaml2ProviderConfig as oe,oidcExchangeCodeForToken as ne,buildLoginUrl as te,decodeSamlResponse as se,extractUserClaims as ie,parseSamlResponse as ae,parseOidcState as de,verifySAMLResponse as ce,getUsernameFromPayload as le,buildOidcLogoutUrl as ue,getOidcMetadata as K,getRedoclyTokenPayload as pe,isRedoclySso as ge,rewritePreviewAuthRedirectUri as fe,parsePreviewBranch as z,buildOidcLoginUrl as me,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as he}from"../utils.js";import{encodeBase64URL as Ie}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as we}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ee(s){if(B.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,U.HS256);return y(s,A.AUTHORIZATION,a,{path:O()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),s.newResponse(null,200,{})}function be(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function G(s){if(!s||!s.includes(S.MCP_CALLBACK))return null;try{const e=s.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 qe(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=de(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(S.MCP_CALLBACK),c=t?G(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!$(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await K(m,i);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),he(e,s,{slug:"/"},403,"403OIDC");if(!u){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const R=typeof o.redirectUri=="string"?o.redirectUri:new URL(L(S.OIDC_CALLBACK),e.req.url).toString(),I=e.get("cookies")?.code_verifier,l=await ne(p,u,R,i,{...i.tokenRequestCustomParams,...I?{code_verifier:I}:{}});if(l.error)return r.error(`Error from OIDC provider: "${l.error}"`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`Token exchange error: ${l.error}`,error_details:l.error_description||null}]),e.text(`Forbidden: ${l.error_description||l.error}`,403);if(!l?.id_token){const w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:f,header:M}=k.decode(l.id_token),n=M.alg===U.RS256;if(i.audience?.length&&![...b(f.aud||[]),...b(f[N]||[])].some(_=>i.audience?.includes(_))){const _="No valid audience found in id_token";return r.error(`OIDC login error: ${_}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:_,error_details:null}]),new Response(`Forbidden: ${_}`)}const g=n?l.id_token:await k.sign({...f,idpId:m},v,U.HS256);le(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const P=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+F*1e3;if(i.introspectEndpoint){const w=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(w.ok){const E=(await w.json()).ext?.federatedIdentity;E&&(y(e,A.FEDERATED_ACCESS_TOKEN,E.access_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(P)}),y(e,A.FEDERATED_ID_TOKEN,E.id_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(P)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(y(e,A.AUTHORIZATION,g,{path:O()||"/",httpOnly:!0,expires:new Date(P)}),g!==l.id_token&&y(e,A.IDP_ID_TOKEN,l.id_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(P)}),y(e,A.IDP_ACCESS_TOKEN,l.access_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(P)}),X(e,"code_verifier",{path:O()||"/"}),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(S.MCP_CALLBACK)){const _=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:_})}const J=typeof o.redirectTo=="string"?o.redirectTo:void 0;let Z=H(new URL(J||"/",e.req.url).pathname);const V=e.newResponse(null,302,{Location:Z});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),V}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const C="Something went wrong";return r.error(`OIDC login error: ${C}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:C,error_details:null}]),e.text(C,500)}}function Ne(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return $(t)||j(e),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const i=(await K(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),C=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${C}://${p}`,h=z(u),R=h?Ie(JSON.stringify({branch:z(u)})):void 0,I=h?`${fe(u)}/${ee}/logout`:`${u}${L(S.POST_LOGOUT)}`;c=ue(i,I,e.get("cookies")?.[A.IDP_ID_TOKEN]||e.get("cookies")?.[A.AUTHORIZATION]||"",R)}}return r.info("Logout successful"),j(e),e.newResponse(null,302,{Location:c||L("/")})}}function Fe(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||L("/");return e.newResponse(null,302,{Location:a})}}function He(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=B.BH_API_URL,m=(t,c,i)=>t&&c?`${t} ${c.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(L("/"));const c=await fetch(`${o}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(L("/"))):(r.error("Invite error",await c.text()),e.redirect(L("/")));const i=await c.json(),d=new URL(L("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",i.organization.name),d.searchParams.set("invitedBy",m(i.invitedBy.firstName,i.invitedBy.lastName,i.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Be(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||o.host,i=`${t}://${c}`;let d=o.searchParams.get("idpId");const C=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const q=G(C||void 0);T.sendMcpAuthorizationFailedMessage([{...D(q),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const I=we({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await re(d,a[d]):void 0,f={};for(const g of Object.keys(l?.extraParams||{}))f[g]=o.searchParams.get(g)||l?.extraParams?.[g]||void 0;let M,n={};if(h&&u&&l&&l.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=me("",{...l,extraParams:f},C,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:I});M=g.loginUrl,n=g.cookies||{}}else if(l){const g=te({...l,extraParams:f},i,C,m,I);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{y(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function je(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=se(o),{success:c,uid:i,nameFormat:d,attrs:C,issuerId:p,expiresAt:u}=ae(t),{idpId:h,redirectTo:R}=JSON.parse(m);if(!c){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const I=s.getConfig().ssoDirect?.[h];if(!I||!oe(I)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(I.issuerId&&p&&Y(I.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await ce(t,I.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ie(i,d,C,I.teamsAttributeName);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,U.HS256);return y(e,A.AUTHORIZATION,M,{path:O()||"/",httpOnly:!0,expires:new Date(u*1e3)}),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:R||"/"})}}function Ke(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=L(H(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,R])=>$(R)&&ge(R));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await pe(i);if(!d)return e.newResponse(null,302,{Location:o});if(!b(d[N]||[]).some(R=>R===Q||R===x))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,U.HS256),h=Date.now()+F*1e3;return y(e,A.AUTHORIZATION,u,{path:O()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ee as authorizeHandler,Be as idpLoginHandler,He as inviteHandler,Ne as logoutHandler,qe as oidcCallbackHandler,Fe as postLogoutHandler,be as redoclyLoginCallbackHandler,Ke as redoclyTokenLoginHandler,je as samlCallbackHandler};
@@ -1,43 +1,43 @@
1
1
  export declare function createEntityRelationUpdateSchema(): {
2
- required: undefined;
3
- type: "object";
2
+ type: 'object';
4
3
  properties: {
5
4
  readonly type: {
6
- readonly type: "string";
5
+ readonly type: 'string';
7
6
  readonly enum: readonly ["partOf", "hasParts", "creates", "createdBy", "owns", "ownedBy", "implements", "implementedBy", "dependsOn", "dependencyOf", "uses", "usedBy", "produces", "consumes", "linksTo", "supersedes", "supersededBy", "compatibleWith", "extends", "extendedBy", "relatesTo", "hasMember", "memberOf", "triggers", "triggeredBy", "returns", "returnedBy"];
8
7
  };
9
8
  readonly sourceKey: {
10
- readonly type: "string";
9
+ readonly type: 'string';
11
10
  readonly minLength: 2;
12
11
  readonly maxLength: 150;
13
12
  };
14
13
  readonly targetKey: {
15
- readonly type: "string";
14
+ readonly type: 'string';
16
15
  readonly minLength: 2;
17
16
  readonly maxLength: 150;
18
17
  };
19
18
  readonly sourceVersion: {
20
- readonly type: readonly ["string", "null"];
19
+ readonly type: readonly ['string', 'null'];
21
20
  };
22
21
  readonly sourceRevision: {
23
- readonly type: readonly ["string", "null"];
22
+ readonly type: readonly ['string', 'null'];
24
23
  };
25
24
  readonly targetVersion: {
26
- readonly type: readonly ["string", "null"];
25
+ readonly type: readonly ['string', 'null'];
27
26
  };
28
27
  readonly targetRevision: {
29
- readonly type: readonly ["string", "null"];
28
+ readonly type: readonly ['string', 'null'];
30
29
  };
31
30
  readonly sourceFile: {
32
- readonly type: readonly ["string", "null"];
31
+ readonly type: readonly ['string', 'null'];
33
32
  };
34
33
  readonly fileHash: {
35
- readonly type: readonly ["string", "null"];
34
+ readonly type: readonly ['string', 'null'];
36
35
  };
37
36
  readonly isDeleted: {
38
- readonly type: readonly ["boolean", "null"];
37
+ readonly type: readonly ['boolean', 'null'];
39
38
  };
40
39
  };
41
40
  additionalProperties: false;
41
+ required: undefined;
42
42
  };
43
43
  //# sourceMappingURL=create-entity-relation-update-schema.d.ts.map