@backstage/backend-defaults 0.4.1 → 0.4.2-next.0
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 +18 -9
- package/auth/package.json +1 -1
- package/cache/package.json +1 -1
- package/database/package.json +1 -1
- package/discovery/package.json +1 -1
- package/dist/rootHttpRouter.cjs.js +22 -21
- package/dist/rootHttpRouter.cjs.js.map +1 -1
- package/dist/rootHttpRouter.d.ts +11 -2
- package/dist/urlReader.cjs.js +9 -7
- package/dist/urlReader.cjs.js.map +1 -1
- package/httpAuth/package.json +1 -1
- package/httpRouter/package.json +1 -1
- package/lifecycle/package.json +1 -1
- package/logger/package.json +1 -1
- package/package.json +12 -12
- package/permissions/package.json +1 -1
- package/rootConfig/package.json +1 -1
- package/rootHealth/package.json +1 -1
- package/rootHttpRouter/package.json +1 -1
- package/rootLifecycle/package.json +1 -1
- package/rootLogger/package.json +1 -1
- package/scheduler/package.json +1 -1
- package/urlReader/package.json +1 -1
- package/userInfo/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
-
## 0.4.
|
|
3
|
+
## 0.4.2-next.0
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- 4e79d19: The `createHealthRouter` utility that allows you to create a health check router is now exported via `@backstage/backend-defaults/rootHttpRouter`.
|
|
8
|
+
- 78c1329: Updated `GitlabUrlReader.readUrl` and `GitlabUrlReader.readTree` to accept a user-provided token, supporting both bearer and private tokens.
|
|
9
|
+
- 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`.
|
|
8
10
|
- Updated dependencies
|
|
9
|
-
- @backstage/backend-
|
|
10
|
-
- @backstage/
|
|
11
|
-
- @backstage/
|
|
12
|
-
- @backstage/
|
|
13
|
-
- @backstage/
|
|
14
|
-
- @backstage/plugin-
|
|
15
|
-
- @backstage/
|
|
11
|
+
- @backstage/backend-common@0.23.4-next.0
|
|
12
|
+
- @backstage/integration@1.14.0-next.0
|
|
13
|
+
- @backstage/config-loader@1.8.2-next.0
|
|
14
|
+
- @backstage/backend-app-api@0.8.1-next.0
|
|
15
|
+
- @backstage/backend-dev-utils@0.1.4
|
|
16
|
+
- @backstage/backend-plugin-api@0.7.1-next.0
|
|
17
|
+
- @backstage/cli-common@0.1.14
|
|
18
|
+
- @backstage/config@1.2.0
|
|
19
|
+
- @backstage/errors@1.2.4
|
|
20
|
+
- @backstage/integration-aws-node@0.1.12
|
|
21
|
+
- @backstage/types@1.1.1
|
|
22
|
+
- @backstage/plugin-auth-node@0.4.18-next.0
|
|
23
|
+
- @backstage/plugin-events-node@0.3.9-next.0
|
|
24
|
+
- @backstage/plugin-permission-node@0.8.1-next.0
|
|
16
25
|
|
|
17
26
|
## 0.4.0
|
|
18
27
|
|
package/auth/package.json
CHANGED
package/cache/package.json
CHANGED
package/database/package.json
CHANGED
package/discovery/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var express = require('express');
|
|
4
4
|
var trimEnd = require('lodash/trimEnd');
|
|
5
|
+
var Router = require('express-promise-router');
|
|
5
6
|
var config = require('./cjs/config-BDOwXIyo.cjs.js');
|
|
6
7
|
var http = require('http');
|
|
7
8
|
var https = require('https');
|
|
@@ -18,7 +19,6 @@ var minimatch = require('minimatch');
|
|
|
18
19
|
var errors = require('@backstage/errors');
|
|
19
20
|
var crypto = require('crypto');
|
|
20
21
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
21
|
-
var Router = require('express-promise-router');
|
|
22
22
|
|
|
23
23
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
24
24
|
|
|
@@ -42,6 +42,7 @@ function _interopNamespaceCompat(e) {
|
|
|
42
42
|
|
|
43
43
|
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
44
44
|
var trimEnd__default = /*#__PURE__*/_interopDefaultCompat(trimEnd);
|
|
45
|
+
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
45
46
|
var http__namespace = /*#__PURE__*/_interopNamespaceCompat(http);
|
|
46
47
|
var https__namespace = /*#__PURE__*/_interopNamespaceCompat(https);
|
|
47
48
|
var stoppableServer__default = /*#__PURE__*/_interopDefaultCompat(stoppableServer);
|
|
@@ -52,7 +53,6 @@ var helmet__default = /*#__PURE__*/_interopDefaultCompat(helmet);
|
|
|
52
53
|
var morgan__default = /*#__PURE__*/_interopDefaultCompat(morgan);
|
|
53
54
|
var compression__default = /*#__PURE__*/_interopDefaultCompat(compression);
|
|
54
55
|
var kebabCase__default = /*#__PURE__*/_interopDefaultCompat(kebabCase);
|
|
55
|
-
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
56
56
|
|
|
57
57
|
function normalizePath(path) {
|
|
58
58
|
return `${trimEnd__default.default(path, "/")}/`;
|
|
@@ -120,6 +120,25 @@ class DefaultRootHttpRouter {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
function createHealthRouter(options) {
|
|
124
|
+
const router = Router__default.default();
|
|
125
|
+
router.get(
|
|
126
|
+
"/.backstage/health/v1/readiness",
|
|
127
|
+
async (_request, response) => {
|
|
128
|
+
const { status, payload } = await options.health.getReadiness();
|
|
129
|
+
response.status(status).json(payload);
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
router.get(
|
|
133
|
+
"/.backstage/health/v1/liveness",
|
|
134
|
+
async (_request, response) => {
|
|
135
|
+
const { status, payload } = await options.health.getLiveness();
|
|
136
|
+
response.status(status).json(payload);
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
return router;
|
|
140
|
+
}
|
|
141
|
+
|
|
123
142
|
const FIVE_DAYS_IN_MS = 5 * 24 * 60 * 60 * 1e3;
|
|
124
143
|
const IP_HOSTNAME_REGEX = /:|^\d+\.\d+\.\d+\.\d+$/;
|
|
125
144
|
async function getGeneratedCertificate(hostname, logger) {
|
|
@@ -573,25 +592,6 @@ function getStatusCode(error) {
|
|
|
573
592
|
return 500;
|
|
574
593
|
}
|
|
575
594
|
|
|
576
|
-
function createHealthRouter(options) {
|
|
577
|
-
const router = Router__default.default();
|
|
578
|
-
router.get(
|
|
579
|
-
"/.backstage/health/v1/readiness",
|
|
580
|
-
async (_request, response) => {
|
|
581
|
-
const { status, payload } = await options.health.getReadiness();
|
|
582
|
-
response.status(status).json(payload);
|
|
583
|
-
}
|
|
584
|
-
);
|
|
585
|
-
router.get(
|
|
586
|
-
"/.backstage/health/v1/liveness",
|
|
587
|
-
async (_request, response) => {
|
|
588
|
-
const { status, payload } = await options.health.getLiveness();
|
|
589
|
-
response.status(status).json(payload);
|
|
590
|
-
}
|
|
591
|
-
);
|
|
592
|
-
return router;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
595
|
function defaultConfigure({ applyDefaults }) {
|
|
596
596
|
applyDefaults();
|
|
597
597
|
}
|
|
@@ -649,6 +649,7 @@ const rootHttpRouterServiceFactory = Object.assign(
|
|
|
649
649
|
exports.readHttpServerOptions = config.readHttpServerOptions;
|
|
650
650
|
exports.DefaultRootHttpRouter = DefaultRootHttpRouter;
|
|
651
651
|
exports.MiddlewareFactory = MiddlewareFactory;
|
|
652
|
+
exports.createHealthRouter = createHealthRouter;
|
|
652
653
|
exports.createHttpServer = createHttpServer;
|
|
653
654
|
exports.readCorsOptions = readCorsOptions;
|
|
654
655
|
exports.readHelmetOptions = readHelmetOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rootHttpRouter.cjs.js","sources":["../src/entrypoints/rootHttpRouter/DefaultRootHttpRouter.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/createHealthRouter.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 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","import { RootHealthService } from '@backstage/backend-plugin-api';\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 Router from 'express-promise-router';\nimport { Request, Response } from 'express';\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 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\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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"}
|
package/dist/rootHttpRouter.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
/// <reference types="express" />
|
|
1
2
|
/// <reference types="node" />
|
|
2
3
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
3
|
-
import { RootHttpRouterService, LoggerService, RootConfigService, LifecycleService } from '@backstage/backend-plugin-api';
|
|
4
|
+
import { RootHttpRouterService, RootHealthService, LoggerService, RootConfigService, LifecycleService } from '@backstage/backend-plugin-api';
|
|
5
|
+
import * as express from 'express';
|
|
4
6
|
import { Handler, RequestHandler, ErrorRequestHandler, Express } from 'express';
|
|
5
7
|
import { Config } from '@backstage/config';
|
|
6
8
|
import * as http from 'http';
|
|
@@ -35,6 +37,13 @@ declare class DefaultRootHttpRouter implements RootHttpRouterService {
|
|
|
35
37
|
handler(): Handler;
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
declare function createHealthRouter(options: {
|
|
44
|
+
health: RootHealthService;
|
|
45
|
+
}): express.Router;
|
|
46
|
+
|
|
38
47
|
/**
|
|
39
48
|
* An HTTP server extended with utility methods.
|
|
40
49
|
*
|
|
@@ -281,4 +290,4 @@ type RootHttpRouterFactoryOptions = {
|
|
|
281
290
|
/** @public */
|
|
282
291
|
declare const rootHttpRouterServiceFactory: ((options?: RootHttpRouterFactoryOptions) => _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.RootHttpRouterService, "root">) & _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.RootHttpRouterService, "root">;
|
|
283
292
|
|
|
284
|
-
export { DefaultRootHttpRouter, type DefaultRootHttpRouterOptions, type ExtendedHttpServer, type HttpServerCertificateOptions, type HttpServerOptions, MiddlewareFactory, type MiddlewareFactoryErrorOptions, type MiddlewareFactoryOptions, type RootHttpRouterConfigureContext, type RootHttpRouterFactoryOptions, createHttpServer, readCorsOptions, readHelmetOptions, readHttpServerOptions, rootHttpRouterServiceFactory };
|
|
293
|
+
export { DefaultRootHttpRouter, type DefaultRootHttpRouterOptions, type ExtendedHttpServer, type HttpServerCertificateOptions, type HttpServerOptions, MiddlewareFactory, type MiddlewareFactoryErrorOptions, type MiddlewareFactoryOptions, type RootHttpRouterConfigureContext, type RootHttpRouterFactoryOptions, createHealthRouter, createHttpServer, readCorsOptions, readHelmetOptions, readHttpServerOptions, rootHttpRouterServiceFactory };
|
package/dist/urlReader.cjs.js
CHANGED
|
@@ -1065,13 +1065,13 @@ class GitlabUrlReader {
|
|
|
1065
1065
|
return response.buffer();
|
|
1066
1066
|
}
|
|
1067
1067
|
async readUrl(url, options) {
|
|
1068
|
-
const { etag, lastModifiedAfter, signal } = options ?? {};
|
|
1068
|
+
const { etag, lastModifiedAfter, signal, token } = options ?? {};
|
|
1069
1069
|
const builtUrl = await this.getGitlabFetchUrl(url);
|
|
1070
1070
|
let response;
|
|
1071
1071
|
try {
|
|
1072
1072
|
response = await fetch__default.default(builtUrl, {
|
|
1073
1073
|
headers: {
|
|
1074
|
-
...integration.getGitLabRequestOptions(this.integration.config).headers,
|
|
1074
|
+
...integration.getGitLabRequestOptions(this.integration.config, token).headers,
|
|
1075
1075
|
...etag && { "If-None-Match": etag },
|
|
1076
1076
|
...lastModifiedAfter && {
|
|
1077
1077
|
"If-Modified-Since": lastModifiedAfter.toUTCString()
|
|
@@ -1106,7 +1106,7 @@ class GitlabUrlReader {
|
|
|
1106
1106
|
throw new Error(message);
|
|
1107
1107
|
}
|
|
1108
1108
|
async readTree(url, options) {
|
|
1109
|
-
const { etag, signal } = options ?? {};
|
|
1109
|
+
const { etag, signal, token } = options ?? {};
|
|
1110
1110
|
const { ref, full_name, filepath } = parseGitUrl__default.default(url);
|
|
1111
1111
|
let repoFullName = full_name;
|
|
1112
1112
|
const relativePath = integration.getGitLabIntegrationRelativePath(
|
|
@@ -1122,7 +1122,7 @@ class GitlabUrlReader {
|
|
|
1122
1122
|
repoFullName
|
|
1123
1123
|
)}`
|
|
1124
1124
|
).toString(),
|
|
1125
|
-
integration.getGitLabRequestOptions(this.integration.config)
|
|
1125
|
+
integration.getGitLabRequestOptions(this.integration.config, token)
|
|
1126
1126
|
);
|
|
1127
1127
|
if (!projectGitlabResponse.ok) {
|
|
1128
1128
|
const msg = `Failed to read tree from ${url}, ${projectGitlabResponse.status} ${projectGitlabResponse.statusText}`;
|
|
@@ -1145,7 +1145,7 @@ class GitlabUrlReader {
|
|
|
1145
1145
|
)}/repository/commits?${commitsReqParams.toString()}`
|
|
1146
1146
|
).toString(),
|
|
1147
1147
|
{
|
|
1148
|
-
...integration.getGitLabRequestOptions(this.integration.config),
|
|
1148
|
+
...integration.getGitLabRequestOptions(this.integration.config, token),
|
|
1149
1149
|
// TODO(freben): The signal cast is there because pre-3.x versions of
|
|
1150
1150
|
// node-fetch have a very slightly deviating AbortSignal type signature.
|
|
1151
1151
|
// The difference does not affect us in practice however. The cast can
|
|
@@ -1176,7 +1176,7 @@ class GitlabUrlReader {
|
|
|
1176
1176
|
repoFullName
|
|
1177
1177
|
)}/repository/archive?${archiveReqParams.toString()}`,
|
|
1178
1178
|
{
|
|
1179
|
-
...integration.getGitLabRequestOptions(this.integration.config),
|
|
1179
|
+
...integration.getGitLabRequestOptions(this.integration.config, token),
|
|
1180
1180
|
// TODO(freben): The signal cast is there because pre-3.x versions of
|
|
1181
1181
|
// node-fetch have a very slightly deviating AbortSignal type signature.
|
|
1182
1182
|
// The difference does not affect us in practice however. The cast can
|
|
@@ -1633,6 +1633,7 @@ class AwsS3UrlReader {
|
|
|
1633
1633
|
integration
|
|
1634
1634
|
);
|
|
1635
1635
|
const s3 = new clientS3.S3Client({
|
|
1636
|
+
customUserAgent: "backstage-aws-s3-url-reader",
|
|
1636
1637
|
region,
|
|
1637
1638
|
credentials,
|
|
1638
1639
|
endpoint: integration.config.endpoint,
|
|
@@ -2295,7 +2296,7 @@ class DefaultReadTreeResponseFactory {
|
|
|
2295
2296
|
}
|
|
2296
2297
|
|
|
2297
2298
|
var name = "@backstage/backend-defaults";
|
|
2298
|
-
var version = "0.4.
|
|
2299
|
+
var version = "0.4.2-next.0";
|
|
2299
2300
|
var description = "Backend defaults used by Backstage backend apps";
|
|
2300
2301
|
var backstage = {
|
|
2301
2302
|
role: "node-library"
|
|
@@ -2724,6 +2725,7 @@ class AwsCodeCommitUrlReader {
|
|
|
2724
2725
|
integration
|
|
2725
2726
|
);
|
|
2726
2727
|
const codeCommit = new clientCodecommit.CodeCommitClient({
|
|
2728
|
+
customUserAgent: "backstage-aws-codecommit-url-reader",
|
|
2727
2729
|
region,
|
|
2728
2730
|
credentials
|
|
2729
2731
|
});
|