@norskvideo/ctl-sdk 0.1.35 → 0.1.36
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/http-proxy.d.ts +4 -0
- package/http-proxy.js +4 -0
- package/package.json +1 -1
- package/proxy-middleware.d.ts +1 -0
- package/proxy-middleware.js +36 -1
package/http-proxy.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ export type ProxyHttpOptions = ForwardResponseOptions & {
|
|
|
25
25
|
timeoutMs?: number;
|
|
26
26
|
};
|
|
27
27
|
/** Proxy one HTTP request to `targetUrl`, streaming the response body back.
|
|
28
|
+
* Forwards the request's headers as they arrive: this runs INSIDE an instance
|
|
29
|
+
* (a product backend fronting its own studio), where the ingress has already
|
|
30
|
+
* blanked the client-supplied identity headers. The runner's product proxy,
|
|
31
|
+
* which sits at the trust boundary, strips them itself in proxy-middleware.ts.
|
|
28
32
|
* Never throws into express: an unreachable/booting upstream surfaces as a
|
|
29
33
|
* 502 the caller retries. */
|
|
30
34
|
export declare function proxyHttp(req: Request, res: Response, targetUrl: string, opts?: ProxyHttpOptions): Promise<void>;
|
package/http-proxy.js
CHANGED
|
@@ -93,6 +93,10 @@ export async function forwardUpstreamResponse(res, upstream, opts = {}) {
|
|
|
93
93
|
}
|
|
94
94
|
const DEFAULT_PROXY_TIMEOUT_MS = 30_000;
|
|
95
95
|
/** Proxy one HTTP request to `targetUrl`, streaming the response body back.
|
|
96
|
+
* Forwards the request's headers as they arrive: this runs INSIDE an instance
|
|
97
|
+
* (a product backend fronting its own studio), where the ingress has already
|
|
98
|
+
* blanked the client-supplied identity headers. The runner's product proxy,
|
|
99
|
+
* which sits at the trust boundary, strips them itself in proxy-middleware.ts.
|
|
96
100
|
* Never throws into express: an unreachable/booting upstream surfaces as a
|
|
97
101
|
* 502 the caller retries. */
|
|
98
102
|
export async function proxyHttp(req, res, targetUrl, opts = {}) {
|
package/package.json
CHANGED
package/proxy-middleware.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ import type { ProductRegistration } from "./product-types.js";
|
|
|
3
3
|
interface ProductRegistry {
|
|
4
4
|
list(): ProductRegistration[];
|
|
5
5
|
}
|
|
6
|
+
export declare function isOauth2SessionCookieName(name: string): boolean;
|
|
6
7
|
export declare function createProductProxyMiddleware(svc: ProductRegistry): (req: Request, res: ExpressResponse, next: NextFunction) => Promise<void>;
|
|
7
8
|
export {};
|
package/proxy-middleware.js
CHANGED
|
@@ -7,6 +7,41 @@ function targetBaseUrl(reg) {
|
|
|
7
7
|
}
|
|
8
8
|
return reg.spec.url.replace(/\/$/, "");
|
|
9
9
|
}
|
|
10
|
+
// The session cookie oauth2-proxy sets at the ctl/mgr ingress (see
|
|
11
|
+
// packages/proxy/src/oauth2-config.ts), including the _0, _1... chunks it
|
|
12
|
+
// splits an oversized session into.
|
|
13
|
+
const OAUTH2_SESSION_COOKIE = /^__(Host|Secure)-[A-Za-z0-9_-]+_oauth2(_\d+)?$/;
|
|
14
|
+
export function isOauth2SessionCookieName(name) {
|
|
15
|
+
return OAUTH2_SESSION_COOKIE.test(name);
|
|
16
|
+
}
|
|
17
|
+
// No product control plane calls back into ctl/mgr, so the ingress secret
|
|
18
|
+
// (full admin), the caller's bearer token and the ingress session cookie
|
|
19
|
+
// have no business reaching one. The whole `x-norsk-*` space goes, per RFC
|
|
20
|
+
// 0003 Phase 0 item 4 — a header the ingress starts asserting later must not
|
|
21
|
+
// reach a product merely because this code was not updated with its name.
|
|
22
|
+
function buildProductForwardHeaders(req) {
|
|
23
|
+
const headers = buildForwardHeaders(req);
|
|
24
|
+
const norskHeaders = [];
|
|
25
|
+
headers.forEach((_value, name) => {
|
|
26
|
+
if (name.toLowerCase().startsWith("x-norsk-"))
|
|
27
|
+
norskHeaders.push(name);
|
|
28
|
+
});
|
|
29
|
+
for (const name of norskHeaders)
|
|
30
|
+
headers.delete(name);
|
|
31
|
+
headers.delete("authorization");
|
|
32
|
+
const cookie = headers.get("cookie");
|
|
33
|
+
if (cookie !== null) {
|
|
34
|
+
const kept = cookie
|
|
35
|
+
.split(";")
|
|
36
|
+
.map((c) => c.trim())
|
|
37
|
+
.filter((c) => c !== "" && !isOauth2SessionCookieName(c.split("=", 1)[0] ?? ""));
|
|
38
|
+
if (kept.length > 0)
|
|
39
|
+
headers.set("cookie", kept.join("; "));
|
|
40
|
+
else
|
|
41
|
+
headers.delete("cookie");
|
|
42
|
+
}
|
|
43
|
+
return headers;
|
|
44
|
+
}
|
|
10
45
|
export function createProductProxyMiddleware(svc) {
|
|
11
46
|
return async (req, res, next) => {
|
|
12
47
|
const name = req.params.name;
|
|
@@ -24,7 +59,7 @@ export function createProductProxyMiddleware(svc) {
|
|
|
24
59
|
return;
|
|
25
60
|
}
|
|
26
61
|
const targetUrl = `${base}${req.url}`;
|
|
27
|
-
const headers =
|
|
62
|
+
const headers = buildProductForwardHeaders(req);
|
|
28
63
|
const body = await readRequestBody(req);
|
|
29
64
|
let upstream;
|
|
30
65
|
try {
|