@backstage/plugin-proxy-backend 0.0.0-nightly-20219322159
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 +162 -0
- package/README.md +32 -0
- package/config.d.ts +55 -0
- package/dist/index.cjs.js +94 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @backstage/plugin-proxy-backend
|
|
2
|
+
|
|
3
|
+
## 0.0.0-nightly-20219322159
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 957e4b3351: Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 0.2.12
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @backstage/backend-common@0.9.0
|
|
15
|
+
- @backstage/config@0.1.8
|
|
16
|
+
|
|
17
|
+
## 0.2.11
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- 13da7be3c: Clean up proxy creation log messages and make them include the mount path.
|
|
22
|
+
|
|
23
|
+
## 0.2.10
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- 3108ff7bf: Make `yarn dev` respect the `PLUGIN_PORT` environment variable.
|
|
28
|
+
- 6ffcf9ed8: Bump http-proxy-middleware from 0.19.2 to 2.0.0
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
- @backstage/backend-common@0.8.3
|
|
31
|
+
|
|
32
|
+
## 0.2.9
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- 875809a59: Fixed proxy requests to the base URL of routes without a trailing slash redirecting to the `target` with the full path appended.
|
|
37
|
+
- Updated dependencies [92963779b]
|
|
38
|
+
- Updated dependencies [eda9dbd5f]
|
|
39
|
+
- @backstage/backend-common@0.8.2
|
|
40
|
+
|
|
41
|
+
## 0.2.8
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [22fd8ce2a]
|
|
46
|
+
- Updated dependencies [f9fb4a205]
|
|
47
|
+
- @backstage/backend-common@0.8.0
|
|
48
|
+
|
|
49
|
+
## 0.2.7
|
|
50
|
+
|
|
51
|
+
### Patch Changes
|
|
52
|
+
|
|
53
|
+
- cdb3426e5: Prefix proxy routes with `/` if not present in configuration
|
|
54
|
+
- Updated dependencies [e0bfd3d44]
|
|
55
|
+
- Updated dependencies [38ca05168]
|
|
56
|
+
- Updated dependencies [d8b81fd28]
|
|
57
|
+
- @backstage/backend-common@0.7.0
|
|
58
|
+
- @backstage/config@0.1.5
|
|
59
|
+
|
|
60
|
+
## 0.2.6
|
|
61
|
+
|
|
62
|
+
### Patch Changes
|
|
63
|
+
|
|
64
|
+
- Updated dependencies [8686eb38c]
|
|
65
|
+
- Updated dependencies [0434853a5]
|
|
66
|
+
- Updated dependencies [8686eb38c]
|
|
67
|
+
- @backstage/backend-common@0.6.0
|
|
68
|
+
- @backstage/config@0.1.4
|
|
69
|
+
|
|
70
|
+
## 0.2.5
|
|
71
|
+
|
|
72
|
+
### Patch Changes
|
|
73
|
+
|
|
74
|
+
- 1987c9341: Added a verification for well formed URLs when processing proxy targets. Otherwise users gets a cryptic error message thrown from Express which makes it hard to debug.
|
|
75
|
+
- 9ce68b677: Fix for proxy-backend plugin when global-agent is enabled
|
|
76
|
+
- Updated dependencies [497859088]
|
|
77
|
+
- Updated dependencies [8adb48df4]
|
|
78
|
+
- @backstage/backend-common@0.5.5
|
|
79
|
+
|
|
80
|
+
## 0.2.4
|
|
81
|
+
|
|
82
|
+
### Patch Changes
|
|
83
|
+
|
|
84
|
+
- Updated dependencies [0b135e7e0]
|
|
85
|
+
- Updated dependencies [294a70cab]
|
|
86
|
+
- Updated dependencies [0ea032763]
|
|
87
|
+
- Updated dependencies [5345a1f98]
|
|
88
|
+
- Updated dependencies [09a370426]
|
|
89
|
+
- @backstage/backend-common@0.5.0
|
|
90
|
+
|
|
91
|
+
## 0.2.3
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
- Updated dependencies [38e24db00]
|
|
96
|
+
- Updated dependencies [e3bd9fc2f]
|
|
97
|
+
- Updated dependencies [12bbd748c]
|
|
98
|
+
- Updated dependencies [e3bd9fc2f]
|
|
99
|
+
- @backstage/backend-common@0.4.0
|
|
100
|
+
- @backstage/config@0.1.2
|
|
101
|
+
|
|
102
|
+
## 0.2.2
|
|
103
|
+
|
|
104
|
+
### Patch Changes
|
|
105
|
+
|
|
106
|
+
- 6a6c7c14e: Filter the headers that are sent from the proxied-targed back to the frontend to not forwarded unwanted authentication or
|
|
107
|
+
monitoring contexts from other origins (like `Set-Cookie` with e.g. a google analytics context). The implementation reuses
|
|
108
|
+
the `allowedHeaders` configuration that now controls both directions `frontend->target` and `target->frontend`.
|
|
109
|
+
- 3619ea4c4: Add configuration schema for the commonly used properties
|
|
110
|
+
- Updated dependencies [612368274]
|
|
111
|
+
- @backstage/backend-common@0.3.3
|
|
112
|
+
|
|
113
|
+
## 0.2.1
|
|
114
|
+
|
|
115
|
+
### Patch Changes
|
|
116
|
+
|
|
117
|
+
- Updated dependencies [1722cb53c]
|
|
118
|
+
- Updated dependencies [1722cb53c]
|
|
119
|
+
- Updated dependencies [7b37e6834]
|
|
120
|
+
- Updated dependencies [8e2effb53]
|
|
121
|
+
- @backstage/backend-common@0.3.0
|
|
122
|
+
|
|
123
|
+
## 0.2.0
|
|
124
|
+
|
|
125
|
+
### Minor Changes
|
|
126
|
+
|
|
127
|
+
- 5249594c5: Add service discovery interface and implement for single host deployments
|
|
128
|
+
|
|
129
|
+
Fixes #1847, #2596
|
|
130
|
+
|
|
131
|
+
Went with an interface similar to the frontend DiscoveryApi, since it's dead simple but still provides a lot of flexibility in the implementation.
|
|
132
|
+
|
|
133
|
+
Also ended up with two different methods, one for internal endpoint discovery and one for external. The two use-cases are explained a bit more in the docs, but basically it's service-to-service vs callback URLs.
|
|
134
|
+
|
|
135
|
+
This did get me thinking about uniqueness and that we're heading towards a global namespace for backend plugin IDs. That's probably fine, but if we're happy with that we should leverage it a bit more to simplify the backend setup. For example we'd have each plugin provide its own ID and not manually mount on paths in the backend.
|
|
136
|
+
|
|
137
|
+
Draft until we're happy with the implementation, then I can add more docs and changelog entry. Also didn't go on a thorough hunt for places where discovery can be used, but I don't think there are many since it's been pretty awkward to do service-to-service communication.
|
|
138
|
+
|
|
139
|
+
- 9226c2aaa: Limit the http headers that are forwarded from the request to a safe set of defaults.
|
|
140
|
+
A user can configure additional headers that should be forwarded if the specific applications needs that.
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
proxy:
|
|
144
|
+
'/my-api':
|
|
145
|
+
target: 'https://my-api.com/get'
|
|
146
|
+
allowedHeaders:
|
|
147
|
+
# We need to forward the Authorization header that was provided by the caller
|
|
148
|
+
- Authorization
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Patch Changes
|
|
152
|
+
|
|
153
|
+
- Updated dependencies [5249594c5]
|
|
154
|
+
- Updated dependencies [56e4eb589]
|
|
155
|
+
- Updated dependencies [e37c0a005]
|
|
156
|
+
- Updated dependencies [f00ca3cb8]
|
|
157
|
+
- Updated dependencies [6579769df]
|
|
158
|
+
- Updated dependencies [8c2b76e45]
|
|
159
|
+
- Updated dependencies [440a17b39]
|
|
160
|
+
- Updated dependencies [8afce088a]
|
|
161
|
+
- Updated dependencies [7bbeb049f]
|
|
162
|
+
- @backstage/backend-common@0.2.0
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Proxy backend plugin
|
|
2
|
+
|
|
3
|
+
This is the backend plugin that enables proxy definitions to be declared in,
|
|
4
|
+
and read from, `app-config.yaml`.
|
|
5
|
+
|
|
6
|
+
Relies on the `http-proxy-middleware` package.
|
|
7
|
+
|
|
8
|
+
## Getting Started
|
|
9
|
+
|
|
10
|
+
This backend plugin can be started in a standalone mode from directly in this package
|
|
11
|
+
with `yarn start`. However, it will have limited functionality and that process is
|
|
12
|
+
most convenient when developing the plugin itself.
|
|
13
|
+
|
|
14
|
+
The proxy is already installed in the Backstage backend per default, so you can also
|
|
15
|
+
start up the full example backend to experiment with the proxy.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn workspace example-backend start
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
See [the proxy docs](https://backstage.io/docs/plugins/proxying).
|
|
24
|
+
|
|
25
|
+
## Links
|
|
26
|
+
|
|
27
|
+
- [Call Existing API](https://backstage.io/docs/plugins/call-existing-api) helps the
|
|
28
|
+
decision process of what method of communication to use from a frontend plugin to
|
|
29
|
+
your API
|
|
30
|
+
- [The proxy plugin documentation](https://backstage.io/docs/plugins/proxying) describes
|
|
31
|
+
configuration options and more
|
|
32
|
+
- [http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware)
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface Config {
|
|
18
|
+
/**
|
|
19
|
+
* A list of forwarding-proxies. Each key is a route to match,
|
|
20
|
+
* below the prefix that the proxy plugin is mounted on. It must
|
|
21
|
+
* start with a '/'.
|
|
22
|
+
*/
|
|
23
|
+
proxy?: {
|
|
24
|
+
[key: string]:
|
|
25
|
+
| string
|
|
26
|
+
| {
|
|
27
|
+
/**
|
|
28
|
+
* Target of the proxy. Url string to be parsed with the url module.
|
|
29
|
+
*/
|
|
30
|
+
target: string;
|
|
31
|
+
/**
|
|
32
|
+
* Object with extra headers to be added to target requests.
|
|
33
|
+
*/
|
|
34
|
+
headers?: { [key: string]: string };
|
|
35
|
+
/**
|
|
36
|
+
* Changes the origin of the host header to the target URL. Default: true.
|
|
37
|
+
*/
|
|
38
|
+
changeOrigin?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Rewrite target's url path. Object-keys will be used as RegExp to match paths.
|
|
41
|
+
* If pathRewrite is not specified, it is set to a single rewrite that removes the entire prefix and route.
|
|
42
|
+
*/
|
|
43
|
+
pathRewrite?: { [regexp: string]: string };
|
|
44
|
+
/**
|
|
45
|
+
* Limit the forwarded HTTP methods, for example allowedMethods: ['GET'] to enforce read-only access.
|
|
46
|
+
*/
|
|
47
|
+
allowedMethods?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Limit the forwarded HTTP methods. By default, only the headers that are considered safe for CORS
|
|
50
|
+
* and headers that are set by the proxy will be forwarded.
|
|
51
|
+
*/
|
|
52
|
+
allowedHeaders?: string[];
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var Router = require('express-promise-router');
|
|
6
|
+
var httpProxyMiddleware = require('http-proxy-middleware');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
|
+
|
|
10
|
+
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
11
|
+
|
|
12
|
+
const safeForwardHeaders = [
|
|
13
|
+
"cache-control",
|
|
14
|
+
"content-language",
|
|
15
|
+
"content-length",
|
|
16
|
+
"content-type",
|
|
17
|
+
"expires",
|
|
18
|
+
"last-modified",
|
|
19
|
+
"pragma",
|
|
20
|
+
"host",
|
|
21
|
+
"accept",
|
|
22
|
+
"accept-language",
|
|
23
|
+
"user-agent"
|
|
24
|
+
];
|
|
25
|
+
function buildMiddleware(pathPrefix, logger, route, config) {
|
|
26
|
+
var _a;
|
|
27
|
+
const fullConfig = typeof config === "string" ? {target: config} : {...config};
|
|
28
|
+
if (typeof fullConfig.target !== "string") {
|
|
29
|
+
throw new Error(`Proxy target must be a string`);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
new URL(fullConfig.target);
|
|
33
|
+
} catch {
|
|
34
|
+
throw new Error(`Proxy target is not a valid URL: ${(_a = fullConfig.target) != null ? _a : ""}`);
|
|
35
|
+
}
|
|
36
|
+
if (fullConfig.pathRewrite === void 0) {
|
|
37
|
+
let routeWithSlash = route.endsWith("/") ? route : `${route}/`;
|
|
38
|
+
if (!pathPrefix.endsWith("/") && !routeWithSlash.startsWith("/")) {
|
|
39
|
+
routeWithSlash = `/${routeWithSlash}`;
|
|
40
|
+
} else if (pathPrefix.endsWith("/") && routeWithSlash.startsWith("/")) {
|
|
41
|
+
routeWithSlash = routeWithSlash.substring(1);
|
|
42
|
+
}
|
|
43
|
+
fullConfig.pathRewrite = {
|
|
44
|
+
[`^${pathPrefix}${routeWithSlash}?`]: "/"
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (fullConfig.changeOrigin === void 0) {
|
|
48
|
+
fullConfig.changeOrigin = true;
|
|
49
|
+
}
|
|
50
|
+
fullConfig.logProvider = () => logger;
|
|
51
|
+
const requestHeaderAllowList = new Set([
|
|
52
|
+
...safeForwardHeaders,
|
|
53
|
+
...fullConfig.headers && Object.keys(fullConfig.headers) || [],
|
|
54
|
+
...fullConfig.allowedHeaders || []
|
|
55
|
+
].map((h) => h.toLocaleLowerCase()));
|
|
56
|
+
const filter = (_pathname, req) => {
|
|
57
|
+
var _a2, _b;
|
|
58
|
+
const headerNames = Object.keys(req.headers);
|
|
59
|
+
headerNames.forEach((h) => {
|
|
60
|
+
if (!requestHeaderAllowList.has(h.toLocaleLowerCase())) {
|
|
61
|
+
delete req.headers[h];
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return (_b = (_a2 = fullConfig == null ? void 0 : fullConfig.allowedMethods) == null ? void 0 : _a2.includes(req.method)) != null ? _b : true;
|
|
65
|
+
};
|
|
66
|
+
filter.toString = () => route;
|
|
67
|
+
const responseHeaderAllowList = new Set([
|
|
68
|
+
...safeForwardHeaders,
|
|
69
|
+
...fullConfig.allowedHeaders || []
|
|
70
|
+
].map((h) => h.toLocaleLowerCase()));
|
|
71
|
+
fullConfig.onProxyRes = (proxyRes) => {
|
|
72
|
+
const headerNames = Object.keys(proxyRes.headers);
|
|
73
|
+
headerNames.forEach((h) => {
|
|
74
|
+
if (!responseHeaderAllowList.has(h.toLocaleLowerCase())) {
|
|
75
|
+
delete proxyRes.headers[h];
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
return httpProxyMiddleware.createProxyMiddleware(filter, fullConfig);
|
|
80
|
+
}
|
|
81
|
+
async function createRouter(options) {
|
|
82
|
+
var _a;
|
|
83
|
+
const router = Router__default['default']();
|
|
84
|
+
const externalUrl = await options.discovery.getExternalBaseUrl("proxy");
|
|
85
|
+
const {pathname: pathPrefix} = new URL(externalUrl);
|
|
86
|
+
const proxyConfig = (_a = options.config.getOptional("proxy")) != null ? _a : {};
|
|
87
|
+
Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => {
|
|
88
|
+
router.use(route, buildMiddleware(pathPrefix, options.logger, route, proxyRouteConfig));
|
|
89
|
+
});
|
|
90
|
+
return router;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
exports.createRouter = createRouter;
|
|
94
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/service/router.ts"],"sourcesContent":["/*\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 express from 'express';\nimport Router from 'express-promise-router';\nimport {\n createProxyMiddleware,\n Options,\n RequestHandler,\n} from 'http-proxy-middleware';\nimport { Logger } from 'winston';\nimport http from 'http';\nimport { PluginEndpointDiscovery } from '@backstage/backend-common';\n\n// A list of headers that are always forwarded to the proxy targets.\nconst safeForwardHeaders = [\n // https://fetch.spec.whatwg.org/#cors-safelisted-request-header\n 'cache-control',\n 'content-language',\n 'content-length',\n 'content-type',\n 'expires',\n 'last-modified',\n 'pragma',\n\n // host is overridden by default. if changeOrigin is configured to false,\n // we assume this is a intentional and should also be forwarded.\n 'host',\n\n // other headers that we assume to be ok\n 'accept',\n 'accept-language',\n 'user-agent',\n];\n\nexport interface RouterOptions {\n logger: Logger;\n config: Config;\n discovery: PluginEndpointDiscovery;\n}\n\nexport interface ProxyConfig extends Options {\n allowedMethods?: string[];\n allowedHeaders?: string[];\n}\n\n// Creates a proxy middleware, possibly with defaults added on top of the\n// given config.\nexport function buildMiddleware(\n pathPrefix: string,\n logger: Logger,\n route: string,\n config: string | ProxyConfig,\n): RequestHandler {\n const fullConfig =\n typeof config === 'string' ? { target: config } : { ...config };\n\n // Validate that target is a valid URL.\n if (typeof fullConfig.target !== 'string') {\n throw new Error(`Proxy target must be a string`);\n }\n try {\n // eslint-disable-next-line no-new\n new URL(fullConfig.target! as string);\n } catch {\n throw new Error(\n `Proxy target is not a valid URL: ${fullConfig.target ?? ''}`,\n );\n }\n\n // Default is to do a path rewrite that strips out the proxy's path prefix\n // and the rest of the route.\n if (fullConfig.pathRewrite === undefined) {\n let routeWithSlash = route.endsWith('/') ? route : `${route}/`;\n\n if (!pathPrefix.endsWith('/') && !routeWithSlash.startsWith('/')) {\n // Need to insert a / between pathPrefix and routeWithSlash\n routeWithSlash = `/${routeWithSlash}`;\n } else if (pathPrefix.endsWith('/') && routeWithSlash.startsWith('/')) {\n // Never expect this to happen at this point in time as\n // pathPrefix is set using `getExternalBaseUrl` which \"Returns the\n // external HTTP base backend URL for a given plugin,\n // **without a trailing slash.**\". But in case this changes in future, we\n // need to drop a / on either pathPrefix or routeWithSlash\n routeWithSlash = routeWithSlash.substring(1);\n }\n\n // The ? makes the slash optional for the rewrite, so that a base path without an ending slash\n // will also be matched (e.g. '/sample' and then requesting just '/api/proxy/sample' without an\n // ending slash). Otherwise the target gets called with the full '/api/proxy/sample' path\n // appended.\n fullConfig.pathRewrite = {\n [`^${pathPrefix}${routeWithSlash}?`]: '/',\n };\n }\n\n // Default is to update the Host header to the target\n if (fullConfig.changeOrigin === undefined) {\n fullConfig.changeOrigin = true;\n }\n\n // Attach the logger to the proxy config\n fullConfig.logProvider = () => logger;\n\n // Only return the allowed HTTP headers to not forward unwanted secret headers\n const requestHeaderAllowList = new Set<string>(\n [\n // allow all safe headers\n ...safeForwardHeaders,\n\n // allow all headers that are set by the proxy\n ...((fullConfig.headers && Object.keys(fullConfig.headers)) || []),\n\n // allow all configured headers\n ...(fullConfig.allowedHeaders || []),\n ].map(h => h.toLocaleLowerCase()),\n );\n\n // Use the custom middleware filter to do two things:\n // 1. Remove any headers not in the allow list to stop them being forwarded\n // 2. Only permit the allowed HTTP methods if configured\n //\n // We are filtering the proxy request headers here rather than in\n // `onProxyReq` because when global-agent is enabled then `onProxyReq`\n // fires _after_ the agent has already sent the headers to the proxy\n // target, causing a ERR_HTTP_HEADERS_SENT crash\n const filter = (_pathname: string, req: http.IncomingMessage): boolean => {\n const headerNames = Object.keys(req.headers);\n headerNames.forEach(h => {\n if (!requestHeaderAllowList.has(h.toLocaleLowerCase())) {\n delete req.headers[h];\n }\n });\n\n return fullConfig?.allowedMethods?.includes(req.method!) ?? true;\n };\n // Makes http-proxy-middleware logs look nicer and include the mount path\n filter.toString = () => route;\n\n // Only forward the allowed HTTP headers to not forward unwanted secret headers\n const responseHeaderAllowList = new Set<string>(\n [\n // allow all safe headers\n ...safeForwardHeaders,\n\n // allow all configured headers\n ...(fullConfig.allowedHeaders || []),\n ].map(h => h.toLocaleLowerCase()),\n );\n\n // only forward the allowed headers in backend->client\n fullConfig.onProxyRes = (proxyRes: http.IncomingMessage) => {\n const headerNames = Object.keys(proxyRes.headers);\n\n headerNames.forEach(h => {\n if (!responseHeaderAllowList.has(h.toLocaleLowerCase())) {\n delete proxyRes.headers[h];\n }\n });\n };\n\n return createProxyMiddleware(filter, fullConfig);\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n\n const externalUrl = await options.discovery.getExternalBaseUrl('proxy');\n const { pathname: pathPrefix } = new URL(externalUrl);\n\n const proxyConfig = options.config.getOptional('proxy') ?? {};\n Object.entries(proxyConfig).forEach(([route, proxyRouteConfig]) => {\n router.use(\n route,\n buildMiddleware(pathPrefix, options.logger, route, proxyRouteConfig),\n );\n });\n\n return router;\n}\n"],"names":["createProxyMiddleware","Router"],"mappings":";;;;;;;;;;;AA6BA,MAAM,qBAAqB;AAAA,EAEzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAIA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;yBAiBA,YACA,QACA,OACA,QACgB;AAnElB;AAoEE,QAAM,aACJ,OAAO,WAAW,WAAW,CAAE,QAAQ,UAAW,IAAK;AAGzD,MAAI,OAAO,WAAW,WAAW,UAAU;AACzC,UAAM,IAAI,MAAM;AAAA;AAElB,MAAI;AAEF,QAAI,IAAI,WAAW;AAAA,UACnB;AACA,UAAM,IAAI,MACR,oCAAoC,iBAAW,WAAX,YAAqB;AAAA;AAM7D,MAAI,WAAW,gBAAgB,QAAW;AACxC,QAAI,iBAAiB,MAAM,SAAS,OAAO,QAAQ,GAAG;AAEtD,QAAI,CAAC,WAAW,SAAS,QAAQ,CAAC,eAAe,WAAW,MAAM;AAEhE,uBAAiB,IAAI;AAAA,eACZ,WAAW,SAAS,QAAQ,eAAe,WAAW,MAAM;AAMrE,uBAAiB,eAAe,UAAU;AAAA;AAO5C,eAAW,cAAc;AAAA,OACtB,IAAI,aAAa,oBAAoB;AAAA;AAAA;AAK1C,MAAI,WAAW,iBAAiB,QAAW;AACzC,eAAW,eAAe;AAAA;AAI5B,aAAW,cAAc,MAAM;AAG/B,QAAM,yBAAyB,IAAI,IACjC;AAAA,IAEE,GAAG;AAAA,IAGH,GAAK,WAAW,WAAW,OAAO,KAAK,WAAW,YAAa;AAAA,IAG/D,GAAI,WAAW,kBAAkB;AAAA,IACjC,IAAI,OAAK,EAAE;AAWf,QAAM,SAAS,CAAC,WAAmB,QAAuC;AA5I5E;AA6II,UAAM,cAAc,OAAO,KAAK,IAAI;AACpC,gBAAY,QAAQ,OAAK;AACvB,UAAI,CAAC,uBAAuB,IAAI,EAAE,sBAAsB;AACtD,eAAO,IAAI,QAAQ;AAAA;AAAA;AAIvB,WAAO,sDAAY,mBAAZ,oBAA4B,SAAS,IAAI,YAAzC,YAAqD;AAAA;AAG9D,SAAO,WAAW,MAAM;AAGxB,QAAM,0BAA0B,IAAI,IAClC;AAAA,IAEE,GAAG;AAAA,IAGH,GAAI,WAAW,kBAAkB;AAAA,IACjC,IAAI,OAAK,EAAE;AAIf,aAAW,aAAa,CAAC,aAAmC;AAC1D,UAAM,cAAc,OAAO,KAAK,SAAS;AAEzC,gBAAY,QAAQ,OAAK;AACvB,UAAI,CAAC,wBAAwB,IAAI,EAAE,sBAAsB;AACvD,eAAO,SAAS,QAAQ;AAAA;AAAA;AAAA;AAK9B,SAAOA,0CAAsB,QAAQ;AAAA;4BAIrC,SACyB;AApL3B;AAqLE,QAAM,SAASC;AAEf,QAAM,cAAc,MAAM,QAAQ,UAAU,mBAAmB;AAC/D,QAAM,CAAE,UAAU,cAAe,IAAI,IAAI;AAEzC,QAAM,cAAc,cAAQ,OAAO,YAAY,aAA3B,YAAuC;AAC3D,SAAO,QAAQ,aAAa,QAAQ,CAAC,CAAC,OAAO,sBAAsB;AACjE,WAAO,IACL,OACA,gBAAgB,YAAY,QAAQ,QAAQ,OAAO;AAAA;AAIvD,SAAO;AAAA;;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Config } from '@backstage/config';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { Logger } from 'winston';
|
|
4
|
+
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
|
5
|
+
|
|
6
|
+
interface RouterOptions {
|
|
7
|
+
logger: Logger;
|
|
8
|
+
config: Config;
|
|
9
|
+
discovery: PluginEndpointDiscovery;
|
|
10
|
+
}
|
|
11
|
+
declare function createRouter(options: RouterOptions): Promise<express.Router>;
|
|
12
|
+
|
|
13
|
+
export { createRouter };
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage/plugin-proxy-backend",
|
|
3
|
+
"description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend",
|
|
4
|
+
"version": "0.0.0-nightly-20219322159",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"types": "dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://backstage.io",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/backstage/backstage",
|
|
17
|
+
"directory": "plugins/proxy-backend"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"backstage"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"start": "backstage-cli backend:dev",
|
|
24
|
+
"build": "backstage-cli backend:build",
|
|
25
|
+
"lint": "backstage-cli lint",
|
|
26
|
+
"test": "backstage-cli test",
|
|
27
|
+
"prepack": "backstage-cli prepack",
|
|
28
|
+
"postpack": "backstage-cli postpack",
|
|
29
|
+
"clean": "backstage-cli clean"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@backstage/backend-common": "^0.9.0",
|
|
33
|
+
"@backstage/config": "^0.1.8",
|
|
34
|
+
"@types/express": "^4.17.6",
|
|
35
|
+
"express": "^4.17.1",
|
|
36
|
+
"express-promise-router": "^4.1.0",
|
|
37
|
+
"http-proxy-middleware": "^2.0.0",
|
|
38
|
+
"morgan": "^1.10.0",
|
|
39
|
+
"uuid": "^8.0.0",
|
|
40
|
+
"winston": "^3.2.1",
|
|
41
|
+
"yaml": "^1.9.2",
|
|
42
|
+
"yn": "^4.0.0",
|
|
43
|
+
"yup": "^0.32.9"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@backstage/cli": "^0.0.0-nightly-20219322159",
|
|
47
|
+
"@types/http-proxy-middleware": "^0.19.3",
|
|
48
|
+
"@types/supertest": "^2.0.8",
|
|
49
|
+
"@types/uuid": "^8.0.0",
|
|
50
|
+
"@types/yup": "^0.29.13",
|
|
51
|
+
"supertest": "^6.1.3"
|
|
52
|
+
},
|
|
53
|
+
"files": [
|
|
54
|
+
"dist",
|
|
55
|
+
"config.d.ts"
|
|
56
|
+
],
|
|
57
|
+
"configSchema": "config.d.ts"
|
|
58
|
+
}
|