@backstage/backend-defaults 0.4.2-next.3 → 0.4.2

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 CHANGED
@@ -1,5 +1,37 @@
1
1
  # @backstage/backend-defaults
2
2
 
3
+ ## 0.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 0d16b52: Add access restrictions to the JWKS external access method config schema
8
+ - 93095ee: Make sure node-fetch is version 2.7.0 or greater
9
+ - 3b429fb: Added deprecation warning to urge users to perform the auth service migration or implement their own token manager service.
10
+ See https://backstage.io/docs/tutorials/auth-service-migration for more information.
11
+ - 7681b17: update the `morgan` middleware to use a custom format to prevent PII from being logged
12
+ - 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`.
13
+ - ba9abf4: The `SchedulerService` now allows tasks with `frequency: { trigger: 'manual' }`. This means that the task will not be scheduled, but rather run only when manually triggered with `SchedulerService.triggerTask`.
14
+ - 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens.
15
+ - 8e967da: Fixed the routing of the new health check service, the health endpoints should now properly be available at `/.backstage/health/v1/readiness` and `/.backstage/health/v1/liveness`.
16
+ - 7c5f3b0: Update the `UrlReader` service to depends on multiple instances of `UrlReaderFactoryProvider` service.
17
+ - 81f930a: use formatted query to prevent chance of SQL-injection
18
+ - 1d5f298: Avoid excessive numbers of error listeners on cache clients
19
+ - Updated dependencies
20
+ - @backstage/backend-app-api@0.9.0
21
+ - @backstage/backend-plugin-api@0.8.0
22
+ - @backstage/backend-common@0.24.0
23
+ - @backstage/config-loader@1.9.0
24
+ - @backstage/plugin-auth-node@0.5.0
25
+ - @backstage/plugin-permission-node@0.8.1
26
+ - @backstage/backend-dev-utils@0.1.5
27
+ - @backstage/integration@1.14.0
28
+ - @backstage/cli-common@0.1.14
29
+ - @backstage/config@1.2.0
30
+ - @backstage/errors@1.2.4
31
+ - @backstage/integration-aws-node@0.1.12
32
+ - @backstage/types@1.1.1
33
+ - @backstage/plugin-events-node@0.3.9
34
+
3
35
  ## 0.4.2-next.3
4
36
 
5
37
  ### Patch Changes
package/auth/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__auth",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/auth.cjs.js",
5
5
  "types": "../dist/auth.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__cache",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/cache.cjs.js",
5
5
  "types": "../dist/cache.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__database",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/database.cjs.js",
5
5
  "types": "../dist/database.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__discovery",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/discovery.cjs.js",
5
5
  "types": "../dist/discovery.d.ts"
6
6
  }
package/dist/auth.cjs.js CHANGED
@@ -11,7 +11,7 @@ var luxon = require('luxon');
11
11
  var fs = require('fs');
12
12
 
13
13
  class DefaultAuthService {
14
- constructor(userTokenHandler, pluginTokenHandler, externalTokenHandler, tokenManager, pluginId, disableDefaultAuthPolicy, pluginKeySource) {
14
+ constructor(userTokenHandler, pluginTokenHandler, externalTokenHandler, tokenManager, pluginId, disableDefaultAuthPolicy, pluginKeySource, logger) {
15
15
  this.userTokenHandler = userTokenHandler;
16
16
  this.pluginTokenHandler = pluginTokenHandler;
17
17
  this.externalTokenHandler = externalTokenHandler;
@@ -19,6 +19,7 @@ class DefaultAuthService {
19
19
  this.pluginId = pluginId;
20
20
  this.disableDefaultAuthPolicy = disableDefaultAuthPolicy;
21
21
  this.pluginKeySource = pluginKeySource;
22
+ this.logger = logger;
22
23
  }
23
24
  async authenticate(token, options) {
24
25
  const pluginResult = await this.pluginTokenHandler.verifyToken(token);
@@ -93,6 +94,9 @@ class DefaultAuthService {
93
94
  targetPluginId
94
95
  });
95
96
  }
97
+ this.logger.warn(
98
+ `DEPRECATION WARNING: A call to the '${targetPluginId}' plugin had to fall back to using deprecated auth via the token manager service. Please migrate all plugins to the new auth service, see https://backstage.io/docs/tutorials/auth-service-migration for more information`
99
+ );
96
100
  return this.tokenManager.getToken().catch((error) => {
97
101
  throw new errors.ForwardedError(
98
102
  `Unable to generate legacy token for communication with the '${targetPluginId}' plugin. You will typically encounter this error when attempting to call a plugin that does not exist, or is deployed with an old version of Backstage`,
@@ -1016,7 +1020,8 @@ const authServiceFactory = backendPluginApi.createServiceFactory({
1016
1020
  tokenManager,
1017
1021
  plugin.getId(),
1018
1022
  disableDefaultAuthPolicy,
1019
- keySource
1023
+ keySource,
1024
+ logger
1020
1025
  );
1021
1026
  }
1022
1027
  });
@@ -1 +1 @@
1
- {"version":3,"file":"auth.cjs.js","sources":["../src/entrypoints/auth/DefaultAuthService.ts","../src/entrypoints/auth/external/helpers.ts","../src/entrypoints/auth/external/legacy.ts","../src/entrypoints/auth/external/static.ts","../src/entrypoints/auth/external/jwks.ts","../src/entrypoints/auth/external/ExternalTokenHandler.ts","../src/entrypoints/auth/JwksClient.ts","../src/entrypoints/auth/plugin/PluginTokenHandler.ts","../src/entrypoints/auth/plugin/keys/DatabaseKeyStore.ts","../src/entrypoints/auth/plugin/keys/DatabasePluginKeySource.ts","../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts","../src/entrypoints/auth/plugin/keys/createPluginKeySource.ts","../src/entrypoints/auth/user/UserTokenHandler.ts","../src/entrypoints/auth/authServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TokenManager } from '@backstage/backend-common';\nimport {\n AuthService,\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalTypes,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\nimport { AuthenticationError, ForwardedError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport { decodeJwt } from 'jose';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport {\n createCredentialsWithNonePrincipal,\n createCredentialsWithServicePrincipal,\n createCredentialsWithUserPrincipal,\n toInternalBackstageCredentials,\n} from './helpers';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { PluginKeySource } from './plugin/keys/types';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/** @internal */\nexport class DefaultAuthService implements AuthService {\n constructor(\n private readonly userTokenHandler: UserTokenHandler,\n private readonly pluginTokenHandler: PluginTokenHandler,\n private readonly externalTokenHandler: ExternalTokenHandler,\n private readonly tokenManager: TokenManager,\n private readonly pluginId: string,\n private readonly disableDefaultAuthPolicy: boolean,\n private readonly pluginKeySource: PluginKeySource,\n ) {}\n\n async authenticate(\n token: string,\n options?: {\n allowLimitedAccess?: boolean;\n },\n ): Promise<BackstageCredentials> {\n const pluginResult = await this.pluginTokenHandler.verifyToken(token);\n if (pluginResult) {\n if (pluginResult.limitedUserToken) {\n const userResult = await this.userTokenHandler.verifyToken(\n pluginResult.limitedUserToken,\n );\n if (!userResult) {\n throw new AuthenticationError(\n 'Invalid user token in plugin token obo claim',\n );\n }\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n pluginResult.limitedUserToken,\n this.#getJwtExpiration(pluginResult.limitedUserToken),\n );\n }\n return createCredentialsWithServicePrincipal(pluginResult.subject);\n }\n\n const userResult = await this.userTokenHandler.verifyToken(token);\n if (userResult) {\n if (\n !options?.allowLimitedAccess &&\n this.userTokenHandler.isLimitedUserToken(token)\n ) {\n throw new AuthenticationError('Illegal limited user token');\n }\n\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n token,\n this.#getJwtExpiration(token),\n );\n }\n\n const externalResult = await this.externalTokenHandler.verifyToken(token);\n if (externalResult) {\n return createCredentialsWithServicePrincipal(\n externalResult.subject,\n undefined,\n externalResult.accessRestrictions,\n );\n }\n\n throw new AuthenticationError('Illegal token');\n }\n\n isPrincipal<TType extends keyof BackstagePrincipalTypes>(\n credentials: BackstageCredentials,\n type: TType,\n ): credentials is BackstageCredentials<BackstagePrincipalTypes[TType]> {\n const principal = credentials.principal as\n | BackstageUserPrincipal\n | BackstageServicePrincipal;\n\n if (type === 'unknown') {\n return true;\n }\n\n if (principal.type !== type) {\n return false;\n }\n\n return true;\n }\n\n async getNoneCredentials(): Promise<\n BackstageCredentials<BackstageNonePrincipal>\n > {\n return createCredentialsWithNonePrincipal();\n }\n\n async getOwnServiceCredentials(): Promise<\n BackstageCredentials<BackstageServicePrincipal>\n > {\n return createCredentialsWithServicePrincipal(`plugin:${this.pluginId}`);\n }\n\n async getPluginRequestToken(options: {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n }): Promise<{ token: string }> {\n const { targetPluginId } = options;\n const internalForward = toInternalBackstageCredentials(options.onBehalfOf);\n const { type } = internalForward.principal;\n\n // Since disabling the default policy means we'll be allowing\n // unauthenticated requests through, we might have unauthenticated\n // credentials from service calls that reach this point. If that's the case,\n // we'll want to keep \"forwarding\" the unauthenticated credentials, which we\n // do by returning an empty token.\n if (type === 'none' && this.disableDefaultAuthPolicy) {\n return { token: '' };\n }\n\n const targetSupportsNewAuth =\n await this.pluginTokenHandler.isTargetPluginSupported(targetPluginId);\n\n // check whether a plugin support the new auth system\n // by checking the public keys endpoint existance.\n switch (type) {\n // TODO: Check whether the principal is ourselves\n case 'service':\n if (targetSupportsNewAuth) {\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n });\n }\n // If the target plugin does not support the new auth service, fall back to using old token format\n return this.tokenManager.getToken().catch(error => {\n throw new ForwardedError(\n `Unable to generate legacy token for communication with the '${targetPluginId}' plugin. ` +\n `You will typically encounter this error when attempting to call a plugin that does not exist, or is deployed with an old version of Backstage`,\n error,\n );\n });\n case 'user': {\n const { token } = internalForward;\n if (!token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n // If the target plugin supports the new auth service we issue a service\n // on-behalf-of token rather than forwarding the user token\n if (targetSupportsNewAuth) {\n const onBehalfOf = await this.userTokenHandler.createLimitedUserToken(\n token,\n );\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n onBehalfOf,\n });\n }\n\n if (this.userTokenHandler.isLimitedUserToken(token)) {\n throw new AuthenticationError(\n `Unable to call '${targetPluginId}' plugin on behalf of user, because the target plugin does not support on-behalf-of tokens or the plugin doesn't exist`,\n );\n }\n return { token };\n }\n default:\n throw new AuthenticationError(\n `Refused to issue service token for credential type '${type}'`,\n );\n }\n }\n\n async getLimitedUserToken(\n credentials: BackstageCredentials<BackstageUserPrincipal>,\n ): Promise<{ token: string; expiresAt: Date }> {\n const { token: backstageToken } =\n toInternalBackstageCredentials(credentials);\n if (!backstageToken) {\n throw new AuthenticationError(\n 'User credentials is unexpectedly missing token',\n );\n }\n\n return this.userTokenHandler.createLimitedUserToken(backstageToken);\n }\n\n async listPublicServiceKeys(): Promise<{ keys: JsonObject[] }> {\n const { keys } = await this.pluginKeySource.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n\n #getJwtExpiration(token: string) {\n const { exp } = decodeJwt(token);\n if (!exp) {\n throw new AuthenticationError('User token is missing expiration');\n }\n return new Date(exp * 1000);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { AccessRestriptionsMap } from './types';\n\n/**\n * Parses and returns the `accessRestrictions` configuration from an\n * `externalAccess` entry, or undefined if there wasn't one.\n *\n * @internal\n */\nexport function readAccessRestrictionsFromConfig(\n externalAccessEntryConfig: Config,\n): AccessRestriptionsMap | undefined {\n const configs =\n externalAccessEntryConfig.getOptionalConfigArray('accessRestrictions') ??\n [];\n\n const result: AccessRestriptionsMap = new Map();\n for (const config of configs) {\n const validKeys = ['plugin', 'permission', 'permissionAttribute'];\n for (const key of config.keys()) {\n if (!validKeys.includes(key)) {\n const valid = validKeys.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid key '${key}' in 'accessRestrictions' config, expected one of ${valid}`,\n );\n }\n }\n\n const pluginId = config.getString('plugin');\n const permissionNames = readPermissionNames(config);\n const permissionAttributes = readPermissionAttributes(config);\n\n if (result.has(pluginId)) {\n throw new Error(\n `Attempted to declare 'accessRestrictions' twice for plugin '${pluginId}', which is not permitted`,\n );\n }\n\n result.set(pluginId, {\n ...(permissionNames ? { permissionNames } : {}),\n ...(permissionAttributes ? { permissionAttributes } : {}),\n });\n }\n\n return result.size ? result : undefined;\n}\n\n/**\n * Reads a config value as a string or an array of strings, and deduplicates and\n * splits by comma/space into a string array. Can also validate against a known\n * set of values. Returns undefined if the key didn't exist or if the array\n * would have ended up being empty.\n *\n * @internal\n */\nexport function readStringOrStringArrayFromConfig<T extends string>(\n root: Config,\n key: string,\n validValues?: readonly T[],\n): T[] | undefined {\n if (!root.has(key)) {\n return undefined;\n }\n\n const rawValues = Array.isArray(root.get(key))\n ? root.getStringArray(key)\n : [root.getString(key)];\n\n const values = [\n ...new Set(\n rawValues\n .map(v => v.split(/[ ,]/))\n .flat()\n .filter(Boolean),\n ),\n ];\n\n if (!values.length) {\n return undefined;\n }\n\n if (validValues?.length) {\n for (const value of values) {\n if (!validValues.includes(value as T)) {\n const valid = validValues.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid value '${value}' at '${key}' in 'permissionAttributes' config, valid values are ${valid}`,\n );\n }\n }\n }\n\n return values as T[];\n}\n\nfunction readPermissionNames(externalAccessEntryConfig: Config) {\n return readStringOrStringArrayFromConfig(\n externalAccessEntryConfig,\n 'permission',\n );\n}\n\nfunction readPermissionAttributes(externalAccessEntryConfig: Config) {\n const config = externalAccessEntryConfig.getOptionalConfig(\n 'permissionAttribute',\n );\n if (!config) {\n return undefined;\n }\n\n const validKeys = ['action'];\n for (const key of config.keys()) {\n if (!validKeys.includes(key)) {\n const valid = validKeys.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid key '${key}' in 'permissionAttribute' config, expected ${valid}`,\n );\n }\n }\n\n const action = readStringOrStringArrayFromConfig(config, 'action', [\n 'create',\n 'read',\n 'update',\n 'delete',\n ]);\n\n const result = {\n ...(action ? { action } : {}),\n };\n\n return Object.keys(result).length ? result : undefined;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { base64url, decodeJwt, decodeProtectedHeader, jwtVerify } from 'jose';\nimport { readAccessRestrictionsFromConfig } from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\n/**\n * Handles `type: legacy` access.\n *\n * @internal\n */\nexport class LegacyTokenHandler implements TokenHandler {\n #entries = new Array<{\n key: Uint8Array;\n result: {\n subject: string;\n allAccessRestrictions?: AccessRestriptionsMap;\n };\n }>();\n\n add(config: Config) {\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n this.#doAdd(\n config.getString('options.secret'),\n config.getString('options.subject'),\n allAccessRestrictions,\n );\n }\n\n // used only for the old backend.auth.keys array\n addOld(config: Config) {\n // This choice of subject is for compatibility reasons\n this.#doAdd(config.getString('secret'), 'external:backstage-plugin');\n }\n\n #doAdd(\n secret: string,\n subject: string,\n allAccessRestrictions?: AccessRestriptionsMap,\n ) {\n if (!secret.match(/^\\S+$/)) {\n throw new Error('Illegal secret, must be a valid base64 string');\n } else if (!subject.match(/^\\S+$/)) {\n throw new Error('Illegal subject, must be a set of non-space characters');\n }\n\n let key: Uint8Array;\n try {\n key = base64url.decode(secret);\n } catch {\n throw new Error('Illegal secret, must be a valid base64 string');\n }\n\n if (this.#entries.some(e => e.key === key)) {\n throw new Error(\n 'Legacy externalAccess token was declared more than once',\n );\n }\n\n this.#entries.push({\n key,\n result: {\n subject,\n allAccessRestrictions,\n },\n });\n }\n\n async verifyToken(token: string) {\n // First do a duck typing check to see if it remotely looks like a legacy token\n try {\n // We do a fair amount of checking upfront here. Since we aren't certain\n // that it's even the right type of key that we're looking at, we can't\n // defer eg the alg check to jwtVerify, because it won't be possible to\n // discern different reasons for key verification failures from each other\n // easily\n const { alg } = decodeProtectedHeader(token);\n if (alg !== 'HS256') {\n return undefined;\n }\n const { sub, aud } = decodeJwt(token);\n if (sub !== 'backstage-server' || aud) {\n return undefined;\n }\n } catch (e) {\n // Doesn't look like a jwt at all\n return undefined;\n }\n\n for (const { key, result } of this.#entries) {\n try {\n await jwtVerify(token, key);\n return result;\n } catch (e) {\n if (e.code !== 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED') {\n throw e;\n }\n // Otherwise continue to try the next key\n }\n }\n\n // None of the signing keys matched\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { readAccessRestrictionsFromConfig } from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\nconst MIN_TOKEN_LENGTH = 8;\n\n/**\n * Handles `type: static` access.\n *\n * @internal\n */\nexport class StaticTokenHandler implements TokenHandler {\n #entries = new Map<\n string,\n {\n subject: string;\n allAccessRestrictions?: AccessRestriptionsMap;\n }\n >();\n\n add(config: Config) {\n const token = config.getString('options.token');\n const subject = config.getString('options.subject');\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n\n if (!token.match(/^\\S+$/)) {\n throw new Error('Illegal token, must be a set of non-space characters');\n } else if (token.length < MIN_TOKEN_LENGTH) {\n throw new Error(\n `Illegal token, must be at least ${MIN_TOKEN_LENGTH} characters length`,\n );\n } else if (!subject.match(/^\\S+$/)) {\n throw new Error('Illegal subject, must be a set of non-space characters');\n } else if (this.#entries.has(token)) {\n throw new Error(\n 'Static externalAccess token was declared more than once',\n );\n }\n\n this.#entries.set(token, { subject, allAccessRestrictions });\n }\n\n async verifyToken(token: string) {\n return this.#entries.get(token);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { jwtVerify, createRemoteJWKSet, JWTVerifyGetKey } from 'jose';\nimport { Config } from '@backstage/config';\nimport {\n readAccessRestrictionsFromConfig,\n readStringOrStringArrayFromConfig,\n} from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\n/**\n * Handles `type: jwks` access.\n *\n * @internal\n */\nexport class JWKSHandler implements TokenHandler {\n #entries: Array<{\n algorithms?: string[];\n audiences?: string[];\n issuers?: string[];\n subjectPrefix?: string;\n url: URL;\n jwks: JWTVerifyGetKey;\n allAccessRestrictions?: AccessRestriptionsMap;\n }> = [];\n\n add(config: Config) {\n if (!config.getString('options.url').match(/^\\S+$/)) {\n throw new Error(\n 'Illegal JWKS URL, must be a set of non-space characters',\n );\n }\n\n const algorithms = readStringOrStringArrayFromConfig(\n config,\n 'options.algorithm',\n );\n const issuers = readStringOrStringArrayFromConfig(config, 'options.issuer');\n const audiences = readStringOrStringArrayFromConfig(\n config,\n 'options.audience',\n );\n const subjectPrefix = config.getOptionalString('options.subjectPrefix');\n const url = new URL(config.getString('options.url'));\n const jwks = createRemoteJWKSet(url);\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n\n this.#entries.push({\n algorithms,\n audiences,\n issuers,\n jwks,\n subjectPrefix,\n url,\n allAccessRestrictions,\n });\n }\n\n async verifyToken(token: string) {\n for (const entry of this.#entries) {\n try {\n const {\n payload: { sub },\n } = await jwtVerify(token, entry.jwks, {\n algorithms: entry.algorithms,\n issuer: entry.issuers,\n audience: entry.audiences,\n });\n\n if (sub) {\n const prefix = entry.subjectPrefix\n ? `external:${entry.subjectPrefix}:`\n : 'external:';\n return {\n subject: `${prefix}${sub}`,\n allAccessRestrictions: entry.allAccessRestrictions,\n };\n }\n } catch {\n continue;\n }\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackstagePrincipalAccessRestrictions,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { LegacyTokenHandler } from './legacy';\nimport { StaticTokenHandler } from './static';\nimport { JWKSHandler } from './jwks';\nimport { TokenHandler } from './types';\n\nconst NEW_CONFIG_KEY = 'backend.auth.externalAccess';\nconst OLD_CONFIG_KEY = 'backend.auth.keys';\nlet loggedDeprecationWarning = false;\n\n/**\n * Handles all types of external caller token types (i.e. not Backstage user\n * tokens, nor Backstage backend plugin tokens).\n *\n * @internal\n */\nexport class ExternalTokenHandler {\n static create(options: {\n ownPluginId: string;\n config: RootConfigService;\n logger: LoggerService;\n }): ExternalTokenHandler {\n const { ownPluginId, config, logger } = options;\n\n const staticHandler = new StaticTokenHandler();\n const legacyHandler = new LegacyTokenHandler();\n const jwksHandler = new JWKSHandler();\n const handlers: Record<string, TokenHandler> = {\n static: staticHandler,\n legacy: legacyHandler,\n jwks: jwksHandler,\n };\n\n // Load the new-style handlers\n const handlerConfigs = config.getOptionalConfigArray(NEW_CONFIG_KEY) ?? [];\n for (const handlerConfig of handlerConfigs) {\n const type = handlerConfig.getString('type');\n const handler = handlers[type];\n if (!handler) {\n const valid = Object.keys(handlers)\n .map(k => `'${k}'`)\n .join(', ');\n throw new Error(\n `Unknown type '${type}' in ${NEW_CONFIG_KEY}, expected one of ${valid}`,\n );\n }\n handler.add(handlerConfig);\n }\n\n // Load the old keys too\n const legacyConfigs = config.getOptionalConfigArray(OLD_CONFIG_KEY) ?? [];\n if (legacyConfigs.length && !loggedDeprecationWarning) {\n loggedDeprecationWarning = true;\n logger.warn(\n `DEPRECATION WARNING: The ${OLD_CONFIG_KEY} config has been replaced by ${NEW_CONFIG_KEY}, see https://backstage.io/docs/auth/service-to-service-auth`,\n );\n }\n for (const handlerConfig of legacyConfigs) {\n legacyHandler.addOld(handlerConfig);\n }\n\n return new ExternalTokenHandler(ownPluginId, Object.values(handlers));\n }\n\n constructor(\n private readonly ownPluginId: string,\n private readonly handlers: TokenHandler[],\n ) {}\n\n async verifyToken(token: string): Promise<\n | {\n subject: string;\n accessRestrictions?: BackstagePrincipalAccessRestrictions;\n }\n | undefined\n > {\n for (const handler of this.handlers) {\n const result = await handler.verifyToken(token);\n if (result) {\n const { allAccessRestrictions, ...rest } = result;\n if (allAccessRestrictions) {\n const accessRestrictions = allAccessRestrictions.get(\n this.ownPluginId,\n );\n if (!accessRestrictions) {\n const valid = [...allAccessRestrictions.keys()]\n .map(k => `'${k}'`)\n .join(', ');\n throw new NotAllowedError(\n `This token's access is restricted to plugin(s) ${valid}`,\n );\n }\n\n return {\n ...rest,\n accessRestrictions,\n };\n }\n\n return rest;\n }\n }\n\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\n\nconst CLOCK_MARGIN_S = 10;\n\nexport class JwksClient {\n #keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;\n #keyStoreUpdated: number = 0;\n\n constructor(private readonly getEndpoint: () => Promise<URL>) {}\n\n get getKey() {\n if (!this.#keyStore) {\n throw new AuthenticationError(\n 'refreshKeyStore must be called before jwksClient.getKey',\n );\n }\n return this.#keyStore;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n async refreshKeyStore(rawJwtToken: string): Promise<void> {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.#keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.#keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.#keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.#keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const endpoint = await this.getEndpoint();\n this.#keyStore = createRemoteJWKSet(endpoint);\n this.#keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api';\nimport { decodeJwt, importJWK, SignJWT, decodeProtectedHeader } from 'jose';\nimport { AuthenticationError } from '@backstage/errors';\nimport { jwtVerify } from 'jose';\nimport { tokenTypes } from '@backstage/plugin-auth-node';\nimport { JwksClient } from '../JwksClient';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { PluginKeySource } from './keys/types';\n\nconst SECONDS_IN_MS = 1000;\n\nconst ALLOWED_PLUGIN_ID_PATTERN = /^[a-z0-9_-]+$/i;\n\ntype Options = {\n ownPluginId: string;\n keyDuration: HumanDuration;\n keySource: PluginKeySource;\n discovery: DiscoveryService;\n logger: LoggerService;\n /**\n * JWS \"alg\" (Algorithm) Header Parameter value. Defaults to ES256.\n * Must match one of the algorithms defined for IdentityClient.\n * When setting a different algorithm, check if the `key` field\n * of the `signing_keys` table can fit the length of the generated keys.\n * If not, add a knex migration file in the migrations folder.\n * More info on supported algorithms: https://github.com/panva/jose\n */\n algorithm?: string;\n};\n\nexport class PluginTokenHandler {\n private jwksMap = new Map<string, JwksClient>();\n\n // Tracking state for isTargetPluginSupported\n private supportedTargetPlugins = new Set<string>();\n private targetPluginInflightChecks = new Map<string, Promise<boolean>>();\n\n static create(options: Options) {\n return new PluginTokenHandler(\n options.logger,\n options.ownPluginId,\n options.keySource,\n options.algorithm ?? 'ES256',\n Math.round(durationToMilliseconds(options.keyDuration) / 1000),\n options.discovery,\n );\n }\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly ownPluginId: string,\n private readonly keySource: PluginKeySource,\n private readonly algorithm: string,\n private readonly keyDurationSeconds: number,\n private readonly discovery: DiscoveryService,\n ) {}\n\n async verifyToken(\n token: string,\n ): Promise<{ subject: string; limitedUserToken?: string } | undefined> {\n try {\n const { typ } = decodeProtectedHeader(token);\n if (typ !== tokenTypes.plugin.typParam) {\n return undefined;\n }\n } catch {\n return undefined;\n }\n\n const pluginId = String(decodeJwt(token).sub);\n if (!pluginId) {\n throw new AuthenticationError('Invalid plugin token: missing subject');\n }\n if (!ALLOWED_PLUGIN_ID_PATTERN.test(pluginId)) {\n throw new AuthenticationError(\n 'Invalid plugin token: forbidden subject format',\n );\n }\n\n const jwksClient = await this.getJwksClient(pluginId);\n await jwksClient.refreshKeyStore(token); // TODO(Rugvip): Refactor so that this isn't needed\n\n const { payload } = await jwtVerify<{ sub: string; obo?: string }>(\n token,\n jwksClient.getKey,\n {\n typ: tokenTypes.plugin.typParam,\n audience: this.ownPluginId,\n requiredClaims: ['iat', 'exp', 'sub', 'aud'],\n },\n ).catch(e => {\n throw new AuthenticationError('Invalid plugin token', e);\n });\n\n return { subject: `plugin:${payload.sub}`, limitedUserToken: payload.obo };\n }\n\n async issueToken(options: {\n pluginId: string;\n targetPluginId: string;\n onBehalfOf?: { token: string; expiresAt: Date };\n }): Promise<{ token: string }> {\n const { pluginId, targetPluginId, onBehalfOf } = options;\n const key = await this.keySource.getPrivateSigningKey();\n\n const sub = pluginId;\n const aud = targetPluginId;\n const iat = Math.floor(Date.now() / SECONDS_IN_MS);\n const ourExp = iat + this.keyDurationSeconds;\n const exp = onBehalfOf\n ? Math.min(\n ourExp,\n Math.floor(onBehalfOf.expiresAt.getTime() / SECONDS_IN_MS),\n )\n : ourExp;\n\n const claims = { sub, aud, iat, exp, obo: onBehalfOf?.token };\n const token = await new SignJWT(claims)\n .setProtectedHeader({\n typ: tokenTypes.plugin.typParam,\n alg: this.algorithm,\n kid: key.kid,\n })\n .setAudience(aud)\n .setSubject(sub)\n .setIssuedAt(iat)\n .setExpirationTime(exp)\n .sign(await importJWK(key));\n\n return { token };\n }\n\n async isTargetPluginSupported(targetPluginId: string): Promise<boolean> {\n if (this.supportedTargetPlugins.has(targetPluginId)) {\n return true;\n }\n const inFlight = this.targetPluginInflightChecks.get(targetPluginId);\n if (inFlight) {\n return inFlight;\n }\n\n const doCheck = async () => {\n try {\n const res = await fetch(\n `${await this.discovery.getBaseUrl(\n targetPluginId,\n )}/.backstage/auth/v1/jwks.json`,\n );\n if (res.status === 404) {\n return false;\n }\n\n if (!res.ok) {\n throw new Error(`Failed to fetch jwks.json, ${res.status}`);\n }\n\n const data = await res.json();\n if (!data.keys) {\n throw new Error(`Invalid jwks.json response, missing keys`);\n }\n\n this.supportedTargetPlugins.add(targetPluginId);\n return true;\n } catch (error) {\n this.logger.error('Unexpected failure for target JWKS check', error);\n return false;\n } finally {\n this.targetPluginInflightChecks.delete(targetPluginId);\n }\n };\n\n const check = doCheck();\n this.targetPluginInflightChecks.set(targetPluginId, check);\n return check;\n }\n\n private async getJwksClient(pluginId: string) {\n const client = this.jwksMap.get(pluginId);\n if (client) {\n return client;\n }\n\n // Double check that the target plugin has a valid JWKS endpoint, otherwise avoid creating a remote key set\n if (!(await this.isTargetPluginSupported(pluginId))) {\n throw new AuthenticationError(\n `Received a plugin token where the source '${pluginId}' plugin unexpectedly does not have a JWKS endpoint`,\n );\n }\n\n const newClient = new JwksClient(async () => {\n return new URL(\n `${await this.discovery.getBaseUrl(\n pluginId,\n )}/.backstage/auth/v1/jwks.json`,\n );\n });\n\n this.jwksMap.set(pluginId, newClient);\n return newClient;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { KeyStore } from './types';\n\nconst MIGRATIONS_TABLE = 'backstage_backend_public_keys__knex_migrations';\n\n/** @internal */\nexport const TABLE = 'backstage_backend_public_keys__keys';\n\ntype Row = {\n id: string;\n key: string;\n expires_at: string;\n};\n\nexport function applyDatabaseMigrations(knex: Knex): Promise<void> {\n const migrationsDir = resolvePackagePath(\n '@backstage/backend-defaults',\n 'migrations/auth',\n );\n\n return knex.migrate.latest({\n directory: migrationsDir,\n tableName: MIGRATIONS_TABLE,\n });\n}\n\n/** @internal */\nexport class DatabaseKeyStore implements KeyStore {\n static async create(options: {\n database: DatabaseService;\n logger: LoggerService;\n }) {\n const { database, logger } = options;\n\n const client = await database.getClient();\n if (!database.migrations?.skip) {\n await applyDatabaseMigrations(client);\n }\n return new DatabaseKeyStore(client, logger);\n }\n\n private constructor(\n private readonly client: Knex,\n private readonly logger: LoggerService,\n ) {}\n\n async addKey(options: {\n id: string;\n key: JsonObject & { kid: string };\n expiresAt: Date;\n }) {\n await this.client<Row>(TABLE).insert({\n id: options.key.kid,\n key: JSON.stringify(options.key),\n expires_at: options.expiresAt.toISOString(),\n });\n }\n\n async listKeys() {\n const rows = await this.client<Row>(TABLE).select();\n const keys = rows.map(row => ({\n id: row.id,\n key: JSON.parse(row.key),\n expiresAt: new Date(row.expires_at),\n }));\n\n const validKeys = [];\n const expiredKeys = [];\n\n for (const key of keys) {\n if (DateTime.fromJSDate(key.expiresAt) < DateTime.local()) {\n expiredKeys.push(key);\n } else {\n validKeys.push(key);\n }\n }\n\n // Lazily prune expired keys. This may cause duplicate removals if we have concurrent callers, but w/e\n if (expiredKeys.length > 0) {\n const kids = expiredKeys.map(({ key }) => key.kid);\n\n this.logger.info(\n `Removing expired plugin service keys, '${kids.join(\"', '\")}'`,\n );\n\n // We don't await this, just let it run in the background\n this.client<Row>(TABLE)\n .delete()\n .whereIn('id', kids)\n .catch(error => {\n this.logger.error(\n 'Failed to remove expired plugin service keys',\n error,\n );\n });\n }\n\n return { keys: validKeys };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { JWK, exportJWK, generateKeyPair } from 'jose';\nimport { v4 as uuid } from 'uuid';\nimport { DatabaseKeyStore } from './DatabaseKeyStore';\nimport { InternalKey, KeyPayload, KeyStore } from './types';\nimport { PluginKeySource } from './types';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * The margin for how many times longer we make the public key available\n * compared to how long we use the private key to sign new tokens.\n */\nconst KEY_EXPIRATION_MARGIN_FACTOR = 3;\n\nexport class DatabasePluginKeySource implements PluginKeySource {\n private privateKeyPromise?: Promise<JWK>;\n private keyExpiry?: Date;\n\n constructor(\n private readonly keyStore: KeyStore,\n private readonly logger: LoggerService,\n private readonly keyDurationSeconds: number,\n private readonly algorithm: string,\n ) {}\n\n public static async create(options: {\n logger: LoggerService;\n database: DatabaseService;\n keyDuration: HumanDuration;\n algorithm?: string;\n }): Promise<PluginKeySource> {\n const keyStore = await DatabaseKeyStore.create({\n database: options.database,\n logger: options.logger,\n });\n\n return new DatabasePluginKeySource(\n keyStore,\n options.logger,\n Math.round(durationToMilliseconds(options.keyDuration) / 1000),\n options.algorithm ?? 'ES256',\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n // Make sure that we only generate one key at a time\n if (this.privateKeyPromise) {\n if (this.keyExpiry && this.keyExpiry.getTime() > Date.now()) {\n return this.privateKeyPromise;\n }\n this.logger.info(`Signing key has expired, generating new key`);\n delete this.privateKeyPromise;\n }\n\n this.keyExpiry = new Date(\n Date.now() + this.keyDurationSeconds * SECONDS_IN_MS,\n );\n\n const promise = (async () => {\n // This generates a new signing key to be used to sign tokens until the next key rotation\n const kid = uuid();\n const key = await generateKeyPair(this.algorithm);\n const publicKey = await exportJWK(key.publicKey);\n const privateKey = await exportJWK(key.privateKey);\n publicKey.kid = privateKey.kid = kid;\n publicKey.alg = privateKey.alg = this.algorithm;\n\n // We're not allowed to use the key until it has been successfully stored\n // TODO: some token verification implementations aggressively cache the list of keys, and\n // don't attempt to fetch new ones even if they encounter an unknown kid. Therefore we\n // may want to keep using the existing key for some period of time until we switch to\n // the new one. This also needs to be implemented cross-service though, meaning new services\n // that boot up need to be able to grab an existing key to use for signing.\n this.logger.info(`Created new signing key ${kid}`);\n\n await this.keyStore.addKey({\n id: kid,\n key: publicKey as InternalKey,\n expiresAt: new Date(\n Date.now() +\n this.keyDurationSeconds *\n SECONDS_IN_MS *\n KEY_EXPIRATION_MARGIN_FACTOR,\n ),\n });\n\n // At this point we are allowed to start using the new key\n return privateKey;\n })();\n\n this.privateKeyPromise = promise;\n\n try {\n // If we fail to generate a new key, we need to clear the state so that\n // the next caller will try to generate another key.\n await promise;\n } catch (error) {\n this.logger.error(`Failed to generate new signing key, ${error}`);\n delete this.keyExpiry;\n delete this.privateKeyPromise;\n }\n\n return promise;\n }\n\n listKeys(): Promise<{ keys: KeyPayload[] }> {\n return this.keyStore.listKeys();\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose/dist/types/types';\nimport { KeyPayload } from './types';\nimport { PluginKeySource } from './types';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey?: JWK;\n keyId: string;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile?: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * Key source that loads predefined public/private key pairs from disk.\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the `create` method.\n */\nexport class StaticConfigPluginKeySource implements PluginKeySource {\n private constructor(\n private readonly keyPairs: KeyPair[],\n private readonly keyDurationSeconds: number,\n ) {}\n\n public static async create(options: {\n sourceConfig: Config;\n keyDuration: HumanDuration;\n }): Promise<PluginKeySource> {\n const keyConfigs = options.sourceConfig\n .getConfigArray('static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getOptionalString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n if (keyPairs.length < 1) {\n throw new Error(\n 'At least one key pair must be provided in static.keys, when the static key store type is used',\n );\n } else if (!keyPairs[0].privateKey) {\n throw new Error(\n 'Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used',\n );\n }\n\n return new StaticConfigPluginKeySource(\n keyPairs,\n durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS,\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n return this.keyPairs[0].privateKey!;\n }\n\n async listKeys(): Promise<{ keys: KeyPayload[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return { keys };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise<KeyPair> {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = options.privateKeyFile\n ? await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n )\n : undefined;\n\n return { publicKey, privateKey, keyId };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise<KeyLike>,\n ): Promise<JWK> {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): KeyPayload {\n const publicKey = {\n ...keyPair.publicKey,\n kid: keyPair.keyId,\n };\n\n return {\n key: publicKey,\n id: keyPair.keyId,\n expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS),\n };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { HumanDuration } from '@backstage/types';\nimport { DatabasePluginKeySource } from './DatabasePluginKeySource';\nimport { StaticConfigPluginKeySource } from './StaticConfigPluginKeySource';\nimport { PluginKeySource } from './types';\n\nconst CONFIG_ROOT_KEY = 'backend.auth.pluginKeyStore';\n\nexport async function createPluginKeySource(options: {\n config: RootConfigService;\n database: DatabaseService;\n logger: LoggerService;\n keyDuration: HumanDuration;\n algorithm?: string;\n}): Promise<PluginKeySource> {\n const keyStoreConfig = options.config.getOptionalConfig(CONFIG_ROOT_KEY);\n const type = keyStoreConfig?.getOptionalString('type') ?? 'database';\n\n if (!keyStoreConfig || type === 'database') {\n return DatabasePluginKeySource.create({\n database: options.database,\n logger: options.logger,\n keyDuration: options.keyDuration,\n algorithm: options.algorithm,\n });\n } else if (type === 'static') {\n return StaticConfigPluginKeySource.create({\n sourceConfig: keyStoreConfig,\n keyDuration: options.keyDuration,\n });\n }\n\n throw new Error(\n `Unsupported config value ${CONFIG_ROOT_KEY}.type '${type}'; expected one of 'database', 'static'`,\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryService } from '@backstage/backend-plugin-api';\nimport { AuthenticationError } from '@backstage/errors';\nimport { tokenTypes } from '@backstage/plugin-auth-node';\nimport {\n base64url,\n decodeJwt,\n decodeProtectedHeader,\n jwtVerify,\n JWTVerifyOptions,\n} from 'jose';\nimport { JwksClient } from '../JwksClient';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @internal\n */\nexport class UserTokenHandler {\n static create(options: { discovery: DiscoveryService }): UserTokenHandler {\n const jwksClient = new JwksClient(async () => {\n const url = await options.discovery.getBaseUrl('auth');\n return new URL(`${url}/.well-known/jwks.json`);\n });\n return new UserTokenHandler(jwksClient);\n }\n\n constructor(private readonly jwksClient: JwksClient) {}\n\n async verifyToken(token: string) {\n const verifyOpts = this.#getTokenVerificationOptions(token);\n if (!verifyOpts) {\n return undefined;\n }\n\n await this.jwksClient.refreshKeyStore(token);\n\n // Verify a limited token, ensuring the necessarily claims are present and token type is correct\n const { payload } = await jwtVerify(\n token,\n this.jwksClient.getKey,\n verifyOpts,\n ).catch(e => {\n throw new AuthenticationError('Invalid token', e);\n });\n\n const userEntityRef = payload.sub;\n\n if (!userEntityRef) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n return { userEntityRef };\n }\n\n #getTokenVerificationOptions(token: string): JWTVerifyOptions | undefined {\n try {\n const { typ } = decodeProtectedHeader(token);\n\n if (typ === tokenTypes.user.typParam) {\n return {\n requiredClaims: ['iat', 'exp', 'sub'],\n typ: tokenTypes.user.typParam,\n };\n }\n\n if (typ === tokenTypes.limitedUser.typParam) {\n return {\n requiredClaims: ['iat', 'exp', 'sub'],\n typ: tokenTypes.limitedUser.typParam,\n };\n }\n\n const { aud } = decodeJwt(token);\n if (aud === tokenTypes.user.audClaim) {\n return {\n audience: tokenTypes.user.audClaim,\n };\n }\n } catch {\n /* ignore */\n }\n\n return undefined;\n }\n\n createLimitedUserToken(backstageToken: string) {\n const [headerRaw, payloadRaw] = backstageToken.split('.');\n const header = JSON.parse(\n new TextDecoder().decode(base64url.decode(headerRaw)),\n );\n const payload = JSON.parse(\n new TextDecoder().decode(base64url.decode(payloadRaw)),\n );\n\n const tokenType = header.typ;\n\n // Only new user tokens can be used to create a limited user token. If we\n // can't create a limited token, or the token is already a limited one, we\n // return the original token\n if (!tokenType || tokenType === tokenTypes.limitedUser.typParam) {\n return { token: backstageToken, expiresAt: new Date(payload.exp * 1000) };\n }\n\n if (tokenType !== tokenTypes.user.typParam) {\n throw new AuthenticationError(\n 'Failed to create limited user token, invalid token type',\n );\n }\n\n // NOTE: The order and properties in both the header and payload must match\n // the usage in plugins/auth-backend/src/identity/TokenFactory.ts\n const limitedUserToken = [\n base64url.encode(\n JSON.stringify({\n typ: tokenTypes.limitedUser.typParam,\n alg: header.alg,\n kid: header.kid,\n }),\n ),\n base64url.encode(\n JSON.stringify({\n sub: payload.sub,\n iat: payload.iat,\n exp: payload.exp,\n }),\n ),\n payload.uip,\n ].join('.');\n\n return { token: limitedUserToken, expiresAt: new Date(payload.exp * 1000) };\n }\n\n isLimitedUserToken(token: string): boolean {\n try {\n const { typ } = decodeProtectedHeader(token);\n return typ === tokenTypes.limitedUser.typParam;\n } catch {\n return false;\n }\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultAuthService } from './DefaultAuthService';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { createPluginKeySource } from './plugin/keys/createPluginKeySource';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/**\n * Handles token authentication and credentials management.\n *\n * See {@link @backstage/code-plugin-api#AuthService}\n * and {@link https://backstage.io/docs/backend-system/core-services/auth | the service docs}\n * for more information.\n *\n * @public\n */\nexport const authServiceFactory = createServiceFactory({\n service: coreServices.auth,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.rootLogger,\n discovery: coreServices.discovery,\n plugin: coreServices.pluginMetadata,\n database: coreServices.database,\n // Re-using the token manager makes sure that we use the same generated keys for\n // development as plugins that have not yet been migrated. It's important that this\n // keeps working as long as there are plugins that have not been migrated to the\n // new auth services in the new backend system.\n tokenManager: coreServices.tokenManager,\n },\n async factory({ config, discovery, plugin, tokenManager, logger, database }) {\n const disableDefaultAuthPolicy =\n config.getOptionalBoolean(\n 'backend.auth.dangerouslyDisableDefaultAuthPolicy',\n ) ?? false;\n\n const keyDuration = { hours: 1 };\n\n const keySource = await createPluginKeySource({\n config,\n database,\n logger,\n keyDuration,\n });\n\n const userTokens = UserTokenHandler.create({\n discovery,\n });\n\n const pluginTokens = PluginTokenHandler.create({\n ownPluginId: plugin.getId(),\n logger,\n keySource,\n keyDuration,\n discovery,\n });\n\n const externalTokens = ExternalTokenHandler.create({\n ownPluginId: plugin.getId(),\n config,\n logger,\n });\n\n return new DefaultAuthService(\n userTokens,\n pluginTokens,\n externalTokens,\n tokenManager,\n plugin.getId(),\n disableDefaultAuthPolicy,\n keySource,\n );\n },\n});\n"],"names":["userResult","AuthenticationError","createCredentialsWithUserPrincipal","createCredentialsWithServicePrincipal","createCredentialsWithNonePrincipal","toInternalBackstageCredentials","ForwardedError","decodeJwt","base64url","decodeProtectedHeader","jwtVerify","createRemoteJWKSet","NotAllowedError","SECONDS_IN_MS","durationToMilliseconds","tokenTypes","SignJWT","importJWK","resolvePackagePath","DateTime","uuid","generateKeyPair","exportJWK","importSPKI","importPKCS8","fs","createServiceFactory","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"auth.cjs.js","sources":["../src/entrypoints/auth/DefaultAuthService.ts","../src/entrypoints/auth/external/helpers.ts","../src/entrypoints/auth/external/legacy.ts","../src/entrypoints/auth/external/static.ts","../src/entrypoints/auth/external/jwks.ts","../src/entrypoints/auth/external/ExternalTokenHandler.ts","../src/entrypoints/auth/JwksClient.ts","../src/entrypoints/auth/plugin/PluginTokenHandler.ts","../src/entrypoints/auth/plugin/keys/DatabaseKeyStore.ts","../src/entrypoints/auth/plugin/keys/DatabasePluginKeySource.ts","../src/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.ts","../src/entrypoints/auth/plugin/keys/createPluginKeySource.ts","../src/entrypoints/auth/user/UserTokenHandler.ts","../src/entrypoints/auth/authServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { TokenManager } from '@backstage/backend-common';\nimport {\n AuthService,\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalTypes,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { AuthenticationError, ForwardedError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport { decodeJwt } from 'jose';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport {\n createCredentialsWithNonePrincipal,\n createCredentialsWithServicePrincipal,\n createCredentialsWithUserPrincipal,\n toInternalBackstageCredentials,\n} from './helpers';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { PluginKeySource } from './plugin/keys/types';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/** @internal */\nexport class DefaultAuthService implements AuthService {\n constructor(\n private readonly userTokenHandler: UserTokenHandler,\n private readonly pluginTokenHandler: PluginTokenHandler,\n private readonly externalTokenHandler: ExternalTokenHandler,\n private readonly tokenManager: TokenManager,\n private readonly pluginId: string,\n private readonly disableDefaultAuthPolicy: boolean,\n private readonly pluginKeySource: PluginKeySource,\n private readonly logger: LoggerService,\n ) {}\n\n async authenticate(\n token: string,\n options?: {\n allowLimitedAccess?: boolean;\n },\n ): Promise<BackstageCredentials> {\n const pluginResult = await this.pluginTokenHandler.verifyToken(token);\n if (pluginResult) {\n if (pluginResult.limitedUserToken) {\n const userResult = await this.userTokenHandler.verifyToken(\n pluginResult.limitedUserToken,\n );\n if (!userResult) {\n throw new AuthenticationError(\n 'Invalid user token in plugin token obo claim',\n );\n }\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n pluginResult.limitedUserToken,\n this.#getJwtExpiration(pluginResult.limitedUserToken),\n );\n }\n return createCredentialsWithServicePrincipal(pluginResult.subject);\n }\n\n const userResult = await this.userTokenHandler.verifyToken(token);\n if (userResult) {\n if (\n !options?.allowLimitedAccess &&\n this.userTokenHandler.isLimitedUserToken(token)\n ) {\n throw new AuthenticationError('Illegal limited user token');\n }\n\n return createCredentialsWithUserPrincipal(\n userResult.userEntityRef,\n token,\n this.#getJwtExpiration(token),\n );\n }\n\n const externalResult = await this.externalTokenHandler.verifyToken(token);\n if (externalResult) {\n return createCredentialsWithServicePrincipal(\n externalResult.subject,\n undefined,\n externalResult.accessRestrictions,\n );\n }\n\n throw new AuthenticationError('Illegal token');\n }\n\n isPrincipal<TType extends keyof BackstagePrincipalTypes>(\n credentials: BackstageCredentials,\n type: TType,\n ): credentials is BackstageCredentials<BackstagePrincipalTypes[TType]> {\n const principal = credentials.principal as\n | BackstageUserPrincipal\n | BackstageServicePrincipal;\n\n if (type === 'unknown') {\n return true;\n }\n\n if (principal.type !== type) {\n return false;\n }\n\n return true;\n }\n\n async getNoneCredentials(): Promise<\n BackstageCredentials<BackstageNonePrincipal>\n > {\n return createCredentialsWithNonePrincipal();\n }\n\n async getOwnServiceCredentials(): Promise<\n BackstageCredentials<BackstageServicePrincipal>\n > {\n return createCredentialsWithServicePrincipal(`plugin:${this.pluginId}`);\n }\n\n async getPluginRequestToken(options: {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n }): Promise<{ token: string }> {\n const { targetPluginId } = options;\n const internalForward = toInternalBackstageCredentials(options.onBehalfOf);\n const { type } = internalForward.principal;\n\n // Since disabling the default policy means we'll be allowing\n // unauthenticated requests through, we might have unauthenticated\n // credentials from service calls that reach this point. If that's the case,\n // we'll want to keep \"forwarding\" the unauthenticated credentials, which we\n // do by returning an empty token.\n if (type === 'none' && this.disableDefaultAuthPolicy) {\n return { token: '' };\n }\n\n const targetSupportsNewAuth =\n await this.pluginTokenHandler.isTargetPluginSupported(targetPluginId);\n\n // check whether a plugin support the new auth system\n // by checking the public keys endpoint existance.\n switch (type) {\n // TODO: Check whether the principal is ourselves\n case 'service':\n if (targetSupportsNewAuth) {\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n });\n }\n // If the target plugin does not support the new auth service, fall back to using old token format\n this.logger.warn(\n `DEPRECATION WARNING: A call to the '${targetPluginId}' plugin had to fall back to using deprecated auth via the token manager service. Please migrate all plugins to the new auth service, see https://backstage.io/docs/tutorials/auth-service-migration for more information`,\n );\n return this.tokenManager.getToken().catch(error => {\n throw new ForwardedError(\n `Unable to generate legacy token for communication with the '${targetPluginId}' plugin. ` +\n `You will typically encounter this error when attempting to call a plugin that does not exist, or is deployed with an old version of Backstage`,\n error,\n );\n });\n case 'user': {\n const { token } = internalForward;\n if (!token) {\n throw new Error('User credentials is unexpectedly missing token');\n }\n // If the target plugin supports the new auth service we issue a service\n // on-behalf-of token rather than forwarding the user token\n if (targetSupportsNewAuth) {\n const onBehalfOf = await this.userTokenHandler.createLimitedUserToken(\n token,\n );\n return this.pluginTokenHandler.issueToken({\n pluginId: this.pluginId,\n targetPluginId,\n onBehalfOf,\n });\n }\n\n if (this.userTokenHandler.isLimitedUserToken(token)) {\n throw new AuthenticationError(\n `Unable to call '${targetPluginId}' plugin on behalf of user, because the target plugin does not support on-behalf-of tokens or the plugin doesn't exist`,\n );\n }\n return { token };\n }\n default:\n throw new AuthenticationError(\n `Refused to issue service token for credential type '${type}'`,\n );\n }\n }\n\n async getLimitedUserToken(\n credentials: BackstageCredentials<BackstageUserPrincipal>,\n ): Promise<{ token: string; expiresAt: Date }> {\n const { token: backstageToken } =\n toInternalBackstageCredentials(credentials);\n if (!backstageToken) {\n throw new AuthenticationError(\n 'User credentials is unexpectedly missing token',\n );\n }\n\n return this.userTokenHandler.createLimitedUserToken(backstageToken);\n }\n\n async listPublicServiceKeys(): Promise<{ keys: JsonObject[] }> {\n const { keys } = await this.pluginKeySource.listKeys();\n return { keys: keys.map(({ key }) => key) };\n }\n\n #getJwtExpiration(token: string) {\n const { exp } = decodeJwt(token);\n if (!exp) {\n throw new AuthenticationError('User token is missing expiration');\n }\n return new Date(exp * 1000);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { AccessRestriptionsMap } from './types';\n\n/**\n * Parses and returns the `accessRestrictions` configuration from an\n * `externalAccess` entry, or undefined if there wasn't one.\n *\n * @internal\n */\nexport function readAccessRestrictionsFromConfig(\n externalAccessEntryConfig: Config,\n): AccessRestriptionsMap | undefined {\n const configs =\n externalAccessEntryConfig.getOptionalConfigArray('accessRestrictions') ??\n [];\n\n const result: AccessRestriptionsMap = new Map();\n for (const config of configs) {\n const validKeys = ['plugin', 'permission', 'permissionAttribute'];\n for (const key of config.keys()) {\n if (!validKeys.includes(key)) {\n const valid = validKeys.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid key '${key}' in 'accessRestrictions' config, expected one of ${valid}`,\n );\n }\n }\n\n const pluginId = config.getString('plugin');\n const permissionNames = readPermissionNames(config);\n const permissionAttributes = readPermissionAttributes(config);\n\n if (result.has(pluginId)) {\n throw new Error(\n `Attempted to declare 'accessRestrictions' twice for plugin '${pluginId}', which is not permitted`,\n );\n }\n\n result.set(pluginId, {\n ...(permissionNames ? { permissionNames } : {}),\n ...(permissionAttributes ? { permissionAttributes } : {}),\n });\n }\n\n return result.size ? result : undefined;\n}\n\n/**\n * Reads a config value as a string or an array of strings, and deduplicates and\n * splits by comma/space into a string array. Can also validate against a known\n * set of values. Returns undefined if the key didn't exist or if the array\n * would have ended up being empty.\n *\n * @internal\n */\nexport function readStringOrStringArrayFromConfig<T extends string>(\n root: Config,\n key: string,\n validValues?: readonly T[],\n): T[] | undefined {\n if (!root.has(key)) {\n return undefined;\n }\n\n const rawValues = Array.isArray(root.get(key))\n ? root.getStringArray(key)\n : [root.getString(key)];\n\n const values = [\n ...new Set(\n rawValues\n .map(v => v.split(/[ ,]/))\n .flat()\n .filter(Boolean),\n ),\n ];\n\n if (!values.length) {\n return undefined;\n }\n\n if (validValues?.length) {\n for (const value of values) {\n if (!validValues.includes(value as T)) {\n const valid = validValues.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid value '${value}' at '${key}' in 'permissionAttributes' config, valid values are ${valid}`,\n );\n }\n }\n }\n\n return values as T[];\n}\n\nfunction readPermissionNames(externalAccessEntryConfig: Config) {\n return readStringOrStringArrayFromConfig(\n externalAccessEntryConfig,\n 'permission',\n );\n}\n\nfunction readPermissionAttributes(externalAccessEntryConfig: Config) {\n const config = externalAccessEntryConfig.getOptionalConfig(\n 'permissionAttribute',\n );\n if (!config) {\n return undefined;\n }\n\n const validKeys = ['action'];\n for (const key of config.keys()) {\n if (!validKeys.includes(key)) {\n const valid = validKeys.map(k => `'${k}'`).join(', ');\n throw new Error(\n `Invalid key '${key}' in 'permissionAttribute' config, expected ${valid}`,\n );\n }\n }\n\n const action = readStringOrStringArrayFromConfig(config, 'action', [\n 'create',\n 'read',\n 'update',\n 'delete',\n ]);\n\n const result = {\n ...(action ? { action } : {}),\n };\n\n return Object.keys(result).length ? result : undefined;\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { base64url, decodeJwt, decodeProtectedHeader, jwtVerify } from 'jose';\nimport { readAccessRestrictionsFromConfig } from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\n/**\n * Handles `type: legacy` access.\n *\n * @internal\n */\nexport class LegacyTokenHandler implements TokenHandler {\n #entries = new Array<{\n key: Uint8Array;\n result: {\n subject: string;\n allAccessRestrictions?: AccessRestriptionsMap;\n };\n }>();\n\n add(config: Config) {\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n this.#doAdd(\n config.getString('options.secret'),\n config.getString('options.subject'),\n allAccessRestrictions,\n );\n }\n\n // used only for the old backend.auth.keys array\n addOld(config: Config) {\n // This choice of subject is for compatibility reasons\n this.#doAdd(config.getString('secret'), 'external:backstage-plugin');\n }\n\n #doAdd(\n secret: string,\n subject: string,\n allAccessRestrictions?: AccessRestriptionsMap,\n ) {\n if (!secret.match(/^\\S+$/)) {\n throw new Error('Illegal secret, must be a valid base64 string');\n } else if (!subject.match(/^\\S+$/)) {\n throw new Error('Illegal subject, must be a set of non-space characters');\n }\n\n let key: Uint8Array;\n try {\n key = base64url.decode(secret);\n } catch {\n throw new Error('Illegal secret, must be a valid base64 string');\n }\n\n if (this.#entries.some(e => e.key === key)) {\n throw new Error(\n 'Legacy externalAccess token was declared more than once',\n );\n }\n\n this.#entries.push({\n key,\n result: {\n subject,\n allAccessRestrictions,\n },\n });\n }\n\n async verifyToken(token: string) {\n // First do a duck typing check to see if it remotely looks like a legacy token\n try {\n // We do a fair amount of checking upfront here. Since we aren't certain\n // that it's even the right type of key that we're looking at, we can't\n // defer eg the alg check to jwtVerify, because it won't be possible to\n // discern different reasons for key verification failures from each other\n // easily\n const { alg } = decodeProtectedHeader(token);\n if (alg !== 'HS256') {\n return undefined;\n }\n const { sub, aud } = decodeJwt(token);\n if (sub !== 'backstage-server' || aud) {\n return undefined;\n }\n } catch (e) {\n // Doesn't look like a jwt at all\n return undefined;\n }\n\n for (const { key, result } of this.#entries) {\n try {\n await jwtVerify(token, key);\n return result;\n } catch (e) {\n if (e.code !== 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED') {\n throw e;\n }\n // Otherwise continue to try the next key\n }\n }\n\n // None of the signing keys matched\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { readAccessRestrictionsFromConfig } from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\nconst MIN_TOKEN_LENGTH = 8;\n\n/**\n * Handles `type: static` access.\n *\n * @internal\n */\nexport class StaticTokenHandler implements TokenHandler {\n #entries = new Map<\n string,\n {\n subject: string;\n allAccessRestrictions?: AccessRestriptionsMap;\n }\n >();\n\n add(config: Config) {\n const token = config.getString('options.token');\n const subject = config.getString('options.subject');\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n\n if (!token.match(/^\\S+$/)) {\n throw new Error('Illegal token, must be a set of non-space characters');\n } else if (token.length < MIN_TOKEN_LENGTH) {\n throw new Error(\n `Illegal token, must be at least ${MIN_TOKEN_LENGTH} characters length`,\n );\n } else if (!subject.match(/^\\S+$/)) {\n throw new Error('Illegal subject, must be a set of non-space characters');\n } else if (this.#entries.has(token)) {\n throw new Error(\n 'Static externalAccess token was declared more than once',\n );\n }\n\n this.#entries.set(token, { subject, allAccessRestrictions });\n }\n\n async verifyToken(token: string) {\n return this.#entries.get(token);\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { jwtVerify, createRemoteJWKSet, JWTVerifyGetKey } from 'jose';\nimport { Config } from '@backstage/config';\nimport {\n readAccessRestrictionsFromConfig,\n readStringOrStringArrayFromConfig,\n} from './helpers';\nimport { AccessRestriptionsMap, TokenHandler } from './types';\n\n/**\n * Handles `type: jwks` access.\n *\n * @internal\n */\nexport class JWKSHandler implements TokenHandler {\n #entries: Array<{\n algorithms?: string[];\n audiences?: string[];\n issuers?: string[];\n subjectPrefix?: string;\n url: URL;\n jwks: JWTVerifyGetKey;\n allAccessRestrictions?: AccessRestriptionsMap;\n }> = [];\n\n add(config: Config) {\n if (!config.getString('options.url').match(/^\\S+$/)) {\n throw new Error(\n 'Illegal JWKS URL, must be a set of non-space characters',\n );\n }\n\n const algorithms = readStringOrStringArrayFromConfig(\n config,\n 'options.algorithm',\n );\n const issuers = readStringOrStringArrayFromConfig(config, 'options.issuer');\n const audiences = readStringOrStringArrayFromConfig(\n config,\n 'options.audience',\n );\n const subjectPrefix = config.getOptionalString('options.subjectPrefix');\n const url = new URL(config.getString('options.url'));\n const jwks = createRemoteJWKSet(url);\n const allAccessRestrictions = readAccessRestrictionsFromConfig(config);\n\n this.#entries.push({\n algorithms,\n audiences,\n issuers,\n jwks,\n subjectPrefix,\n url,\n allAccessRestrictions,\n });\n }\n\n async verifyToken(token: string) {\n for (const entry of this.#entries) {\n try {\n const {\n payload: { sub },\n } = await jwtVerify(token, entry.jwks, {\n algorithms: entry.algorithms,\n issuer: entry.issuers,\n audience: entry.audiences,\n });\n\n if (sub) {\n const prefix = entry.subjectPrefix\n ? `external:${entry.subjectPrefix}:`\n : 'external:';\n return {\n subject: `${prefix}${sub}`,\n allAccessRestrictions: entry.allAccessRestrictions,\n };\n }\n } catch {\n continue;\n }\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n BackstagePrincipalAccessRestrictions,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { LegacyTokenHandler } from './legacy';\nimport { StaticTokenHandler } from './static';\nimport { JWKSHandler } from './jwks';\nimport { TokenHandler } from './types';\n\nconst NEW_CONFIG_KEY = 'backend.auth.externalAccess';\nconst OLD_CONFIG_KEY = 'backend.auth.keys';\nlet loggedDeprecationWarning = false;\n\n/**\n * Handles all types of external caller token types (i.e. not Backstage user\n * tokens, nor Backstage backend plugin tokens).\n *\n * @internal\n */\nexport class ExternalTokenHandler {\n static create(options: {\n ownPluginId: string;\n config: RootConfigService;\n logger: LoggerService;\n }): ExternalTokenHandler {\n const { ownPluginId, config, logger } = options;\n\n const staticHandler = new StaticTokenHandler();\n const legacyHandler = new LegacyTokenHandler();\n const jwksHandler = new JWKSHandler();\n const handlers: Record<string, TokenHandler> = {\n static: staticHandler,\n legacy: legacyHandler,\n jwks: jwksHandler,\n };\n\n // Load the new-style handlers\n const handlerConfigs = config.getOptionalConfigArray(NEW_CONFIG_KEY) ?? [];\n for (const handlerConfig of handlerConfigs) {\n const type = handlerConfig.getString('type');\n const handler = handlers[type];\n if (!handler) {\n const valid = Object.keys(handlers)\n .map(k => `'${k}'`)\n .join(', ');\n throw new Error(\n `Unknown type '${type}' in ${NEW_CONFIG_KEY}, expected one of ${valid}`,\n );\n }\n handler.add(handlerConfig);\n }\n\n // Load the old keys too\n const legacyConfigs = config.getOptionalConfigArray(OLD_CONFIG_KEY) ?? [];\n if (legacyConfigs.length && !loggedDeprecationWarning) {\n loggedDeprecationWarning = true;\n logger.warn(\n `DEPRECATION WARNING: The ${OLD_CONFIG_KEY} config has been replaced by ${NEW_CONFIG_KEY}, see https://backstage.io/docs/auth/service-to-service-auth`,\n );\n }\n for (const handlerConfig of legacyConfigs) {\n legacyHandler.addOld(handlerConfig);\n }\n\n return new ExternalTokenHandler(ownPluginId, Object.values(handlers));\n }\n\n constructor(\n private readonly ownPluginId: string,\n private readonly handlers: TokenHandler[],\n ) {}\n\n async verifyToken(token: string): Promise<\n | {\n subject: string;\n accessRestrictions?: BackstagePrincipalAccessRestrictions;\n }\n | undefined\n > {\n for (const handler of this.handlers) {\n const result = await handler.verifyToken(token);\n if (result) {\n const { allAccessRestrictions, ...rest } = result;\n if (allAccessRestrictions) {\n const accessRestrictions = allAccessRestrictions.get(\n this.ownPluginId,\n );\n if (!accessRestrictions) {\n const valid = [...allAccessRestrictions.keys()]\n .map(k => `'${k}'`)\n .join(', ');\n throw new NotAllowedError(\n `This token's access is restricted to plugin(s) ${valid}`,\n );\n }\n\n return {\n ...rest,\n accessRestrictions,\n };\n }\n\n return rest;\n }\n }\n\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AuthenticationError } from '@backstage/errors';\nimport {\n createRemoteJWKSet,\n decodeJwt,\n decodeProtectedHeader,\n FlattenedJWSInput,\n JWSHeaderParameters,\n} from 'jose';\nimport { GetKeyFunction } from 'jose/dist/types/types';\n\nconst CLOCK_MARGIN_S = 10;\n\nexport class JwksClient {\n #keyStore?: GetKeyFunction<JWSHeaderParameters, FlattenedJWSInput>;\n #keyStoreUpdated: number = 0;\n\n constructor(private readonly getEndpoint: () => Promise<URL>) {}\n\n get getKey() {\n if (!this.#keyStore) {\n throw new AuthenticationError(\n 'refreshKeyStore must be called before jwksClient.getKey',\n );\n }\n return this.#keyStore;\n }\n\n /**\n * If the last keystore refresh is stale, update the keystore URL to the latest\n */\n async refreshKeyStore(rawJwtToken: string): Promise<void> {\n const payload = await decodeJwt(rawJwtToken);\n const header = await decodeProtectedHeader(rawJwtToken);\n\n // Refresh public keys if needed\n let keyStoreHasKey;\n try {\n if (this.#keyStore) {\n // Check if the key is present in the keystore\n const [_, rawPayload, rawSignature] = rawJwtToken.split('.');\n keyStoreHasKey = await this.#keyStore(header, {\n payload: rawPayload,\n signature: rawSignature,\n });\n }\n } catch (error) {\n keyStoreHasKey = false;\n }\n // Refresh public key URL if needed\n // Add a small margin in case clocks are out of sync\n const issuedAfterLastRefresh =\n payload?.iat && payload.iat > this.#keyStoreUpdated - CLOCK_MARGIN_S;\n if (!this.#keyStore || (!keyStoreHasKey && issuedAfterLastRefresh)) {\n const endpoint = await this.getEndpoint();\n this.#keyStore = createRemoteJWKSet(endpoint);\n this.#keyStoreUpdated = Date.now() / 1000;\n }\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api';\nimport { decodeJwt, importJWK, SignJWT, decodeProtectedHeader } from 'jose';\nimport { AuthenticationError } from '@backstage/errors';\nimport { jwtVerify } from 'jose';\nimport { tokenTypes } from '@backstage/plugin-auth-node';\nimport { JwksClient } from '../JwksClient';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { PluginKeySource } from './keys/types';\n\nconst SECONDS_IN_MS = 1000;\n\nconst ALLOWED_PLUGIN_ID_PATTERN = /^[a-z0-9_-]+$/i;\n\ntype Options = {\n ownPluginId: string;\n keyDuration: HumanDuration;\n keySource: PluginKeySource;\n discovery: DiscoveryService;\n logger: LoggerService;\n /**\n * JWS \"alg\" (Algorithm) Header Parameter value. Defaults to ES256.\n * Must match one of the algorithms defined for IdentityClient.\n * When setting a different algorithm, check if the `key` field\n * of the `signing_keys` table can fit the length of the generated keys.\n * If not, add a knex migration file in the migrations folder.\n * More info on supported algorithms: https://github.com/panva/jose\n */\n algorithm?: string;\n};\n\nexport class PluginTokenHandler {\n private jwksMap = new Map<string, JwksClient>();\n\n // Tracking state for isTargetPluginSupported\n private supportedTargetPlugins = new Set<string>();\n private targetPluginInflightChecks = new Map<string, Promise<boolean>>();\n\n static create(options: Options) {\n return new PluginTokenHandler(\n options.logger,\n options.ownPluginId,\n options.keySource,\n options.algorithm ?? 'ES256',\n Math.round(durationToMilliseconds(options.keyDuration) / 1000),\n options.discovery,\n );\n }\n\n private constructor(\n private readonly logger: LoggerService,\n private readonly ownPluginId: string,\n private readonly keySource: PluginKeySource,\n private readonly algorithm: string,\n private readonly keyDurationSeconds: number,\n private readonly discovery: DiscoveryService,\n ) {}\n\n async verifyToken(\n token: string,\n ): Promise<{ subject: string; limitedUserToken?: string } | undefined> {\n try {\n const { typ } = decodeProtectedHeader(token);\n if (typ !== tokenTypes.plugin.typParam) {\n return undefined;\n }\n } catch {\n return undefined;\n }\n\n const pluginId = String(decodeJwt(token).sub);\n if (!pluginId) {\n throw new AuthenticationError('Invalid plugin token: missing subject');\n }\n if (!ALLOWED_PLUGIN_ID_PATTERN.test(pluginId)) {\n throw new AuthenticationError(\n 'Invalid plugin token: forbidden subject format',\n );\n }\n\n const jwksClient = await this.getJwksClient(pluginId);\n await jwksClient.refreshKeyStore(token); // TODO(Rugvip): Refactor so that this isn't needed\n\n const { payload } = await jwtVerify<{ sub: string; obo?: string }>(\n token,\n jwksClient.getKey,\n {\n typ: tokenTypes.plugin.typParam,\n audience: this.ownPluginId,\n requiredClaims: ['iat', 'exp', 'sub', 'aud'],\n },\n ).catch(e => {\n throw new AuthenticationError('Invalid plugin token', e);\n });\n\n return { subject: `plugin:${payload.sub}`, limitedUserToken: payload.obo };\n }\n\n async issueToken(options: {\n pluginId: string;\n targetPluginId: string;\n onBehalfOf?: { token: string; expiresAt: Date };\n }): Promise<{ token: string }> {\n const { pluginId, targetPluginId, onBehalfOf } = options;\n const key = await this.keySource.getPrivateSigningKey();\n\n const sub = pluginId;\n const aud = targetPluginId;\n const iat = Math.floor(Date.now() / SECONDS_IN_MS);\n const ourExp = iat + this.keyDurationSeconds;\n const exp = onBehalfOf\n ? Math.min(\n ourExp,\n Math.floor(onBehalfOf.expiresAt.getTime() / SECONDS_IN_MS),\n )\n : ourExp;\n\n const claims = { sub, aud, iat, exp, obo: onBehalfOf?.token };\n const token = await new SignJWT(claims)\n .setProtectedHeader({\n typ: tokenTypes.plugin.typParam,\n alg: this.algorithm,\n kid: key.kid,\n })\n .setAudience(aud)\n .setSubject(sub)\n .setIssuedAt(iat)\n .setExpirationTime(exp)\n .sign(await importJWK(key));\n\n return { token };\n }\n\n async isTargetPluginSupported(targetPluginId: string): Promise<boolean> {\n if (this.supportedTargetPlugins.has(targetPluginId)) {\n return true;\n }\n const inFlight = this.targetPluginInflightChecks.get(targetPluginId);\n if (inFlight) {\n return inFlight;\n }\n\n const doCheck = async () => {\n try {\n const res = await fetch(\n `${await this.discovery.getBaseUrl(\n targetPluginId,\n )}/.backstage/auth/v1/jwks.json`,\n );\n if (res.status === 404) {\n return false;\n }\n\n if (!res.ok) {\n throw new Error(`Failed to fetch jwks.json, ${res.status}`);\n }\n\n const data = await res.json();\n if (!data.keys) {\n throw new Error(`Invalid jwks.json response, missing keys`);\n }\n\n this.supportedTargetPlugins.add(targetPluginId);\n return true;\n } catch (error) {\n this.logger.error('Unexpected failure for target JWKS check', error);\n return false;\n } finally {\n this.targetPluginInflightChecks.delete(targetPluginId);\n }\n };\n\n const check = doCheck();\n this.targetPluginInflightChecks.set(targetPluginId, check);\n return check;\n }\n\n private async getJwksClient(pluginId: string) {\n const client = this.jwksMap.get(pluginId);\n if (client) {\n return client;\n }\n\n // Double check that the target plugin has a valid JWKS endpoint, otherwise avoid creating a remote key set\n if (!(await this.isTargetPluginSupported(pluginId))) {\n throw new AuthenticationError(\n `Received a plugin token where the source '${pluginId}' plugin unexpectedly does not have a JWKS endpoint`,\n );\n }\n\n const newClient = new JwksClient(async () => {\n return new URL(\n `${await this.discovery.getBaseUrl(\n pluginId,\n )}/.backstage/auth/v1/jwks.json`,\n );\n });\n\n this.jwksMap.set(pluginId, newClient);\n return newClient;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { DateTime } from 'luxon';\nimport { KeyStore } from './types';\n\nconst MIGRATIONS_TABLE = 'backstage_backend_public_keys__knex_migrations';\n\n/** @internal */\nexport const TABLE = 'backstage_backend_public_keys__keys';\n\ntype Row = {\n id: string;\n key: string;\n expires_at: string;\n};\n\nexport function applyDatabaseMigrations(knex: Knex): Promise<void> {\n const migrationsDir = resolvePackagePath(\n '@backstage/backend-defaults',\n 'migrations/auth',\n );\n\n return knex.migrate.latest({\n directory: migrationsDir,\n tableName: MIGRATIONS_TABLE,\n });\n}\n\n/** @internal */\nexport class DatabaseKeyStore implements KeyStore {\n static async create(options: {\n database: DatabaseService;\n logger: LoggerService;\n }) {\n const { database, logger } = options;\n\n const client = await database.getClient();\n if (!database.migrations?.skip) {\n await applyDatabaseMigrations(client);\n }\n return new DatabaseKeyStore(client, logger);\n }\n\n private constructor(\n private readonly client: Knex,\n private readonly logger: LoggerService,\n ) {}\n\n async addKey(options: {\n id: string;\n key: JsonObject & { kid: string };\n expiresAt: Date;\n }) {\n await this.client<Row>(TABLE).insert({\n id: options.key.kid,\n key: JSON.stringify(options.key),\n expires_at: options.expiresAt.toISOString(),\n });\n }\n\n async listKeys() {\n const rows = await this.client<Row>(TABLE).select();\n const keys = rows.map(row => ({\n id: row.id,\n key: JSON.parse(row.key),\n expiresAt: new Date(row.expires_at),\n }));\n\n const validKeys = [];\n const expiredKeys = [];\n\n for (const key of keys) {\n if (DateTime.fromJSDate(key.expiresAt) < DateTime.local()) {\n expiredKeys.push(key);\n } else {\n validKeys.push(key);\n }\n }\n\n // Lazily prune expired keys. This may cause duplicate removals if we have concurrent callers, but w/e\n if (expiredKeys.length > 0) {\n const kids = expiredKeys.map(({ key }) => key.kid);\n\n this.logger.info(\n `Removing expired plugin service keys, '${kids.join(\"', '\")}'`,\n );\n\n // We don't await this, just let it run in the background\n this.client<Row>(TABLE)\n .delete()\n .whereIn('id', kids)\n .catch(error => {\n this.logger.error(\n 'Failed to remove expired plugin service keys',\n error,\n );\n });\n }\n\n return { keys: validKeys };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DatabaseService, LoggerService } from '@backstage/backend-plugin-api';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { JWK, exportJWK, generateKeyPair } from 'jose';\nimport { v4 as uuid } from 'uuid';\nimport { DatabaseKeyStore } from './DatabaseKeyStore';\nimport { InternalKey, KeyPayload, KeyStore } from './types';\nimport { PluginKeySource } from './types';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * The margin for how many times longer we make the public key available\n * compared to how long we use the private key to sign new tokens.\n */\nconst KEY_EXPIRATION_MARGIN_FACTOR = 3;\n\nexport class DatabasePluginKeySource implements PluginKeySource {\n private privateKeyPromise?: Promise<JWK>;\n private keyExpiry?: Date;\n\n constructor(\n private readonly keyStore: KeyStore,\n private readonly logger: LoggerService,\n private readonly keyDurationSeconds: number,\n private readonly algorithm: string,\n ) {}\n\n public static async create(options: {\n logger: LoggerService;\n database: DatabaseService;\n keyDuration: HumanDuration;\n algorithm?: string;\n }): Promise<PluginKeySource> {\n const keyStore = await DatabaseKeyStore.create({\n database: options.database,\n logger: options.logger,\n });\n\n return new DatabasePluginKeySource(\n keyStore,\n options.logger,\n Math.round(durationToMilliseconds(options.keyDuration) / 1000),\n options.algorithm ?? 'ES256',\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n // Make sure that we only generate one key at a time\n if (this.privateKeyPromise) {\n if (this.keyExpiry && this.keyExpiry.getTime() > Date.now()) {\n return this.privateKeyPromise;\n }\n this.logger.info(`Signing key has expired, generating new key`);\n delete this.privateKeyPromise;\n }\n\n this.keyExpiry = new Date(\n Date.now() + this.keyDurationSeconds * SECONDS_IN_MS,\n );\n\n const promise = (async () => {\n // This generates a new signing key to be used to sign tokens until the next key rotation\n const kid = uuid();\n const key = await generateKeyPair(this.algorithm);\n const publicKey = await exportJWK(key.publicKey);\n const privateKey = await exportJWK(key.privateKey);\n publicKey.kid = privateKey.kid = kid;\n publicKey.alg = privateKey.alg = this.algorithm;\n\n // We're not allowed to use the key until it has been successfully stored\n // TODO: some token verification implementations aggressively cache the list of keys, and\n // don't attempt to fetch new ones even if they encounter an unknown kid. Therefore we\n // may want to keep using the existing key for some period of time until we switch to\n // the new one. This also needs to be implemented cross-service though, meaning new services\n // that boot up need to be able to grab an existing key to use for signing.\n this.logger.info(`Created new signing key ${kid}`);\n\n await this.keyStore.addKey({\n id: kid,\n key: publicKey as InternalKey,\n expiresAt: new Date(\n Date.now() +\n this.keyDurationSeconds *\n SECONDS_IN_MS *\n KEY_EXPIRATION_MARGIN_FACTOR,\n ),\n });\n\n // At this point we are allowed to start using the new key\n return privateKey;\n })();\n\n this.privateKeyPromise = promise;\n\n try {\n // If we fail to generate a new key, we need to clear the state so that\n // the next caller will try to generate another key.\n await promise;\n } catch (error) {\n this.logger.error(`Failed to generate new signing key, ${error}`);\n delete this.keyExpiry;\n delete this.privateKeyPromise;\n }\n\n return promise;\n }\n\n listKeys(): Promise<{ keys: KeyPayload[] }> {\n return this.keyStore.listKeys();\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { HumanDuration, durationToMilliseconds } from '@backstage/types';\nimport { promises as fs } from 'fs';\nimport { JWK, exportJWK, importPKCS8, importSPKI } from 'jose';\nimport { KeyLike } from 'jose/dist/types/types';\nimport { KeyPayload } from './types';\nimport { PluginKeySource } from './types';\n\nexport type KeyPair = {\n publicKey: JWK;\n privateKey?: JWK;\n keyId: string;\n};\n\nexport type StaticKeyConfig = {\n publicKeyFile: string;\n privateKeyFile?: string;\n keyId: string;\n algorithm: string;\n};\n\nconst DEFAULT_ALGORITHM = 'ES256';\n\nconst SECONDS_IN_MS = 1000;\n\n/**\n * Key source that loads predefined public/private key pairs from disk.\n *\n * The private key should be represented using the PKCS#8 format,\n * while the public key should be in the SPKI format.\n *\n * @remarks\n *\n * You can generate a public and private key pair, using\n * openssl:\n *\n * Generate a private key using the ES256 algorithm\n * ```sh\n * openssl ecparam -name prime256v1 -genkey -out private.ec.key\n * ```\n * Convert it to PKCS#8 format\n * ```sh\n * openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key\n * ```\n * Extract the public key\n * ```sh\n * openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key\n * ```\n *\n * Provide the paths to private.key and public.key as the respective\n * private and public key paths in the `create` method.\n */\nexport class StaticConfigPluginKeySource implements PluginKeySource {\n private constructor(\n private readonly keyPairs: KeyPair[],\n private readonly keyDurationSeconds: number,\n ) {}\n\n public static async create(options: {\n sourceConfig: Config;\n keyDuration: HumanDuration;\n }): Promise<PluginKeySource> {\n const keyConfigs = options.sourceConfig\n .getConfigArray('static.keys')\n .map(c => {\n const staticKeyConfig: StaticKeyConfig = {\n publicKeyFile: c.getString('publicKeyFile'),\n privateKeyFile: c.getOptionalString('privateKeyFile'),\n keyId: c.getString('keyId'),\n algorithm: c.getOptionalString('algorithm') ?? DEFAULT_ALGORITHM,\n };\n\n return staticKeyConfig;\n });\n\n const keyPairs = await Promise.all(\n keyConfigs.map(async k => await this.loadKeyPair(k)),\n );\n\n if (keyPairs.length < 1) {\n throw new Error(\n 'At least one key pair must be provided in static.keys, when the static key store type is used',\n );\n } else if (!keyPairs[0].privateKey) {\n throw new Error(\n 'Private key for signing must be provided in the first key pair in static.keys, when the static key store type is used',\n );\n }\n\n return new StaticConfigPluginKeySource(\n keyPairs,\n durationToMilliseconds(options.keyDuration) / SECONDS_IN_MS,\n );\n }\n\n async getPrivateSigningKey(): Promise<JWK> {\n return this.keyPairs[0].privateKey!;\n }\n\n async listKeys(): Promise<{ keys: KeyPayload[] }> {\n const keys = this.keyPairs.map(k => this.keyPairToStoredKey(k));\n return { keys };\n }\n\n private static async loadKeyPair(options: StaticKeyConfig): Promise<KeyPair> {\n const algorithm = options.algorithm;\n const keyId = options.keyId;\n const publicKey = await this.loadPublicKeyFromFile(\n options.publicKeyFile,\n keyId,\n algorithm,\n );\n const privateKey = options.privateKeyFile\n ? await this.loadPrivateKeyFromFile(\n options.privateKeyFile,\n keyId,\n algorithm,\n )\n : undefined;\n\n return { publicKey, privateKey, keyId };\n }\n\n private static async loadPublicKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importSPKI);\n }\n\n private static async loadPrivateKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n ): Promise<JWK> {\n return this.loadKeyFromFile(path, keyId, algorithm, importPKCS8);\n }\n\n private static async loadKeyFromFile(\n path: string,\n keyId: string,\n algorithm: string,\n importer: (content: string, algorithm: string) => Promise<KeyLike>,\n ): Promise<JWK> {\n const content = await fs.readFile(path, { encoding: 'utf8', flag: 'r' });\n const key = await importer(content, algorithm);\n const jwk = await exportJWK(key);\n jwk.kid = keyId;\n jwk.alg = algorithm;\n\n return jwk;\n }\n\n private keyPairToStoredKey(keyPair: KeyPair): KeyPayload {\n const publicKey = {\n ...keyPair.publicKey,\n kid: keyPair.keyId,\n };\n\n return {\n key: publicKey,\n id: keyPair.keyId,\n expiresAt: new Date(Date.now() + this.keyDurationSeconds * SECONDS_IN_MS),\n };\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n DatabaseService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { HumanDuration } from '@backstage/types';\nimport { DatabasePluginKeySource } from './DatabasePluginKeySource';\nimport { StaticConfigPluginKeySource } from './StaticConfigPluginKeySource';\nimport { PluginKeySource } from './types';\n\nconst CONFIG_ROOT_KEY = 'backend.auth.pluginKeyStore';\n\nexport async function createPluginKeySource(options: {\n config: RootConfigService;\n database: DatabaseService;\n logger: LoggerService;\n keyDuration: HumanDuration;\n algorithm?: string;\n}): Promise<PluginKeySource> {\n const keyStoreConfig = options.config.getOptionalConfig(CONFIG_ROOT_KEY);\n const type = keyStoreConfig?.getOptionalString('type') ?? 'database';\n\n if (!keyStoreConfig || type === 'database') {\n return DatabasePluginKeySource.create({\n database: options.database,\n logger: options.logger,\n keyDuration: options.keyDuration,\n algorithm: options.algorithm,\n });\n } else if (type === 'static') {\n return StaticConfigPluginKeySource.create({\n sourceConfig: keyStoreConfig,\n keyDuration: options.keyDuration,\n });\n }\n\n throw new Error(\n `Unsupported config value ${CONFIG_ROOT_KEY}.type '${type}'; expected one of 'database', 'static'`,\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DiscoveryService } from '@backstage/backend-plugin-api';\nimport { AuthenticationError } from '@backstage/errors';\nimport { tokenTypes } from '@backstage/plugin-auth-node';\nimport {\n base64url,\n decodeJwt,\n decodeProtectedHeader,\n jwtVerify,\n JWTVerifyOptions,\n} from 'jose';\nimport { JwksClient } from '../JwksClient';\n\n/**\n * An identity client to interact with auth-backend and authenticate Backstage\n * tokens\n *\n * @internal\n */\nexport class UserTokenHandler {\n static create(options: { discovery: DiscoveryService }): UserTokenHandler {\n const jwksClient = new JwksClient(async () => {\n const url = await options.discovery.getBaseUrl('auth');\n return new URL(`${url}/.well-known/jwks.json`);\n });\n return new UserTokenHandler(jwksClient);\n }\n\n constructor(private readonly jwksClient: JwksClient) {}\n\n async verifyToken(token: string) {\n const verifyOpts = this.#getTokenVerificationOptions(token);\n if (!verifyOpts) {\n return undefined;\n }\n\n await this.jwksClient.refreshKeyStore(token);\n\n // Verify a limited token, ensuring the necessarily claims are present and token type is correct\n const { payload } = await jwtVerify(\n token,\n this.jwksClient.getKey,\n verifyOpts,\n ).catch(e => {\n throw new AuthenticationError('Invalid token', e);\n });\n\n const userEntityRef = payload.sub;\n\n if (!userEntityRef) {\n throw new AuthenticationError('No user sub found in token');\n }\n\n return { userEntityRef };\n }\n\n #getTokenVerificationOptions(token: string): JWTVerifyOptions | undefined {\n try {\n const { typ } = decodeProtectedHeader(token);\n\n if (typ === tokenTypes.user.typParam) {\n return {\n requiredClaims: ['iat', 'exp', 'sub'],\n typ: tokenTypes.user.typParam,\n };\n }\n\n if (typ === tokenTypes.limitedUser.typParam) {\n return {\n requiredClaims: ['iat', 'exp', 'sub'],\n typ: tokenTypes.limitedUser.typParam,\n };\n }\n\n const { aud } = decodeJwt(token);\n if (aud === tokenTypes.user.audClaim) {\n return {\n audience: tokenTypes.user.audClaim,\n };\n }\n } catch {\n /* ignore */\n }\n\n return undefined;\n }\n\n createLimitedUserToken(backstageToken: string) {\n const [headerRaw, payloadRaw] = backstageToken.split('.');\n const header = JSON.parse(\n new TextDecoder().decode(base64url.decode(headerRaw)),\n );\n const payload = JSON.parse(\n new TextDecoder().decode(base64url.decode(payloadRaw)),\n );\n\n const tokenType = header.typ;\n\n // Only new user tokens can be used to create a limited user token. If we\n // can't create a limited token, or the token is already a limited one, we\n // return the original token\n if (!tokenType || tokenType === tokenTypes.limitedUser.typParam) {\n return { token: backstageToken, expiresAt: new Date(payload.exp * 1000) };\n }\n\n if (tokenType !== tokenTypes.user.typParam) {\n throw new AuthenticationError(\n 'Failed to create limited user token, invalid token type',\n );\n }\n\n // NOTE: The order and properties in both the header and payload must match\n // the usage in plugins/auth-backend/src/identity/TokenFactory.ts\n const limitedUserToken = [\n base64url.encode(\n JSON.stringify({\n typ: tokenTypes.limitedUser.typParam,\n alg: header.alg,\n kid: header.kid,\n }),\n ),\n base64url.encode(\n JSON.stringify({\n sub: payload.sub,\n iat: payload.iat,\n exp: payload.exp,\n }),\n ),\n payload.uip,\n ].join('.');\n\n return { token: limitedUserToken, expiresAt: new Date(payload.exp * 1000) };\n }\n\n isLimitedUserToken(token: string): boolean {\n try {\n const { typ } = decodeProtectedHeader(token);\n return typ === tokenTypes.limitedUser.typParam;\n } catch {\n return false;\n }\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultAuthService } from './DefaultAuthService';\nimport { ExternalTokenHandler } from './external/ExternalTokenHandler';\nimport { PluginTokenHandler } from './plugin/PluginTokenHandler';\nimport { createPluginKeySource } from './plugin/keys/createPluginKeySource';\nimport { UserTokenHandler } from './user/UserTokenHandler';\n\n/**\n * Handles token authentication and credentials management.\n *\n * See {@link @backstage/code-plugin-api#AuthService}\n * and {@link https://backstage.io/docs/backend-system/core-services/auth | the service docs}\n * for more information.\n *\n * @public\n */\nexport const authServiceFactory = createServiceFactory({\n service: coreServices.auth,\n deps: {\n config: coreServices.rootConfig,\n logger: coreServices.rootLogger,\n discovery: coreServices.discovery,\n plugin: coreServices.pluginMetadata,\n database: coreServices.database,\n // Re-using the token manager makes sure that we use the same generated keys for\n // development as plugins that have not yet been migrated. It's important that this\n // keeps working as long as there are plugins that have not been migrated to the\n // new auth services in the new backend system.\n tokenManager: coreServices.tokenManager,\n },\n async factory({ config, discovery, plugin, tokenManager, logger, database }) {\n const disableDefaultAuthPolicy =\n config.getOptionalBoolean(\n 'backend.auth.dangerouslyDisableDefaultAuthPolicy',\n ) ?? false;\n\n const keyDuration = { hours: 1 };\n\n const keySource = await createPluginKeySource({\n config,\n database,\n logger,\n keyDuration,\n });\n\n const userTokens = UserTokenHandler.create({\n discovery,\n });\n\n const pluginTokens = PluginTokenHandler.create({\n ownPluginId: plugin.getId(),\n logger,\n keySource,\n keyDuration,\n discovery,\n });\n\n const externalTokens = ExternalTokenHandler.create({\n ownPluginId: plugin.getId(),\n config,\n logger,\n });\n\n return new DefaultAuthService(\n userTokens,\n pluginTokens,\n externalTokens,\n tokenManager,\n plugin.getId(),\n disableDefaultAuthPolicy,\n keySource,\n logger,\n );\n },\n});\n"],"names":["userResult","AuthenticationError","createCredentialsWithUserPrincipal","createCredentialsWithServicePrincipal","createCredentialsWithNonePrincipal","toInternalBackstageCredentials","ForwardedError","decodeJwt","base64url","decodeProtectedHeader","jwtVerify","createRemoteJWKSet","NotAllowedError","SECONDS_IN_MS","durationToMilliseconds","tokenTypes","SignJWT","importJWK","resolvePackagePath","DateTime","uuid","generateKeyPair","exportJWK","importSPKI","importPKCS8","fs","createServiceFactory","coreServices"],"mappings":"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"}
@@ -480,7 +480,8 @@ class MiddlewareFactory {
480
480
  const logger = this.#logger.child({
481
481
  type: "incomingRequest"
482
482
  });
483
- return morgan__default.default("combined", {
483
+ const customMorganFormat = '[:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"';
484
+ return morgan__default.default(customMorganFormat, {
484
485
  stream: {
485
486
  write(message) {
486
487
  logger.info(message.trimEnd());
@@ -1 +1 @@
1
- {"version":3,"file":"rootHttpRouter.cjs.js","sources":["../src/entrypoints/rootHttpRouter/DefaultRootHttpRouter.ts","../src/entrypoints/rootHttpRouter/createHealthRouter.ts","../src/entrypoints/rootHttpRouter/http/getGeneratedCertificate.ts","../src/entrypoints/rootHttpRouter/http/createHttpServer.ts","../src/entrypoints/rootHttpRouter/http/readHelmetOptions.ts","../src/entrypoints/rootHttpRouter/http/readCorsOptions.ts","../src/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.ts","../src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts","../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootHttpRouterService } from '@backstage/backend-plugin-api';\nimport { Handler, Router } from 'express';\nimport trimEnd from 'lodash/trimEnd';\n\nfunction normalizePath(path: string): string {\n return `${trimEnd(path, '/')}/`;\n}\n\n/**\n * Options for the {@link DefaultRootHttpRouter} class.\n *\n * @public\n */\nexport interface DefaultRootHttpRouterOptions {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n}\n\n/**\n * The default implementation of the {@link @backstage/backend-plugin-api#RootHttpRouterService} interface for\n * {@link @backstage/backend-plugin-api#coreServices.rootHttpRouter}.\n *\n * @public\n */\nexport class DefaultRootHttpRouter implements RootHttpRouterService {\n #indexPath?: string;\n\n #router = Router();\n #namedRoutes = Router();\n #indexRouter = Router();\n #existingPaths = new Array<string>();\n\n static create(options?: DefaultRootHttpRouterOptions) {\n let indexPath;\n if (options?.indexPath === false) {\n indexPath = undefined;\n } else if (options?.indexPath === undefined) {\n indexPath = '/api/app';\n } else if (options?.indexPath === '') {\n throw new Error('indexPath option may not be an empty string');\n } else {\n indexPath = options.indexPath;\n }\n return new DefaultRootHttpRouter(indexPath);\n }\n\n private constructor(indexPath?: string) {\n this.#indexPath = indexPath;\n this.#router.use(this.#namedRoutes);\n\n // Any request with a /api/ prefix will skip the index router, even if no named router matches\n this.#router.use('/api/', (_req, _res, next) => {\n next('router');\n });\n\n if (this.#indexPath) {\n this.#router.use(this.#indexRouter);\n }\n }\n\n use(path: string, handler: Handler) {\n if (path.match(/^[/\\s]*$/)) {\n throw new Error(`Root router path may not be empty`);\n }\n const conflictingPath = this.#findConflictingPath(path);\n if (conflictingPath) {\n throw new Error(\n `Path ${path} conflicts with the existing path ${conflictingPath}`,\n );\n }\n this.#existingPaths.push(path);\n this.#namedRoutes.use(path, handler);\n\n if (this.#indexPath === path) {\n this.#indexRouter.use(handler);\n }\n }\n\n handler(): Handler {\n return this.#router;\n }\n\n #findConflictingPath(newPath: string): string | undefined {\n const normalizedNewPath = normalizePath(newPath);\n for (const path of this.#existingPaths) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath.startsWith(normalizedNewPath)) {\n return path;\n }\n if (normalizedNewPath.startsWith(normalizedPath)) {\n return path;\n }\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootHealthService } from '@backstage/backend-plugin-api';\nimport Router from 'express-promise-router';\nimport { Request, Response } from 'express';\n\n/**\n * @public\n */\nexport function createHealthRouter(options: { health: RootHealthService }) {\n const router = Router();\n\n router.get(\n '/.backstage/health/v1/readiness',\n async (_request: Request, response: Response) => {\n const { status, payload } = await options.health.getReadiness();\n response.status(status).json(payload);\n },\n );\n\n router.get(\n '/.backstage/health/v1/liveness',\n async (_request: Request, response: Response) => {\n const { status, payload } = await options.health.getLiveness();\n response.status(status).json(payload);\n },\n );\n\n return router;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport forge from 'node-forge';\n\nconst FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1000;\n\nconst IP_HOSTNAME_REGEX = /:|^\\d+\\.\\d+\\.\\d+\\.\\d+$/;\n\nexport async function getGeneratedCertificate(\n hostname: string,\n logger: LoggerService,\n) {\n const hasModules = await fs.pathExists('node_modules');\n let certPath;\n if (hasModules) {\n certPath = resolvePath(\n 'node_modules/.cache/backstage-backend/dev-cert.pem',\n );\n await fs.ensureDir(dirname(certPath));\n } else {\n certPath = resolvePath('.dev-cert.pem');\n }\n\n if (await fs.pathExists(certPath)) {\n try {\n const cert = await fs.readFile(certPath);\n\n const crt = forge.pki.certificateFromPem(cert.toString());\n const remainingMs = crt.validity.notAfter.getTime() - Date.now();\n if (remainingMs > FIVE_DAYS_IN_MS) {\n logger.info('Using existing self-signed certificate');\n return {\n key: cert,\n cert,\n };\n }\n } catch (error) {\n logger.warn(`Unable to use existing self-signed certificate, ${error}`);\n }\n }\n\n logger.info('Generating new self-signed certificate');\n const newCert = await generateCertificate(hostname);\n await fs.writeFile(certPath, newCert.cert + newCert.key, 'utf8');\n return newCert;\n}\n\nasync function generateCertificate(hostname: string) {\n const attributes = [\n {\n name: 'commonName',\n value: 'dev-cert',\n },\n ];\n\n const sans = [\n {\n type: 2, // DNS\n value: 'localhost',\n },\n {\n type: 2,\n value: 'localhost.localdomain',\n },\n {\n type: 2,\n value: '[::1]',\n },\n {\n type: 7, // IP\n ip: '127.0.0.1',\n },\n {\n type: 7,\n ip: 'fe80::1',\n },\n ];\n\n // Add hostname from backend.baseUrl if it doesn't already exist in our list of SANs\n if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {\n sans.push(\n IP_HOSTNAME_REGEX.test(hostname)\n ? {\n type: 7,\n ip: hostname,\n }\n : {\n type: 2,\n value: hostname,\n },\n );\n }\n\n const params = {\n algorithm: 'sha256',\n keySize: 2048,\n days: 30,\n extensions: [\n {\n name: 'keyUsage',\n keyCertSign: true,\n digitalSignature: true,\n nonRepudiation: true,\n keyEncipherment: true,\n dataEncipherment: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n codeSigning: true,\n timeStamping: true,\n },\n {\n name: 'subjectAltName',\n altNames: sans,\n },\n ],\n };\n\n return new Promise<{ key: string; cert: string }>((resolve, reject) =>\n require('selfsigned').generate(\n attributes,\n params,\n (err: Error, bundle: { private: string; cert: string }) => {\n if (err) {\n reject(err);\n } else {\n resolve({ key: bundle.private, cert: bundle.cert });\n }\n },\n ),\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as http from 'http';\nimport * as https from 'https';\nimport stoppableServer from 'stoppable';\nimport { RequestListener } from 'http';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { HttpServerOptions, ExtendedHttpServer } from './types';\nimport { getGeneratedCertificate } from './getGeneratedCertificate';\n\n/**\n * Creates a Node.js HTTP or HTTPS server instance.\n *\n * @public\n */\nexport async function createHttpServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<ExtendedHttpServer> {\n const server = await createServer(listener, options, deps);\n\n const stopper = stoppableServer(server, 0);\n // The stopper here is actually the server itself, so if we try\n // to call stopper.stop() down in the stop implementation, we'll\n // be calling ourselves.\n const stopServer = stopper.stop.bind(stopper);\n\n return Object.assign(server, {\n start() {\n return new Promise<void>((resolve, reject) => {\n const handleStartupError = (error: Error) => {\n server.close();\n reject(error);\n };\n\n server.on('error', handleStartupError);\n\n const { host, port } = options.listen;\n server.listen(port, host, () => {\n server.off('error', handleStartupError);\n deps.logger.info(`Listening on ${host}:${port}`);\n resolve();\n });\n });\n },\n\n stop() {\n return new Promise<void>((resolve, reject) => {\n stopServer((error?: Error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n },\n\n port() {\n const address = server.address();\n if (typeof address === 'string' || address === null) {\n throw new Error(`Unexpected server address '${address}'`);\n }\n return address.port;\n },\n });\n}\n\nasync function createServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<http.Server> {\n if (options.https) {\n const { certificate } = options.https;\n if (certificate.type === 'generated') {\n const credentials = await getGeneratedCertificate(\n certificate.hostname,\n deps.logger,\n );\n return https.createServer(credentials, listener);\n }\n return https.createServer(certificate, listener);\n }\n\n return http.createServer(listener);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport helmet from 'helmet';\nimport { HelmetOptions } from 'helmet';\nimport { ContentSecurityPolicyOptions } from 'helmet/dist/types/middlewares/content-security-policy';\nimport kebabCase from 'lodash/kebabCase';\n\n/**\n * Attempts to read Helmet options from the backend configuration object.\n *\n * @public\n * @param config - The backend configuration object.\n * @returns A Helmet options object, or undefined if no Helmet configuration is present.\n *\n * @example\n * ```ts\n * const helmetOptions = readHelmetOptions(config.getConfig('backend'));\n * ```\n */\nexport function readHelmetOptions(config?: Config): HelmetOptions {\n const cspOptions = readCspDirectives(config);\n return {\n contentSecurityPolicy: {\n useDefaults: false,\n directives: applyCspDirectives(cspOptions),\n },\n // These are all disabled in order to maintain backwards compatibility\n // when bumping helmet v5. We can't enable these by default because\n // there is no way for users to configure them.\n // TODO(Rugvip): We should give control of this setup to consumers\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n originAgentCluster: false,\n };\n}\n\ntype CspDirectives = Record<string, string[] | false> | undefined;\n\n/**\n * Attempts to read a CSP directives from the backend configuration object.\n *\n * @example\n * ```yaml\n * backend:\n * csp:\n * connect-src: [\"'self'\", 'http:', 'https:']\n * upgrade-insecure-requests: false\n * ```\n */\nfunction readCspDirectives(config?: Config): CspDirectives {\n const cc = config?.getOptionalConfig('csp');\n if (!cc) {\n return undefined;\n }\n\n const result: Record<string, string[] | false> = {};\n for (const key of cc.keys()) {\n if (cc.get(key) === false) {\n result[key] = false;\n } else {\n result[key] = cc.getStringArray(key);\n }\n }\n\n return result;\n}\n\nexport function applyCspDirectives(\n directives: CspDirectives,\n): ContentSecurityPolicyOptions['directives'] {\n const result: ContentSecurityPolicyOptions['directives'] =\n helmet.contentSecurityPolicy.getDefaultDirectives();\n\n // TODO(Rugvip): We currently use non-precompiled AJV for validation in the frontend, which uses eval.\n // It should be replaced by any other solution that doesn't require unsafe-eval.\n result['script-src'] = [\"'self'\", \"'unsafe-eval'\"];\n\n // TODO(Rugvip): This is removed so that we maintained backwards compatibility\n // when bumping to helmet v5, we could remove this as well as\n // skip setting `useDefaults: false` in the future.\n delete result['form-action'];\n\n if (directives) {\n for (const [key, value] of Object.entries(directives)) {\n const kebabCaseKey = kebabCase(key);\n if (value === false) {\n delete result[kebabCaseKey];\n } else {\n result[kebabCaseKey] = value;\n }\n }\n }\n\n return result;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { CorsOptions } from 'cors';\nimport { Minimatch } from 'minimatch';\n\n/**\n * Attempts to read a CORS options object from the backend configuration object.\n *\n * @public\n * @param config - The backend configuration object.\n * @returns A CORS options object, or undefined if no cors configuration is present.\n *\n * @example\n * ```ts\n * const corsOptions = readCorsOptions(config.getConfig('backend'));\n * ```\n */\nexport function readCorsOptions(config?: Config): CorsOptions {\n const cc = config?.getOptionalConfig('cors');\n if (!cc) {\n return { origin: false }; // Disable CORS\n }\n\n return removeUnknown({\n origin: createCorsOriginMatcher(readStringArray(cc, 'origin')),\n methods: readStringArray(cc, 'methods'),\n allowedHeaders: readStringArray(cc, 'allowedHeaders'),\n exposedHeaders: readStringArray(cc, 'exposedHeaders'),\n credentials: cc.getOptionalBoolean('credentials'),\n maxAge: cc.getOptionalNumber('maxAge'),\n preflightContinue: cc.getOptionalBoolean('preflightContinue'),\n optionsSuccessStatus: cc.getOptionalNumber('optionsSuccessStatus'),\n });\n}\n\nfunction removeUnknown<T extends object>(obj: T): T {\n return Object.fromEntries(\n Object.entries(obj).filter(([, v]) => v !== undefined),\n ) as T;\n}\n\nfunction readStringArray(config: Config, key: string): string[] | undefined {\n const value = config.getOptional(key);\n if (typeof value === 'string') {\n return [value];\n } else if (!value) {\n return undefined;\n }\n return config.getStringArray(key);\n}\n\nfunction createCorsOriginMatcher(allowedOriginPatterns: string[] | undefined) {\n if (!allowedOriginPatterns) {\n return undefined;\n }\n\n const allowedOriginMatchers = allowedOriginPatterns.map(\n pattern => new Minimatch(pattern, { nocase: true, noglobstar: true }),\n );\n\n return (\n origin: string | undefined,\n callback: (\n err: Error | null,\n origin: boolean | string | RegExp | (boolean | string | RegExp)[],\n ) => void,\n ) => {\n return callback(\n null,\n allowedOriginMatchers.some(pattern => pattern.match(origin ?? '')),\n );\n };\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { assertError } from '@backstage/errors';\nimport { randomBytes } from 'crypto';\n\nfunction handleBadError(error: Error, logger: LoggerService) {\n const logId = randomBytes(10).toString('hex');\n logger\n .child({ logId })\n .error(`Filtered internal error with logId=${logId} from response`, error);\n const newError = new Error(`An internal error occurred logId=${logId}`);\n delete newError.stack; // Trim the stack since it's not particularly useful\n return newError;\n}\n\n/**\n * Filters out certain known error types that should never be returned in responses.\n *\n * @internal\n */\nexport function applyInternalErrorFilter(\n error: unknown,\n logger: LoggerService,\n): Error {\n try {\n assertError(error);\n } catch (assertionError: unknown) {\n assertError(assertionError);\n return handleBadError(assertionError, logger);\n }\n\n const constructorName = error.constructor.name;\n\n // DatabaseError are thrown by the pg-protocol module\n if (constructorName === 'DatabaseError') {\n return handleBadError(error, logger);\n }\n\n return error;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RootConfigService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n Request,\n Response,\n ErrorRequestHandler,\n NextFunction,\n RequestHandler,\n} from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport morgan from 'morgan';\nimport compression from 'compression';\nimport { readHelmetOptions } from './readHelmetOptions';\nimport { readCorsOptions } from './readCorsOptions';\nimport {\n AuthenticationError,\n ConflictError,\n ErrorResponseBody,\n InputError,\n NotAllowedError,\n NotFoundError,\n NotModifiedError,\n ServiceUnavailableError,\n serializeError,\n} from '@backstage/errors';\nimport { NotImplementedError } from '@backstage/errors';\nimport { applyInternalErrorFilter } from './applyInternalErrorFilter';\n\n/**\n * Options used to create a {@link MiddlewareFactory}.\n *\n * @public\n */\nexport interface MiddlewareFactoryOptions {\n config: RootConfigService;\n logger: LoggerService;\n}\n\n/**\n * Options passed to the {@link MiddlewareFactory.error} middleware.\n *\n * @public\n */\nexport interface MiddlewareFactoryErrorOptions {\n /**\n * Whether error response bodies should show error stack traces or not.\n *\n * If not specified, by default shows stack traces only in development mode.\n */\n showStackTraces?: boolean;\n\n /**\n * Whether any 4xx errors should be logged or not.\n *\n * If not specified, default to only logging 5xx errors.\n */\n logAllErrors?: boolean;\n}\n\n/**\n * A utility to configure common middleware.\n *\n * @public\n */\nexport class MiddlewareFactory {\n #config: RootConfigService;\n #logger: LoggerService;\n\n /**\n * Creates a new {@link MiddlewareFactory}.\n */\n static create(options: MiddlewareFactoryOptions) {\n return new MiddlewareFactory(options);\n }\n\n private constructor(options: MiddlewareFactoryOptions) {\n this.#config = options.config;\n this.#logger = options.logger;\n }\n\n /**\n * Returns a middleware that unconditionally produces a 404 error response.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the end of the chain, such\n * that it's the last one attempted after no other routes matched.\n *\n * @returns An Express request handler\n */\n notFound(): RequestHandler {\n return (_req: Request, res: Response) => {\n res.status(404).end();\n };\n }\n\n /**\n * Returns the compression middleware.\n *\n * @remarks\n *\n * The middleware will attempt to compress response bodies for all requests\n * that traverse through the middleware.\n */\n compression(): RequestHandler {\n return compression();\n }\n\n /**\n * Returns a request logging middleware.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the start of the chain, such\n * that it always logs requests whether they are \"caught\" by handlers farther\n * down or not.\n *\n * @returns An Express request handler\n */\n logging(): RequestHandler {\n const logger = this.#logger.child({\n type: 'incomingRequest',\n });\n\n return morgan('combined', {\n stream: {\n write(message: string) {\n logger.info(message.trimEnd());\n },\n },\n });\n }\n\n /**\n * Returns a middleware that implements the helmet library.\n *\n * @remarks\n *\n * This middleware applies security policies to incoming requests and outgoing\n * responses. It is configured using config keys such as `backend.csp`.\n *\n * @see {@link https://helmetjs.github.io/}\n *\n * @returns An Express request handler\n */\n helmet(): RequestHandler {\n return helmet(readHelmetOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Returns a middleware that implements the cors library.\n *\n * @remarks\n *\n * This middleware handles CORS. It is configured using the config key\n * `backend.cors`.\n *\n * @see {@link https://github.com/expressjs/cors}\n *\n * @returns An Express request handler\n */\n cors(): RequestHandler {\n return cors(readCorsOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Express middleware to handle errors during request processing.\n *\n * @remarks\n *\n * This is commonly the very last middleware in the chain.\n *\n * Its primary purpose is not to do translation of business logic exceptions,\n * but rather to be a global catch-all for uncaught \"fatal\" errors that are\n * expected to result in a 500 error. However, it also does handle some common\n * error types (such as http-error exceptions, and the well-known error types\n * in the `@backstage/errors` package) and returns the enclosed status code\n * accordingly.\n *\n * It will also produce a response body with a serialized form of the error,\n * unless a previous handler already did send a body. See\n * {@link @backstage/errors#ErrorResponseBody} for the response shape used.\n *\n * @returns An Express error request handler\n */\n error(options: MiddlewareFactoryErrorOptions = {}): ErrorRequestHandler {\n const showStackTraces =\n options.showStackTraces ?? process.env.NODE_ENV === 'development';\n\n const logger = this.#logger.child({\n type: 'errorHandler',\n });\n\n return (\n rawError: Error,\n req: Request,\n res: Response,\n next: NextFunction,\n ) => {\n const error = applyInternalErrorFilter(rawError, logger);\n\n const statusCode = getStatusCode(error);\n if (options.logAllErrors || statusCode >= 500) {\n logger.error(`Request failed with status ${statusCode}`, error);\n }\n\n if (res.headersSent) {\n // If the headers have already been sent, do not send the response again\n // as this will throw an error in the backend.\n next(error);\n return;\n }\n\n const body: ErrorResponseBody = {\n error: serializeError(error, { includeStack: showStackTraces }),\n request: { method: req.method, url: req.url },\n response: { statusCode },\n };\n\n res.status(statusCode).json(body);\n };\n }\n}\n\nfunction getStatusCode(error: Error): number {\n // Look for common http library status codes\n const knownStatusCodeFields = ['statusCode', 'status'];\n for (const field of knownStatusCodeFields) {\n const statusCode = (error as any)[field];\n if (\n typeof statusCode === 'number' &&\n (statusCode | 0) === statusCode && // is whole integer\n statusCode >= 100 &&\n statusCode <= 599\n ) {\n return statusCode;\n }\n }\n\n // Handle well-known error types\n switch (error.name) {\n case NotModifiedError.name:\n return 304;\n case InputError.name:\n return 400;\n case AuthenticationError.name:\n return 401;\n case NotAllowedError.name:\n return 403;\n case NotFoundError.name:\n return 404;\n case ConflictError.name:\n return 409;\n case NotImplementedError.name:\n return 501;\n case ServiceUnavailableError.name:\n return 503;\n default:\n break;\n }\n\n // Fall back to internal server error\n return 500;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RootConfigService,\n coreServices,\n createServiceFactory,\n LifecycleService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport express, { RequestHandler, Express } from 'express';\nimport type { Server } from 'node:http';\nimport {\n createHttpServer,\n MiddlewareFactory,\n readHttpServerOptions,\n} from './http';\nimport { DefaultRootHttpRouter } from './DefaultRootHttpRouter';\nimport { createHealthRouter } from './createHealthRouter';\n\n/**\n * @public\n */\nexport interface RootHttpRouterConfigureContext {\n app: Express;\n server: Server;\n middleware: MiddlewareFactory;\n routes: RequestHandler;\n config: RootConfigService;\n logger: LoggerService;\n lifecycle: LifecycleService;\n healthRouter: RequestHandler;\n applyDefaults: () => void;\n}\n\n/**\n * HTTP route registration for root services.\n *\n * See {@link @backstage/code-plugin-api#RootHttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport type RootHttpRouterFactoryOptions = {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n\n configure?(context: RootHttpRouterConfigureContext): void;\n};\n\nfunction defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {\n applyDefaults();\n}\n\nconst rootHttpRouterServiceFactoryWithOptions = (\n options?: RootHttpRouterFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n rootLogger: coreServices.rootLogger,\n lifecycle: coreServices.rootLifecycle,\n health: coreServices.rootHealth,\n },\n async factory({ config, rootLogger, lifecycle, health }) {\n const { indexPath, configure = defaultConfigure } = options ?? {};\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n const app = express();\n\n const router = DefaultRootHttpRouter.create({ indexPath });\n const middleware = MiddlewareFactory.create({ config, logger });\n const routes = router.handler();\n\n const healthRouter = createHealthRouter({ health });\n const server = await createHttpServer(\n app,\n readHttpServerOptions(config.getOptionalConfig('backend')),\n { logger },\n );\n\n configure({\n app,\n server,\n routes,\n middleware,\n config,\n logger,\n lifecycle,\n healthRouter,\n applyDefaults() {\n app.use(middleware.helmet());\n app.use(middleware.cors());\n app.use(middleware.compression());\n app.use(middleware.logging());\n app.use(healthRouter);\n app.use(routes);\n app.use(middleware.notFound());\n app.use(middleware.error());\n },\n });\n\n lifecycle.addShutdownHook(() => server.stop());\n\n await server.start();\n\n return router;\n },\n })();\n\n/** @public */\nexport const rootHttpRouterServiceFactory = Object.assign(\n rootHttpRouterServiceFactoryWithOptions,\n rootHttpRouterServiceFactoryWithOptions(),\n);\n"],"names":["trimEnd","Router","fs","resolvePath","dirname","forge","stoppableServer","https","http","helmet","kebabCase","Minimatch","randomBytes","assertError","compression","morgan","cors","serializeError","NotModifiedError","InputError","AuthenticationError","NotAllowedError","NotFoundError","ConflictError","NotImplementedError","ServiceUnavailableError","createServiceFactory","coreServices","config","express","readHttpServerOptions"],"mappings":"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"}
1
+ {"version":3,"file":"rootHttpRouter.cjs.js","sources":["../src/entrypoints/rootHttpRouter/DefaultRootHttpRouter.ts","../src/entrypoints/rootHttpRouter/createHealthRouter.ts","../src/entrypoints/rootHttpRouter/http/getGeneratedCertificate.ts","../src/entrypoints/rootHttpRouter/http/createHttpServer.ts","../src/entrypoints/rootHttpRouter/http/readHelmetOptions.ts","../src/entrypoints/rootHttpRouter/http/readCorsOptions.ts","../src/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.ts","../src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts","../src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootHttpRouterService } from '@backstage/backend-plugin-api';\nimport { Handler, Router } from 'express';\nimport trimEnd from 'lodash/trimEnd';\n\nfunction normalizePath(path: string): string {\n return `${trimEnd(path, '/')}/`;\n}\n\n/**\n * Options for the {@link DefaultRootHttpRouter} class.\n *\n * @public\n */\nexport interface DefaultRootHttpRouterOptions {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n}\n\n/**\n * The default implementation of the {@link @backstage/backend-plugin-api#RootHttpRouterService} interface for\n * {@link @backstage/backend-plugin-api#coreServices.rootHttpRouter}.\n *\n * @public\n */\nexport class DefaultRootHttpRouter implements RootHttpRouterService {\n #indexPath?: string;\n\n #router = Router();\n #namedRoutes = Router();\n #indexRouter = Router();\n #existingPaths = new Array<string>();\n\n static create(options?: DefaultRootHttpRouterOptions) {\n let indexPath;\n if (options?.indexPath === false) {\n indexPath = undefined;\n } else if (options?.indexPath === undefined) {\n indexPath = '/api/app';\n } else if (options?.indexPath === '') {\n throw new Error('indexPath option may not be an empty string');\n } else {\n indexPath = options.indexPath;\n }\n return new DefaultRootHttpRouter(indexPath);\n }\n\n private constructor(indexPath?: string) {\n this.#indexPath = indexPath;\n this.#router.use(this.#namedRoutes);\n\n // Any request with a /api/ prefix will skip the index router, even if no named router matches\n this.#router.use('/api/', (_req, _res, next) => {\n next('router');\n });\n\n if (this.#indexPath) {\n this.#router.use(this.#indexRouter);\n }\n }\n\n use(path: string, handler: Handler) {\n if (path.match(/^[/\\s]*$/)) {\n throw new Error(`Root router path may not be empty`);\n }\n const conflictingPath = this.#findConflictingPath(path);\n if (conflictingPath) {\n throw new Error(\n `Path ${path} conflicts with the existing path ${conflictingPath}`,\n );\n }\n this.#existingPaths.push(path);\n this.#namedRoutes.use(path, handler);\n\n if (this.#indexPath === path) {\n this.#indexRouter.use(handler);\n }\n }\n\n handler(): Handler {\n return this.#router;\n }\n\n #findConflictingPath(newPath: string): string | undefined {\n const normalizedNewPath = normalizePath(newPath);\n for (const path of this.#existingPaths) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath.startsWith(normalizedNewPath)) {\n return path;\n }\n if (normalizedNewPath.startsWith(normalizedPath)) {\n return path;\n }\n }\n return undefined;\n }\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RootHealthService } from '@backstage/backend-plugin-api';\nimport Router from 'express-promise-router';\nimport { Request, Response } from 'express';\n\n/**\n * @public\n */\nexport function createHealthRouter(options: { health: RootHealthService }) {\n const router = Router();\n\n router.get(\n '/.backstage/health/v1/readiness',\n async (_request: Request, response: Response) => {\n const { status, payload } = await options.health.getReadiness();\n response.status(status).json(payload);\n },\n );\n\n router.get(\n '/.backstage/health/v1/liveness',\n async (_request: Request, response: Response) => {\n const { status, payload } = await options.health.getLiveness();\n response.status(status).json(payload);\n },\n );\n\n return router;\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs-extra';\nimport { resolve as resolvePath, dirname } from 'path';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport forge from 'node-forge';\n\nconst FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1000;\n\nconst IP_HOSTNAME_REGEX = /:|^\\d+\\.\\d+\\.\\d+\\.\\d+$/;\n\nexport async function getGeneratedCertificate(\n hostname: string,\n logger: LoggerService,\n) {\n const hasModules = await fs.pathExists('node_modules');\n let certPath;\n if (hasModules) {\n certPath = resolvePath(\n 'node_modules/.cache/backstage-backend/dev-cert.pem',\n );\n await fs.ensureDir(dirname(certPath));\n } else {\n certPath = resolvePath('.dev-cert.pem');\n }\n\n if (await fs.pathExists(certPath)) {\n try {\n const cert = await fs.readFile(certPath);\n\n const crt = forge.pki.certificateFromPem(cert.toString());\n const remainingMs = crt.validity.notAfter.getTime() - Date.now();\n if (remainingMs > FIVE_DAYS_IN_MS) {\n logger.info('Using existing self-signed certificate');\n return {\n key: cert,\n cert,\n };\n }\n } catch (error) {\n logger.warn(`Unable to use existing self-signed certificate, ${error}`);\n }\n }\n\n logger.info('Generating new self-signed certificate');\n const newCert = await generateCertificate(hostname);\n await fs.writeFile(certPath, newCert.cert + newCert.key, 'utf8');\n return newCert;\n}\n\nasync function generateCertificate(hostname: string) {\n const attributes = [\n {\n name: 'commonName',\n value: 'dev-cert',\n },\n ];\n\n const sans = [\n {\n type: 2, // DNS\n value: 'localhost',\n },\n {\n type: 2,\n value: 'localhost.localdomain',\n },\n {\n type: 2,\n value: '[::1]',\n },\n {\n type: 7, // IP\n ip: '127.0.0.1',\n },\n {\n type: 7,\n ip: 'fe80::1',\n },\n ];\n\n // Add hostname from backend.baseUrl if it doesn't already exist in our list of SANs\n if (!sans.find(({ value, ip }) => value === hostname || ip === hostname)) {\n sans.push(\n IP_HOSTNAME_REGEX.test(hostname)\n ? {\n type: 7,\n ip: hostname,\n }\n : {\n type: 2,\n value: hostname,\n },\n );\n }\n\n const params = {\n algorithm: 'sha256',\n keySize: 2048,\n days: 30,\n extensions: [\n {\n name: 'keyUsage',\n keyCertSign: true,\n digitalSignature: true,\n nonRepudiation: true,\n keyEncipherment: true,\n dataEncipherment: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n codeSigning: true,\n timeStamping: true,\n },\n {\n name: 'subjectAltName',\n altNames: sans,\n },\n ],\n };\n\n return new Promise<{ key: string; cert: string }>((resolve, reject) =>\n require('selfsigned').generate(\n attributes,\n params,\n (err: Error, bundle: { private: string; cert: string }) => {\n if (err) {\n reject(err);\n } else {\n resolve({ key: bundle.private, cert: bundle.cert });\n }\n },\n ),\n );\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport * as http from 'http';\nimport * as https from 'https';\nimport stoppableServer from 'stoppable';\nimport { RequestListener } from 'http';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { HttpServerOptions, ExtendedHttpServer } from './types';\nimport { getGeneratedCertificate } from './getGeneratedCertificate';\n\n/**\n * Creates a Node.js HTTP or HTTPS server instance.\n *\n * @public\n */\nexport async function createHttpServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<ExtendedHttpServer> {\n const server = await createServer(listener, options, deps);\n\n const stopper = stoppableServer(server, 0);\n // The stopper here is actually the server itself, so if we try\n // to call stopper.stop() down in the stop implementation, we'll\n // be calling ourselves.\n const stopServer = stopper.stop.bind(stopper);\n\n return Object.assign(server, {\n start() {\n return new Promise<void>((resolve, reject) => {\n const handleStartupError = (error: Error) => {\n server.close();\n reject(error);\n };\n\n server.on('error', handleStartupError);\n\n const { host, port } = options.listen;\n server.listen(port, host, () => {\n server.off('error', handleStartupError);\n deps.logger.info(`Listening on ${host}:${port}`);\n resolve();\n });\n });\n },\n\n stop() {\n return new Promise<void>((resolve, reject) => {\n stopServer((error?: Error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n },\n\n port() {\n const address = server.address();\n if (typeof address === 'string' || address === null) {\n throw new Error(`Unexpected server address '${address}'`);\n }\n return address.port;\n },\n });\n}\n\nasync function createServer(\n listener: RequestListener,\n options: HttpServerOptions,\n deps: { logger: LoggerService },\n): Promise<http.Server> {\n if (options.https) {\n const { certificate } = options.https;\n if (certificate.type === 'generated') {\n const credentials = await getGeneratedCertificate(\n certificate.hostname,\n deps.logger,\n );\n return https.createServer(credentials, listener);\n }\n return https.createServer(certificate, listener);\n }\n\n return http.createServer(listener);\n}\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport helmet from 'helmet';\nimport { HelmetOptions } from 'helmet';\nimport { ContentSecurityPolicyOptions } from 'helmet/dist/types/middlewares/content-security-policy';\nimport kebabCase from 'lodash/kebabCase';\n\n/**\n * Attempts to read Helmet options from the backend configuration object.\n *\n * @public\n * @param config - The backend configuration object.\n * @returns A Helmet options object, or undefined if no Helmet configuration is present.\n *\n * @example\n * ```ts\n * const helmetOptions = readHelmetOptions(config.getConfig('backend'));\n * ```\n */\nexport function readHelmetOptions(config?: Config): HelmetOptions {\n const cspOptions = readCspDirectives(config);\n return {\n contentSecurityPolicy: {\n useDefaults: false,\n directives: applyCspDirectives(cspOptions),\n },\n // These are all disabled in order to maintain backwards compatibility\n // when bumping helmet v5. We can't enable these by default because\n // there is no way for users to configure them.\n // TODO(Rugvip): We should give control of this setup to consumers\n crossOriginEmbedderPolicy: false,\n crossOriginOpenerPolicy: false,\n crossOriginResourcePolicy: false,\n originAgentCluster: false,\n };\n}\n\ntype CspDirectives = Record<string, string[] | false> | undefined;\n\n/**\n * Attempts to read a CSP directives from the backend configuration object.\n *\n * @example\n * ```yaml\n * backend:\n * csp:\n * connect-src: [\"'self'\", 'http:', 'https:']\n * upgrade-insecure-requests: false\n * ```\n */\nfunction readCspDirectives(config?: Config): CspDirectives {\n const cc = config?.getOptionalConfig('csp');\n if (!cc) {\n return undefined;\n }\n\n const result: Record<string, string[] | false> = {};\n for (const key of cc.keys()) {\n if (cc.get(key) === false) {\n result[key] = false;\n } else {\n result[key] = cc.getStringArray(key);\n }\n }\n\n return result;\n}\n\nexport function applyCspDirectives(\n directives: CspDirectives,\n): ContentSecurityPolicyOptions['directives'] {\n const result: ContentSecurityPolicyOptions['directives'] =\n helmet.contentSecurityPolicy.getDefaultDirectives();\n\n // TODO(Rugvip): We currently use non-precompiled AJV for validation in the frontend, which uses eval.\n // It should be replaced by any other solution that doesn't require unsafe-eval.\n result['script-src'] = [\"'self'\", \"'unsafe-eval'\"];\n\n // TODO(Rugvip): This is removed so that we maintained backwards compatibility\n // when bumping to helmet v5, we could remove this as well as\n // skip setting `useDefaults: false` in the future.\n delete result['form-action'];\n\n if (directives) {\n for (const [key, value] of Object.entries(directives)) {\n const kebabCaseKey = kebabCase(key);\n if (value === false) {\n delete result[kebabCaseKey];\n } else {\n result[kebabCaseKey] = value;\n }\n }\n }\n\n return result;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport { CorsOptions } from 'cors';\nimport { Minimatch } from 'minimatch';\n\n/**\n * Attempts to read a CORS options object from the backend configuration object.\n *\n * @public\n * @param config - The backend configuration object.\n * @returns A CORS options object, or undefined if no cors configuration is present.\n *\n * @example\n * ```ts\n * const corsOptions = readCorsOptions(config.getConfig('backend'));\n * ```\n */\nexport function readCorsOptions(config?: Config): CorsOptions {\n const cc = config?.getOptionalConfig('cors');\n if (!cc) {\n return { origin: false }; // Disable CORS\n }\n\n return removeUnknown({\n origin: createCorsOriginMatcher(readStringArray(cc, 'origin')),\n methods: readStringArray(cc, 'methods'),\n allowedHeaders: readStringArray(cc, 'allowedHeaders'),\n exposedHeaders: readStringArray(cc, 'exposedHeaders'),\n credentials: cc.getOptionalBoolean('credentials'),\n maxAge: cc.getOptionalNumber('maxAge'),\n preflightContinue: cc.getOptionalBoolean('preflightContinue'),\n optionsSuccessStatus: cc.getOptionalNumber('optionsSuccessStatus'),\n });\n}\n\nfunction removeUnknown<T extends object>(obj: T): T {\n return Object.fromEntries(\n Object.entries(obj).filter(([, v]) => v !== undefined),\n ) as T;\n}\n\nfunction readStringArray(config: Config, key: string): string[] | undefined {\n const value = config.getOptional(key);\n if (typeof value === 'string') {\n return [value];\n } else if (!value) {\n return undefined;\n }\n return config.getStringArray(key);\n}\n\nfunction createCorsOriginMatcher(allowedOriginPatterns: string[] | undefined) {\n if (!allowedOriginPatterns) {\n return undefined;\n }\n\n const allowedOriginMatchers = allowedOriginPatterns.map(\n pattern => new Minimatch(pattern, { nocase: true, noglobstar: true }),\n );\n\n return (\n origin: string | undefined,\n callback: (\n err: Error | null,\n origin: boolean | string | RegExp | (boolean | string | RegExp)[],\n ) => void,\n ) => {\n return callback(\n null,\n allowedOriginMatchers.some(pattern => pattern.match(origin ?? '')),\n );\n };\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { assertError } from '@backstage/errors';\nimport { randomBytes } from 'crypto';\n\nfunction handleBadError(error: Error, logger: LoggerService) {\n const logId = randomBytes(10).toString('hex');\n logger\n .child({ logId })\n .error(`Filtered internal error with logId=${logId} from response`, error);\n const newError = new Error(`An internal error occurred logId=${logId}`);\n delete newError.stack; // Trim the stack since it's not particularly useful\n return newError;\n}\n\n/**\n * Filters out certain known error types that should never be returned in responses.\n *\n * @internal\n */\nexport function applyInternalErrorFilter(\n error: unknown,\n logger: LoggerService,\n): Error {\n try {\n assertError(error);\n } catch (assertionError: unknown) {\n assertError(assertionError);\n return handleBadError(assertionError, logger);\n }\n\n const constructorName = error.constructor.name;\n\n // DatabaseError are thrown by the pg-protocol module\n if (constructorName === 'DatabaseError') {\n return handleBadError(error, logger);\n }\n\n return error;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RootConfigService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport {\n Request,\n Response,\n ErrorRequestHandler,\n NextFunction,\n RequestHandler,\n} from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport morgan from 'morgan';\nimport compression from 'compression';\nimport { readHelmetOptions } from './readHelmetOptions';\nimport { readCorsOptions } from './readCorsOptions';\nimport {\n AuthenticationError,\n ConflictError,\n ErrorResponseBody,\n InputError,\n NotAllowedError,\n NotFoundError,\n NotModifiedError,\n ServiceUnavailableError,\n serializeError,\n} from '@backstage/errors';\nimport { NotImplementedError } from '@backstage/errors';\nimport { applyInternalErrorFilter } from './applyInternalErrorFilter';\n\n/**\n * Options used to create a {@link MiddlewareFactory}.\n *\n * @public\n */\nexport interface MiddlewareFactoryOptions {\n config: RootConfigService;\n logger: LoggerService;\n}\n\n/**\n * Options passed to the {@link MiddlewareFactory.error} middleware.\n *\n * @public\n */\nexport interface MiddlewareFactoryErrorOptions {\n /**\n * Whether error response bodies should show error stack traces or not.\n *\n * If not specified, by default shows stack traces only in development mode.\n */\n showStackTraces?: boolean;\n\n /**\n * Whether any 4xx errors should be logged or not.\n *\n * If not specified, default to only logging 5xx errors.\n */\n logAllErrors?: boolean;\n}\n\n/**\n * A utility to configure common middleware.\n *\n * @public\n */\nexport class MiddlewareFactory {\n #config: RootConfigService;\n #logger: LoggerService;\n\n /**\n * Creates a new {@link MiddlewareFactory}.\n */\n static create(options: MiddlewareFactoryOptions) {\n return new MiddlewareFactory(options);\n }\n\n private constructor(options: MiddlewareFactoryOptions) {\n this.#config = options.config;\n this.#logger = options.logger;\n }\n\n /**\n * Returns a middleware that unconditionally produces a 404 error response.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the end of the chain, such\n * that it's the last one attempted after no other routes matched.\n *\n * @returns An Express request handler\n */\n notFound(): RequestHandler {\n return (_req: Request, res: Response) => {\n res.status(404).end();\n };\n }\n\n /**\n * Returns the compression middleware.\n *\n * @remarks\n *\n * The middleware will attempt to compress response bodies for all requests\n * that traverse through the middleware.\n */\n compression(): RequestHandler {\n return compression();\n }\n\n /**\n * Returns a request logging middleware.\n *\n * @remarks\n *\n * Typically you want to place this middleware at the start of the chain, such\n * that it always logs requests whether they are \"caught\" by handlers farther\n * down or not.\n *\n * @returns An Express request handler\n */\n logging(): RequestHandler {\n const logger = this.#logger.child({\n type: 'incomingRequest',\n });\n const customMorganFormat =\n '[:date[clf]] \":method :url HTTP/:http-version\" :status :res[content-length] \":referrer\" \":user-agent\"';\n return morgan(customMorganFormat, {\n stream: {\n write(message: string) {\n logger.info(message.trimEnd());\n },\n },\n });\n }\n\n /**\n * Returns a middleware that implements the helmet library.\n *\n * @remarks\n *\n * This middleware applies security policies to incoming requests and outgoing\n * responses. It is configured using config keys such as `backend.csp`.\n *\n * @see {@link https://helmetjs.github.io/}\n *\n * @returns An Express request handler\n */\n helmet(): RequestHandler {\n return helmet(readHelmetOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Returns a middleware that implements the cors library.\n *\n * @remarks\n *\n * This middleware handles CORS. It is configured using the config key\n * `backend.cors`.\n *\n * @see {@link https://github.com/expressjs/cors}\n *\n * @returns An Express request handler\n */\n cors(): RequestHandler {\n return cors(readCorsOptions(this.#config.getOptionalConfig('backend')));\n }\n\n /**\n * Express middleware to handle errors during request processing.\n *\n * @remarks\n *\n * This is commonly the very last middleware in the chain.\n *\n * Its primary purpose is not to do translation of business logic exceptions,\n * but rather to be a global catch-all for uncaught \"fatal\" errors that are\n * expected to result in a 500 error. However, it also does handle some common\n * error types (such as http-error exceptions, and the well-known error types\n * in the `@backstage/errors` package) and returns the enclosed status code\n * accordingly.\n *\n * It will also produce a response body with a serialized form of the error,\n * unless a previous handler already did send a body. See\n * {@link @backstage/errors#ErrorResponseBody} for the response shape used.\n *\n * @returns An Express error request handler\n */\n error(options: MiddlewareFactoryErrorOptions = {}): ErrorRequestHandler {\n const showStackTraces =\n options.showStackTraces ?? process.env.NODE_ENV === 'development';\n\n const logger = this.#logger.child({\n type: 'errorHandler',\n });\n\n return (\n rawError: Error,\n req: Request,\n res: Response,\n next: NextFunction,\n ) => {\n const error = applyInternalErrorFilter(rawError, logger);\n\n const statusCode = getStatusCode(error);\n if (options.logAllErrors || statusCode >= 500) {\n logger.error(`Request failed with status ${statusCode}`, error);\n }\n\n if (res.headersSent) {\n // If the headers have already been sent, do not send the response again\n // as this will throw an error in the backend.\n next(error);\n return;\n }\n\n const body: ErrorResponseBody = {\n error: serializeError(error, { includeStack: showStackTraces }),\n request: { method: req.method, url: req.url },\n response: { statusCode },\n };\n\n res.status(statusCode).json(body);\n };\n }\n}\n\nfunction getStatusCode(error: Error): number {\n // Look for common http library status codes\n const knownStatusCodeFields = ['statusCode', 'status'];\n for (const field of knownStatusCodeFields) {\n const statusCode = (error as any)[field];\n if (\n typeof statusCode === 'number' &&\n (statusCode | 0) === statusCode && // is whole integer\n statusCode >= 100 &&\n statusCode <= 599\n ) {\n return statusCode;\n }\n }\n\n // Handle well-known error types\n switch (error.name) {\n case NotModifiedError.name:\n return 304;\n case InputError.name:\n return 400;\n case AuthenticationError.name:\n return 401;\n case NotAllowedError.name:\n return 403;\n case NotFoundError.name:\n return 404;\n case ConflictError.name:\n return 409;\n case NotImplementedError.name:\n return 501;\n case ServiceUnavailableError.name:\n return 503;\n default:\n break;\n }\n\n // Fall back to internal server error\n return 500;\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RootConfigService,\n coreServices,\n createServiceFactory,\n LifecycleService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport express, { RequestHandler, Express } from 'express';\nimport type { Server } from 'node:http';\nimport {\n createHttpServer,\n MiddlewareFactory,\n readHttpServerOptions,\n} from './http';\nimport { DefaultRootHttpRouter } from './DefaultRootHttpRouter';\nimport { createHealthRouter } from './createHealthRouter';\n\n/**\n * @public\n */\nexport interface RootHttpRouterConfigureContext {\n app: Express;\n server: Server;\n middleware: MiddlewareFactory;\n routes: RequestHandler;\n config: RootConfigService;\n logger: LoggerService;\n lifecycle: LifecycleService;\n healthRouter: RequestHandler;\n applyDefaults: () => void;\n}\n\n/**\n * HTTP route registration for root services.\n *\n * See {@link @backstage/code-plugin-api#RootHttpRouterService}\n * and {@link https://backstage.io/docs/backend-system/core-services/root-http-router | the service docs}\n * for more information.\n *\n * @public\n */\nexport type RootHttpRouterFactoryOptions = {\n /**\n * The path to forward all unmatched requests to. Defaults to '/api/app' if\n * not given. Disables index path behavior if false is given.\n */\n indexPath?: string | false;\n\n configure?(context: RootHttpRouterConfigureContext): void;\n};\n\nfunction defaultConfigure({ applyDefaults }: RootHttpRouterConfigureContext) {\n applyDefaults();\n}\n\nconst rootHttpRouterServiceFactoryWithOptions = (\n options?: RootHttpRouterFactoryOptions,\n) =>\n createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n rootLogger: coreServices.rootLogger,\n lifecycle: coreServices.rootLifecycle,\n health: coreServices.rootHealth,\n },\n async factory({ config, rootLogger, lifecycle, health }) {\n const { indexPath, configure = defaultConfigure } = options ?? {};\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n const app = express();\n\n const router = DefaultRootHttpRouter.create({ indexPath });\n const middleware = MiddlewareFactory.create({ config, logger });\n const routes = router.handler();\n\n const healthRouter = createHealthRouter({ health });\n const server = await createHttpServer(\n app,\n readHttpServerOptions(config.getOptionalConfig('backend')),\n { logger },\n );\n\n configure({\n app,\n server,\n routes,\n middleware,\n config,\n logger,\n lifecycle,\n healthRouter,\n applyDefaults() {\n app.use(middleware.helmet());\n app.use(middleware.cors());\n app.use(middleware.compression());\n app.use(middleware.logging());\n app.use(healthRouter);\n app.use(routes);\n app.use(middleware.notFound());\n app.use(middleware.error());\n },\n });\n\n lifecycle.addShutdownHook(() => server.stop());\n\n await server.start();\n\n return router;\n },\n })();\n\n/** @public */\nexport const rootHttpRouterServiceFactory = Object.assign(\n rootHttpRouterServiceFactoryWithOptions,\n rootHttpRouterServiceFactoryWithOptions(),\n);\n"],"names":["trimEnd","Router","fs","resolvePath","dirname","forge","stoppableServer","https","http","helmet","kebabCase","Minimatch","randomBytes","assertError","compression","morgan","cors","serializeError","NotModifiedError","InputError","AuthenticationError","NotAllowedError","NotFoundError","ConflictError","NotImplementedError","ServiceUnavailableError","createServiceFactory","coreServices","config","express","readHttpServerOptions"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,cAAc,IAAsB,EAAA;AAC3C,EAAA,OAAO,CAAG,EAAAA,wBAAA,CAAQ,IAAM,EAAA,GAAG,CAAC,CAAA,CAAA,CAAA,CAAA;AAC9B,CAAA;AAqBO,MAAM,qBAAuD,CAAA;AAAA,EAClE,UAAA,CAAA;AAAA,EAEA,UAAUC,cAAO,EAAA,CAAA;AAAA,EACjB,eAAeA,cAAO,EAAA,CAAA;AAAA,EACtB,eAAeA,cAAO,EAAA,CAAA;AAAA,EACtB,cAAA,GAAiB,IAAI,KAAc,EAAA,CAAA;AAAA,EAEnC,OAAO,OAAO,OAAwC,EAAA;AACpD,IAAI,IAAA,SAAA,CAAA;AACJ,IAAI,IAAA,OAAA,EAAS,cAAc,KAAO,EAAA;AAChC,MAAY,SAAA,GAAA,KAAA,CAAA,CAAA;AAAA,KACd,MAAA,IAAW,OAAS,EAAA,SAAA,KAAc,KAAW,CAAA,EAAA;AAC3C,MAAY,SAAA,GAAA,UAAA,CAAA;AAAA,KACd,MAAA,IAAW,OAAS,EAAA,SAAA,KAAc,EAAI,EAAA;AACpC,MAAM,MAAA,IAAI,MAAM,6CAA6C,CAAA,CAAA;AAAA,KACxD,MAAA;AACL,MAAA,SAAA,GAAY,OAAQ,CAAA,SAAA,CAAA;AAAA,KACtB;AACA,IAAO,OAAA,IAAI,sBAAsB,SAAS,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEQ,YAAY,SAAoB,EAAA;AACtC,IAAA,IAAA,CAAK,UAAa,GAAA,SAAA,CAAA;AAClB,IAAK,IAAA,CAAA,OAAA,CAAQ,GAAI,CAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AAGlC,IAAA,IAAA,CAAK,QAAQ,GAAI,CAAA,OAAA,EAAS,CAAC,IAAA,EAAM,MAAM,IAAS,KAAA;AAC9C,MAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,KACd,CAAA,CAAA;AAED,IAAA,IAAI,KAAK,UAAY,EAAA;AACnB,MAAK,IAAA,CAAA,OAAA,CAAQ,GAAI,CAAA,IAAA,CAAK,YAAY,CAAA,CAAA;AAAA,KACpC;AAAA,GACF;AAAA,EAEA,GAAA,CAAI,MAAc,OAAkB,EAAA;AAClC,IAAI,IAAA,IAAA,CAAK,KAAM,CAAA,UAAU,CAAG,EAAA;AAC1B,MAAM,MAAA,IAAI,MAAM,CAAmC,iCAAA,CAAA,CAAA,CAAA;AAAA,KACrD;AACA,IAAM,MAAA,eAAA,GAAkB,IAAK,CAAA,oBAAA,CAAqB,IAAI,CAAA,CAAA;AACtD,IAAA,IAAI,eAAiB,EAAA;AACnB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,KAAA,EAAQ,IAAI,CAAA,kCAAA,EAAqC,eAAe,CAAA,CAAA;AAAA,OAClE,CAAA;AAAA,KACF;AACA,IAAK,IAAA,CAAA,cAAA,CAAe,KAAK,IAAI,CAAA,CAAA;AAC7B,IAAK,IAAA,CAAA,YAAA,CAAa,GAAI,CAAA,IAAA,EAAM,OAAO,CAAA,CAAA;AAEnC,IAAI,IAAA,IAAA,CAAK,eAAe,IAAM,EAAA;AAC5B,MAAK,IAAA,CAAA,YAAA,CAAa,IAAI,OAAO,CAAA,CAAA;AAAA,KAC/B;AAAA,GACF;AAAA,EAEA,OAAmB,GAAA;AACjB,IAAA,OAAO,IAAK,CAAA,OAAA,CAAA;AAAA,GACd;AAAA,EAEA,qBAAqB,OAAqC,EAAA;AACxD,IAAM,MAAA,iBAAA,GAAoB,cAAc,OAAO,CAAA,CAAA;AAC/C,IAAW,KAAA,MAAA,IAAA,IAAQ,KAAK,cAAgB,EAAA;AACtC,MAAM,MAAA,cAAA,GAAiB,cAAc,IAAI,CAAA,CAAA;AACzC,MAAI,IAAA,cAAA,CAAe,UAAW,CAAA,iBAAiB,CAAG,EAAA;AAChD,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AACA,MAAI,IAAA,iBAAA,CAAkB,UAAW,CAAA,cAAc,CAAG,EAAA;AAChD,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,KACF;AACA,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AACF;;AC3FO,SAAS,mBAAmB,OAAwC,EAAA;AACzE,EAAA,MAAM,SAASA,uBAAO,EAAA,CAAA;AAEtB,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,iCAAA;AAAA,IACA,OAAO,UAAmB,QAAuB,KAAA;AAC/C,MAAA,MAAM,EAAE,MAAQ,EAAA,OAAA,KAAY,MAAM,OAAA,CAAQ,OAAO,YAAa,EAAA,CAAA;AAC9D,MAAA,QAAA,CAAS,MAAO,CAAA,MAAM,CAAE,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,KACtC;AAAA,GACF,CAAA;AAEA,EAAO,MAAA,CAAA,GAAA;AAAA,IACL,gCAAA;AAAA,IACA,OAAO,UAAmB,QAAuB,KAAA;AAC/C,MAAA,MAAM,EAAE,MAAQ,EAAA,OAAA,KAAY,MAAM,OAAA,CAAQ,OAAO,WAAY,EAAA,CAAA;AAC7D,MAAA,QAAA,CAAS,MAAO,CAAA,MAAM,CAAE,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,KACtC;AAAA,GACF,CAAA;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;ACtBA,MAAM,eAAkB,GAAA,CAAA,GAAI,EAAK,GAAA,EAAA,GAAK,EAAK,GAAA,GAAA,CAAA;AAE3C,MAAM,iBAAoB,GAAA,wBAAA,CAAA;AAEJ,eAAA,uBAAA,CACpB,UACA,MACA,EAAA;AACA,EAAA,MAAM,UAAa,GAAA,MAAMC,mBAAG,CAAA,UAAA,CAAW,cAAc,CAAA,CAAA;AACrD,EAAI,IAAA,QAAA,CAAA;AACJ,EAAA,IAAI,UAAY,EAAA;AACd,IAAW,QAAA,GAAAC,oBAAA;AAAA,MACT,oDAAA;AAAA,KACF,CAAA;AACA,IAAA,MAAMD,mBAAG,CAAA,SAAA,CAAUE,oBAAQ,CAAA,QAAQ,CAAC,CAAA,CAAA;AAAA,GAC/B,MAAA;AACL,IAAA,QAAA,GAAWD,qBAAY,eAAe,CAAA,CAAA;AAAA,GACxC;AAEA,EAAA,IAAI,MAAMD,mBAAA,CAAG,UAAW,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAI,IAAA;AACF,MAAA,MAAM,IAAO,GAAA,MAAMA,mBAAG,CAAA,QAAA,CAAS,QAAQ,CAAA,CAAA;AAEvC,MAAA,MAAM,MAAMG,sBAAM,CAAA,GAAA,CAAI,kBAAmB,CAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AACxD,MAAA,MAAM,cAAc,GAAI,CAAA,QAAA,CAAS,SAAS,OAAQ,EAAA,GAAI,KAAK,GAAI,EAAA,CAAA;AAC/D,MAAA,IAAI,cAAc,eAAiB,EAAA;AACjC,QAAA,MAAA,CAAO,KAAK,wCAAwC,CAAA,CAAA;AACpD,QAAO,OAAA;AAAA,UACL,GAAK,EAAA,IAAA;AAAA,UACL,IAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,aACO,KAAO,EAAA;AACd,MAAO,MAAA,CAAA,IAAA,CAAK,CAAmD,gDAAA,EAAA,KAAK,CAAE,CAAA,CAAA,CAAA;AAAA,KACxE;AAAA,GACF;AAEA,EAAA,MAAA,CAAO,KAAK,wCAAwC,CAAA,CAAA;AACpD,EAAM,MAAA,OAAA,GAAU,MAAM,mBAAA,CAAoB,QAAQ,CAAA,CAAA;AAClD,EAAA,MAAMH,oBAAG,SAAU,CAAA,QAAA,EAAU,QAAQ,IAAO,GAAA,OAAA,CAAQ,KAAK,MAAM,CAAA,CAAA;AAC/D,EAAO,OAAA,OAAA,CAAA;AACT,CAAA;AAEA,eAAe,oBAAoB,QAAkB,EAAA;AACnD,EAAA,MAAM,UAAa,GAAA;AAAA,IACjB;AAAA,MACE,IAAM,EAAA,YAAA;AAAA,MACN,KAAO,EAAA,UAAA;AAAA,KACT;AAAA,GACF,CAAA;AAEA,EAAA,MAAM,IAAO,GAAA;AAAA,IACX;AAAA,MACE,IAAM,EAAA,CAAA;AAAA;AAAA,MACN,KAAO,EAAA,WAAA;AAAA,KACT;AAAA,IACA;AAAA,MACE,IAAM,EAAA,CAAA;AAAA,MACN,KAAO,EAAA,uBAAA;AAAA,KACT;AAAA,IACA;AAAA,MACE,IAAM,EAAA,CAAA;AAAA,MACN,KAAO,EAAA,OAAA;AAAA,KACT;AAAA,IACA;AAAA,MACE,IAAM,EAAA,CAAA;AAAA;AAAA,MACN,EAAI,EAAA,WAAA;AAAA,KACN;AAAA,IACA;AAAA,MACE,IAAM,EAAA,CAAA;AAAA,MACN,EAAI,EAAA,SAAA;AAAA,KACN;AAAA,GACF,CAAA;AAGA,EAAA,IAAI,CAAC,IAAA,CAAK,IAAK,CAAA,CAAC,EAAE,KAAA,EAAO,EAAG,EAAA,KAAM,KAAU,KAAA,QAAA,IAAY,EAAO,KAAA,QAAQ,CAAG,EAAA;AACxE,IAAK,IAAA,CAAA,IAAA;AAAA,MACH,iBAAA,CAAkB,IAAK,CAAA,QAAQ,CAC3B,GAAA;AAAA,QACE,IAAM,EAAA,CAAA;AAAA,QACN,EAAI,EAAA,QAAA;AAAA,OAEN,GAAA;AAAA,QACE,IAAM,EAAA,CAAA;AAAA,QACN,KAAO,EAAA,QAAA;AAAA,OACT;AAAA,KACN,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,MAAS,GAAA;AAAA,IACb,SAAW,EAAA,QAAA;AAAA,IACX,OAAS,EAAA,IAAA;AAAA,IACT,IAAM,EAAA,EAAA;AAAA,IACN,UAAY,EAAA;AAAA,MACV;AAAA,QACE,IAAM,EAAA,UAAA;AAAA,QACN,WAAa,EAAA,IAAA;AAAA,QACb,gBAAkB,EAAA,IAAA;AAAA,QAClB,cAAgB,EAAA,IAAA;AAAA,QAChB,eAAiB,EAAA,IAAA;AAAA,QACjB,gBAAkB,EAAA,IAAA;AAAA,OACpB;AAAA,MACA;AAAA,QACE,IAAM,EAAA,aAAA;AAAA,QACN,UAAY,EAAA,IAAA;AAAA,QACZ,UAAY,EAAA,IAAA;AAAA,QACZ,WAAa,EAAA,IAAA;AAAA,QACb,YAAc,EAAA,IAAA;AAAA,OAChB;AAAA,MACA;AAAA,QACE,IAAM,EAAA,gBAAA;AAAA,QACN,QAAU,EAAA,IAAA;AAAA,OACZ;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAA,OAAO,IAAI,OAAA;AAAA,IAAuC,CAAC,OAAA,EAAS,MAC1D,KAAA,OAAA,CAAQ,YAAY,CAAE,CAAA,QAAA;AAAA,MACpB,UAAA;AAAA,MACA,MAAA;AAAA,MACA,CAAC,KAAY,MAA8C,KAAA;AACzD,QAAA,IAAI,GAAK,EAAA;AACP,UAAA,MAAA,CAAO,GAAG,CAAA,CAAA;AAAA,SACL,MAAA;AACL,UAAA,OAAA,CAAQ,EAAE,GAAK,EAAA,MAAA,CAAO,SAAS,IAAM,EAAA,MAAA,CAAO,MAAM,CAAA,CAAA;AAAA,SACpD;AAAA,OACF;AAAA,KACF;AAAA,GACF,CAAA;AACF;;ACzHsB,eAAA,gBAAA,CACpB,QACA,EAAA,OAAA,EACA,IAC6B,EAAA;AAC7B,EAAA,MAAM,MAAS,GAAA,MAAM,YAAa,CAAA,QAAA,EAAU,SAAS,IAAI,CAAA,CAAA;AAEzD,EAAM,MAAA,OAAA,GAAUI,gCAAgB,CAAA,MAAA,EAAQ,CAAC,CAAA,CAAA;AAIzC,EAAA,MAAM,UAAa,GAAA,OAAA,CAAQ,IAAK,CAAA,IAAA,CAAK,OAAO,CAAA,CAAA;AAE5C,EAAO,OAAA,MAAA,CAAO,OAAO,MAAQ,EAAA;AAAA,IAC3B,KAAQ,GAAA;AACN,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAW,KAAA;AAC5C,QAAM,MAAA,kBAAA,GAAqB,CAAC,KAAiB,KAAA;AAC3C,UAAA,MAAA,CAAO,KAAM,EAAA,CAAA;AACb,UAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAAA,SACd,CAAA;AAEA,QAAO,MAAA,CAAA,EAAA,CAAG,SAAS,kBAAkB,CAAA,CAAA;AAErC,QAAA,MAAM,EAAE,IAAA,EAAM,IAAK,EAAA,GAAI,OAAQ,CAAA,MAAA,CAAA;AAC/B,QAAO,MAAA,CAAA,MAAA,CAAO,IAAM,EAAA,IAAA,EAAM,MAAM;AAC9B,UAAO,MAAA,CAAA,GAAA,CAAI,SAAS,kBAAkB,CAAA,CAAA;AACtC,UAAA,IAAA,CAAK,OAAO,IAAK,CAAA,CAAA,aAAA,EAAgB,IAAI,CAAA,CAAA,EAAI,IAAI,CAAE,CAAA,CAAA,CAAA;AAC/C,UAAQ,OAAA,EAAA,CAAA;AAAA,SACT,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AAAA,KACH;AAAA,IAEA,IAAO,GAAA;AACL,MAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAW,KAAA;AAC5C,QAAA,UAAA,CAAW,CAAC,KAAkB,KAAA;AAC5B,UAAA,IAAI,KAAO,EAAA;AACT,YAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAAA,WACP,MAAA;AACL,YAAQ,OAAA,EAAA,CAAA;AAAA,WACV;AAAA,SACD,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AAAA,KACH;AAAA,IAEA,IAAO,GAAA;AACL,MAAM,MAAA,OAAA,GAAU,OAAO,OAAQ,EAAA,CAAA;AAC/B,MAAA,IAAI,OAAO,OAAA,KAAY,QAAY,IAAA,OAAA,KAAY,IAAM,EAAA;AACnD,QAAA,MAAM,IAAI,KAAA,CAAM,CAA8B,2BAAA,EAAA,OAAO,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,OAC1D;AACA,MAAA,OAAO,OAAQ,CAAA,IAAA,CAAA;AAAA,KACjB;AAAA,GACD,CAAA,CAAA;AACH,CAAA;AAEA,eAAe,YAAA,CACb,QACA,EAAA,OAAA,EACA,IACsB,EAAA;AACtB,EAAA,IAAI,QAAQ,KAAO,EAAA;AACjB,IAAM,MAAA,EAAE,WAAY,EAAA,GAAI,OAAQ,CAAA,KAAA,CAAA;AAChC,IAAI,IAAA,WAAA,CAAY,SAAS,WAAa,EAAA;AACpC,MAAA,MAAM,cAAc,MAAM,uBAAA;AAAA,QACxB,WAAY,CAAA,QAAA;AAAA,QACZ,IAAK,CAAA,MAAA;AAAA,OACP,CAAA;AACA,MAAO,OAAAC,gBAAA,CAAM,YAAa,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAAA,KACjD;AACA,IAAO,OAAAA,gBAAA,CAAM,YAAa,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAAA,GACjD;AAEA,EAAO,OAAAC,eAAA,CAAK,aAAa,QAAQ,CAAA,CAAA;AACnC;;ACnEO,SAAS,kBAAkB,MAAgC,EAAA;AAChE,EAAM,MAAA,UAAA,GAAa,kBAAkB,MAAM,CAAA,CAAA;AAC3C,EAAO,OAAA;AAAA,IACL,qBAAuB,EAAA;AAAA,MACrB,WAAa,EAAA,KAAA;AAAA,MACb,UAAA,EAAY,mBAAmB,UAAU,CAAA;AAAA,KAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,yBAA2B,EAAA,KAAA;AAAA,IAC3B,uBAAyB,EAAA,KAAA;AAAA,IACzB,yBAA2B,EAAA,KAAA;AAAA,IAC3B,kBAAoB,EAAA,KAAA;AAAA,GACtB,CAAA;AACF,CAAA;AAeA,SAAS,kBAAkB,MAAgC,EAAA;AACzD,EAAM,MAAA,EAAA,GAAK,MAAQ,EAAA,iBAAA,CAAkB,KAAK,CAAA,CAAA;AAC1C,EAAA,IAAI,CAAC,EAAI,EAAA;AACP,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AAEA,EAAA,MAAM,SAA2C,EAAC,CAAA;AAClD,EAAW,KAAA,MAAA,GAAA,IAAO,EAAG,CAAA,IAAA,EAAQ,EAAA;AAC3B,IAAA,IAAI,EAAG,CAAA,GAAA,CAAI,GAAG,CAAA,KAAM,KAAO,EAAA;AACzB,MAAA,MAAA,CAAO,GAAG,CAAI,GAAA,KAAA,CAAA;AAAA,KACT,MAAA;AACL,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,EAAG,CAAA,cAAA,CAAe,GAAG,CAAA,CAAA;AAAA,KACrC;AAAA,GACF;AAEA,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AAEO,SAAS,mBACd,UAC4C,EAAA;AAC5C,EAAM,MAAA,MAAA,GACJC,uBAAO,CAAA,qBAAA,CAAsB,oBAAqB,EAAA,CAAA;AAIpD,EAAA,MAAA,CAAO,YAAY,CAAA,GAAI,CAAC,QAAA,EAAU,eAAe,CAAA,CAAA;AAKjD,EAAA,OAAO,OAAO,aAAa,CAAA,CAAA;AAE3B,EAAA,IAAI,UAAY,EAAA;AACd,IAAA,KAAA,MAAW,CAAC,GAAK,EAAA,KAAK,KAAK,MAAO,CAAA,OAAA,CAAQ,UAAU,CAAG,EAAA;AACrD,MAAM,MAAA,YAAA,GAAeC,2BAAU,GAAG,CAAA,CAAA;AAClC,MAAA,IAAI,UAAU,KAAO,EAAA;AACnB,QAAA,OAAO,OAAO,YAAY,CAAA,CAAA;AAAA,OACrB,MAAA;AACL,QAAA,MAAA,CAAO,YAAY,CAAI,GAAA,KAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,GACF;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;AC9EO,SAAS,gBAAgB,MAA8B,EAAA;AAC5D,EAAM,MAAA,EAAA,GAAK,MAAQ,EAAA,iBAAA,CAAkB,MAAM,CAAA,CAAA;AAC3C,EAAA,IAAI,CAAC,EAAI,EAAA;AACP,IAAO,OAAA,EAAE,QAAQ,KAAM,EAAA,CAAA;AAAA,GACzB;AAEA,EAAA,OAAO,aAAc,CAAA;AAAA,IACnB,MAAQ,EAAA,uBAAA,CAAwB,eAAgB,CAAA,EAAA,EAAI,QAAQ,CAAC,CAAA;AAAA,IAC7D,OAAA,EAAS,eAAgB,CAAA,EAAA,EAAI,SAAS,CAAA;AAAA,IACtC,cAAA,EAAgB,eAAgB,CAAA,EAAA,EAAI,gBAAgB,CAAA;AAAA,IACpD,cAAA,EAAgB,eAAgB,CAAA,EAAA,EAAI,gBAAgB,CAAA;AAAA,IACpD,WAAA,EAAa,EAAG,CAAA,kBAAA,CAAmB,aAAa,CAAA;AAAA,IAChD,MAAA,EAAQ,EAAG,CAAA,iBAAA,CAAkB,QAAQ,CAAA;AAAA,IACrC,iBAAA,EAAmB,EAAG,CAAA,kBAAA,CAAmB,mBAAmB,CAAA;AAAA,IAC5D,oBAAA,EAAsB,EAAG,CAAA,iBAAA,CAAkB,sBAAsB,CAAA;AAAA,GAClE,CAAA,CAAA;AACH,CAAA;AAEA,SAAS,cAAgC,GAAW,EAAA;AAClD,EAAA,OAAO,MAAO,CAAA,WAAA;AAAA,IACZ,MAAA,CAAO,OAAQ,CAAA,GAAG,CAAE,CAAA,MAAA,CAAO,CAAC,GAAG,CAAC,CAAM,KAAA,CAAA,KAAM,KAAS,CAAA,CAAA;AAAA,GACvD,CAAA;AACF,CAAA;AAEA,SAAS,eAAA,CAAgB,QAAgB,GAAmC,EAAA;AAC1E,EAAM,MAAA,KAAA,GAAQ,MAAO,CAAA,WAAA,CAAY,GAAG,CAAA,CAAA;AACpC,EAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC7B,IAAA,OAAO,CAAC,KAAK,CAAA,CAAA;AAAA,GACf,MAAA,IAAW,CAAC,KAAO,EAAA;AACjB,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AACA,EAAO,OAAA,MAAA,CAAO,eAAe,GAAG,CAAA,CAAA;AAClC,CAAA;AAEA,SAAS,wBAAwB,qBAA6C,EAAA;AAC5E,EAAA,IAAI,CAAC,qBAAuB,EAAA;AAC1B,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AAEA,EAAA,MAAM,wBAAwB,qBAAsB,CAAA,GAAA;AAAA,IAClD,CAAA,OAAA,KAAW,IAAIC,mBAAU,CAAA,OAAA,EAAS,EAAE,MAAQ,EAAA,IAAA,EAAM,UAAY,EAAA,IAAA,EAAM,CAAA;AAAA,GACtE,CAAA;AAEA,EAAO,OAAA,CACL,QACA,QAIG,KAAA;AACH,IAAO,OAAA,QAAA;AAAA,MACL,IAAA;AAAA,MACA,sBAAsB,IAAK,CAAA,CAAA,OAAA,KAAW,QAAQ,KAAM,CAAA,MAAA,IAAU,EAAE,CAAC,CAAA;AAAA,KACnE,CAAA;AAAA,GACF,CAAA;AACF;;ACnEA,SAAS,cAAA,CAAe,OAAc,MAAuB,EAAA;AAC3D,EAAA,MAAM,KAAQ,GAAAC,kBAAA,CAAY,EAAE,CAAA,CAAE,SAAS,KAAK,CAAA,CAAA;AAC5C,EACG,MAAA,CAAA,KAAA,CAAM,EAAE,KAAM,EAAC,EACf,KAAM,CAAA,CAAA,mCAAA,EAAsC,KAAK,CAAA,cAAA,CAAA,EAAkB,KAAK,CAAA,CAAA;AAC3E,EAAA,MAAM,QAAW,GAAA,IAAI,KAAM,CAAA,CAAA,iCAAA,EAAoC,KAAK,CAAE,CAAA,CAAA,CAAA;AACtE,EAAA,OAAO,QAAS,CAAA,KAAA,CAAA;AAChB,EAAO,OAAA,QAAA,CAAA;AACT,CAAA;AAOgB,SAAA,wBAAA,CACd,OACA,MACO,EAAA;AACP,EAAI,IAAA;AACF,IAAAC,kBAAA,CAAY,KAAK,CAAA,CAAA;AAAA,WACV,cAAyB,EAAA;AAChC,IAAAA,kBAAA,CAAY,cAAc,CAAA,CAAA;AAC1B,IAAO,OAAA,cAAA,CAAe,gBAAgB,MAAM,CAAA,CAAA;AAAA,GAC9C;AAEA,EAAM,MAAA,eAAA,GAAkB,MAAM,WAAY,CAAA,IAAA,CAAA;AAG1C,EAAA,IAAI,oBAAoB,eAAiB,EAAA;AACvC,IAAO,OAAA,cAAA,CAAe,OAAO,MAAM,CAAA,CAAA;AAAA,GACrC;AAEA,EAAO,OAAA,KAAA,CAAA;AACT;;AC6BO,MAAM,iBAAkB,CAAA;AAAA,EAC7B,OAAA,CAAA;AAAA,EACA,OAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAO,OAAmC,EAAA;AAC/C,IAAO,OAAA,IAAI,kBAAkB,OAAO,CAAA,CAAA;AAAA,GACtC;AAAA,EAEQ,YAAY,OAAmC,EAAA;AACrD,IAAA,IAAA,CAAK,UAAU,OAAQ,CAAA,MAAA,CAAA;AACvB,IAAA,IAAA,CAAK,UAAU,OAAQ,CAAA,MAAA,CAAA;AAAA,GACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,QAA2B,GAAA;AACzB,IAAO,OAAA,CAAC,MAAe,GAAkB,KAAA;AACvC,MAAI,GAAA,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,GAAI,EAAA,CAAA;AAAA,KACtB,CAAA;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,WAA8B,GAAA;AAC5B,IAAA,OAAOC,4BAAY,EAAA,CAAA;AAAA,GACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAA0B,GAAA;AACxB,IAAM,MAAA,MAAA,GAAS,IAAK,CAAA,OAAA,CAAQ,KAAM,CAAA;AAAA,MAChC,IAAM,EAAA,iBAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAA,MAAM,kBACJ,GAAA,uGAAA,CAAA;AACF,IAAA,OAAOC,wBAAO,kBAAoB,EAAA;AAAA,MAChC,MAAQ,EAAA;AAAA,QACN,MAAM,OAAiB,EAAA;AACrB,UAAO,MAAA,CAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,EAAS,CAAA,CAAA;AAAA,SAC/B;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAyB,GAAA;AACvB,IAAA,OAAON,wBAAO,iBAAkB,CAAA,IAAA,CAAK,QAAQ,iBAAkB,CAAA,SAAS,CAAC,CAAC,CAAA,CAAA;AAAA,GAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,IAAuB,GAAA;AACrB,IAAA,OAAOO,sBAAK,eAAgB,CAAA,IAAA,CAAK,QAAQ,iBAAkB,CAAA,SAAS,CAAC,CAAC,CAAA,CAAA;AAAA,GACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,KAAA,CAAM,OAAyC,GAAA,EAAyB,EAAA;AACtE,IAAA,MAAM,eACJ,GAAA,OAAA,CAAQ,eAAmB,IAAA,OAAA,CAAQ,IAAI,QAAa,KAAA,aAAA,CAAA;AAEtD,IAAM,MAAA,MAAA,GAAS,IAAK,CAAA,OAAA,CAAQ,KAAM,CAAA;AAAA,MAChC,IAAM,EAAA,cAAA;AAAA,KACP,CAAA,CAAA;AAED,IAAA,OAAO,CACL,QAAA,EACA,GACA,EAAA,GAAA,EACA,IACG,KAAA;AACH,MAAM,MAAA,KAAA,GAAQ,wBAAyB,CAAA,QAAA,EAAU,MAAM,CAAA,CAAA;AAEvD,MAAM,MAAA,UAAA,GAAa,cAAc,KAAK,CAAA,CAAA;AACtC,MAAI,IAAA,OAAA,CAAQ,YAAgB,IAAA,UAAA,IAAc,GAAK,EAAA;AAC7C,QAAA,MAAA,CAAO,KAAM,CAAA,CAAA,2BAAA,EAA8B,UAAU,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,OAChE;AAEA,MAAA,IAAI,IAAI,WAAa,EAAA;AAGnB,QAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AACV,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,IAA0B,GAAA;AAAA,QAC9B,OAAOC,qBAAe,CAAA,KAAA,EAAO,EAAE,YAAA,EAAc,iBAAiB,CAAA;AAAA,QAC9D,SAAS,EAAE,MAAA,EAAQ,IAAI,MAAQ,EAAA,GAAA,EAAK,IAAI,GAAI,EAAA;AAAA,QAC5C,QAAA,EAAU,EAAE,UAAW,EAAA;AAAA,OACzB,CAAA;AAEA,MAAA,GAAA,CAAI,MAAO,CAAA,UAAU,CAAE,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,KAClC,CAAA;AAAA,GACF;AACF,CAAA;AAEA,SAAS,cAAc,KAAsB,EAAA;AAE3C,EAAM,MAAA,qBAAA,GAAwB,CAAC,YAAA,EAAc,QAAQ,CAAA,CAAA;AACrD,EAAA,KAAA,MAAW,SAAS,qBAAuB,EAAA;AACzC,IAAM,MAAA,UAAA,GAAc,MAAc,KAAK,CAAA,CAAA;AACvC,IAAA,IACE,OAAO,UAAA,KAAe,QACrB,IAAA,CAAA,UAAA,GAAa,CAAO,MAAA,UAAA;AAAA,IACrB,UAAA,IAAc,GACd,IAAA,UAAA,IAAc,GACd,EAAA;AACA,MAAO,OAAA,UAAA,CAAA;AAAA,KACT;AAAA,GACF;AAGA,EAAA,QAAQ,MAAM,IAAM;AAAA,IAClB,KAAKC,uBAAiB,CAAA,IAAA;AACpB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,iBAAW,CAAA,IAAA;AACd,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,0BAAoB,CAAA,IAAA;AACvB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,sBAAgB,CAAA,IAAA;AACnB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,oBAAc,CAAA,IAAA;AACjB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,oBAAc,CAAA,IAAA;AACjB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,0BAAoB,CAAA,IAAA;AACvB,MAAO,OAAA,GAAA,CAAA;AAAA,IACT,KAAKC,8BAAwB,CAAA,IAAA;AAC3B,MAAO,OAAA,GAAA,CAAA;AAEP,GACJ;AAGA,EAAO,OAAA,GAAA,CAAA;AACT;;ACxNA,SAAS,gBAAA,CAAiB,EAAE,aAAA,EAAiD,EAAA;AAC3E,EAAc,aAAA,EAAA,CAAA;AAChB,CAAA;AAEA,MAAM,uCAAA,GAA0C,CAC9C,OAAA,KAEAC,qCAAqB,CAAA;AAAA,EACnB,SAASC,6BAAa,CAAA,cAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,UAAA;AAAA,IACrB,YAAYA,6BAAa,CAAA,UAAA;AAAA,IACzB,WAAWA,6BAAa,CAAA,aAAA;AAAA,IACxB,QAAQA,6BAAa,CAAA,UAAA;AAAA,GACvB;AAAA,EACA,MAAM,OAAQ,CAAA,UAAEC,UAAQ,UAAY,EAAA,SAAA,EAAW,QAAU,EAAA;AACvD,IAAA,MAAM,EAAE,SAAW,EAAA,SAAA,GAAY,gBAAiB,EAAA,GAAI,WAAW,EAAC,CAAA;AAChE,IAAA,MAAM,SAAS,UAAW,CAAA,KAAA,CAAM,EAAE,OAAA,EAAS,kBAAkB,CAAA,CAAA;AAC7D,IAAA,MAAM,MAAMC,wBAAQ,EAAA,CAAA;AAEpB,IAAA,MAAM,MAAS,GAAA,qBAAA,CAAsB,MAAO,CAAA,EAAE,WAAW,CAAA,CAAA;AACzD,IAAA,MAAM,aAAa,iBAAkB,CAAA,MAAA,CAAO,UAAED,QAAA,EAAQ,QAAQ,CAAA,CAAA;AAC9D,IAAM,MAAA,MAAA,GAAS,OAAO,OAAQ,EAAA,CAAA;AAE9B,IAAA,MAAM,YAAe,GAAA,kBAAA,CAAmB,EAAE,MAAA,EAAQ,CAAA,CAAA;AAClD,IAAA,MAAM,SAAS,MAAM,gBAAA;AAAA,MACnB,GAAA;AAAA,MACAE,4BAAsB,CAAAF,QAAA,CAAO,iBAAkB,CAAA,SAAS,CAAC,CAAA;AAAA,MACzD,EAAE,MAAO,EAAA;AAAA,KACX,CAAA;AAEA,IAAU,SAAA,CAAA;AAAA,MACR,GAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAA;AAAA,cACAA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA;AAAA,MACA,aAAgB,GAAA;AACd,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,MAAA,EAAQ,CAAA,CAAA;AAC3B,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,IAAA,EAAM,CAAA,CAAA;AACzB,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,WAAA,EAAa,CAAA,CAAA;AAChC,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,OAAA,EAAS,CAAA,CAAA;AAC5B,QAAA,GAAA,CAAI,IAAI,YAAY,CAAA,CAAA;AACpB,QAAA,GAAA,CAAI,IAAI,MAAM,CAAA,CAAA;AACd,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,QAAA,EAAU,CAAA,CAAA;AAC7B,QAAI,GAAA,CAAA,GAAA,CAAI,UAAW,CAAA,KAAA,EAAO,CAAA,CAAA;AAAA,OAC5B;AAAA,KACD,CAAA,CAAA;AAED,IAAA,SAAA,CAAU,eAAgB,CAAA,MAAM,MAAO,CAAA,IAAA,EAAM,CAAA,CAAA;AAE7C,IAAA,MAAM,OAAO,KAAM,EAAA,CAAA;AAEnB,IAAO,OAAA,MAAA,CAAA;AAAA,GACT;AACF,CAAC,CAAE,EAAA,CAAA;AAGE,MAAM,+BAA+B,MAAO,CAAA,MAAA;AAAA,EACjD,uCAAA;AAAA,EACA,uCAAwC,EAAA;AAC1C;;;;;;;;;;;"}
@@ -2296,7 +2296,7 @@ class DefaultReadTreeResponseFactory {
2296
2296
  }
2297
2297
 
2298
2298
  var name = "@backstage/backend-defaults";
2299
- var version = "0.4.2-next.3";
2299
+ var version = "0.4.2";
2300
2300
  var description = "Backend defaults used by Backstage backend apps";
2301
2301
  var backstage = {
2302
2302
  role: "node-library"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__httpauth",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/httpAuth.cjs.js",
5
5
  "types": "../dist/httpAuth.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__httprouter",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/httpRouter.cjs.js",
5
5
  "types": "../dist/httpRouter.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__lifecycle",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/lifecycle.cjs.js",
5
5
  "types": "../dist/lifecycle.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__logger",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/logger.cjs.js",
5
5
  "types": "../dist/logger.d.ts"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "description": "Backend defaults used by Backstage backend apps",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -150,19 +150,19 @@
150
150
  "@aws-sdk/client-s3": "^3.350.0",
151
151
  "@aws-sdk/credential-providers": "^3.350.0",
152
152
  "@aws-sdk/types": "^3.347.0",
153
- "@backstage/backend-app-api": "^0.8.1-next.3",
154
- "@backstage/backend-common": "^0.23.4-next.3",
155
- "@backstage/backend-dev-utils": "^0.1.4",
156
- "@backstage/backend-plugin-api": "^0.8.0-next.3",
153
+ "@backstage/backend-app-api": "^0.9.0",
154
+ "@backstage/backend-common": "^0.24.0",
155
+ "@backstage/backend-dev-utils": "^0.1.5",
156
+ "@backstage/backend-plugin-api": "^0.8.0",
157
157
  "@backstage/cli-common": "^0.1.14",
158
158
  "@backstage/config": "^1.2.0",
159
- "@backstage/config-loader": "^1.9.0-next.2",
159
+ "@backstage/config-loader": "^1.9.0",
160
160
  "@backstage/errors": "^1.2.4",
161
- "@backstage/integration": "^1.14.0-next.0",
161
+ "@backstage/integration": "^1.14.0",
162
162
  "@backstage/integration-aws-node": "^0.1.12",
163
- "@backstage/plugin-auth-node": "^0.5.0-next.3",
164
- "@backstage/plugin-events-node": "^0.3.9-next.3",
165
- "@backstage/plugin-permission-node": "^0.8.1-next.3",
163
+ "@backstage/plugin-auth-node": "^0.5.0",
164
+ "@backstage/plugin-events-node": "^0.3.9",
165
+ "@backstage/plugin-permission-node": "^0.8.1",
166
166
  "@backstage/types": "^1.1.1",
167
167
  "@google-cloud/storage": "^7.0.0",
168
168
  "@keyv/memcache": "^1.3.5",
@@ -217,9 +217,9 @@
217
217
  },
218
218
  "devDependencies": {
219
219
  "@aws-sdk/util-stream-node": "^3.350.0",
220
- "@backstage/backend-plugin-api": "^0.8.0-next.3",
221
- "@backstage/backend-test-utils": "^0.4.5-next.3",
222
- "@backstage/cli": "^0.27.0-next.4",
220
+ "@backstage/backend-plugin-api": "^0.8.0",
221
+ "@backstage/backend-test-utils": "^0.5.0",
222
+ "@backstage/cli": "^0.27.0",
223
223
  "@types/http-errors": "^2.0.0",
224
224
  "@types/morgan": "^1.9.0",
225
225
  "@types/node-forge": "^1.3.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__permissions",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/permissions.cjs.js",
5
5
  "types": "../dist/permissions.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__rootconfig",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/rootConfig.cjs.js",
5
5
  "types": "../dist/rootConfig.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__roothealth",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/rootHealth.cjs.js",
5
5
  "types": "../dist/rootHealth.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__roothttprouter",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/rootHttpRouter.cjs.js",
5
5
  "types": "../dist/rootHttpRouter.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__rootlifecycle",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/rootLifecycle.cjs.js",
5
5
  "types": "../dist/rootLifecycle.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__rootlogger",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/rootLogger.cjs.js",
5
5
  "types": "../dist/rootLogger.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__scheduler",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/scheduler.cjs.js",
5
5
  "types": "../dist/scheduler.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__urlreader",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/urlReader.cjs.js",
5
5
  "types": "../dist/urlReader.d.ts"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults__userinfo",
3
- "version": "0.4.2-next.3",
3
+ "version": "0.4.2",
4
4
  "main": "../dist/userInfo.cjs.js",
5
5
  "types": "../dist/userInfo.d.ts"
6
6
  }