@floegence/flowersec-core 3.2.0 → 4.0.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/README.md +57 -200
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/dist/browser/index.d.ts +0 -5
- package/dist/browser/index.js +0 -3
- package/dist/cli.js +93 -64
- package/dist/facade.d.ts +0 -17
- package/dist/facade.js +0 -11
- package/dist/generated/unicode151.d.ts +2 -0
- package/dist/generated/unicode151.js +83 -0
- package/dist/interop/proxyServerPeer.js +34 -20
- package/dist/interop/serverParityPeer.js +11 -252
- package/dist/node/acceptor.d.ts +1 -57
- package/dist/node/acceptor.js +3 -420
- package/dist/node/acceptorV3.js +2 -2
- package/dist/node/connectSessionV3.js +2 -2
- package/dist/node/index.d.ts +2 -17
- package/dist/node/index.js +1 -9
- package/dist/node/nativeTransportAddon.d.ts +7 -36
- package/dist/node/nativeTransportAddon.js +7 -27
- package/dist/node/proxyServer.d.ts +2 -2
- package/dist/node/proxyServer.js +2 -2
- package/dist/node/rawQuicAdapterV3.d.ts +2 -2
- package/dist/node/rawQuicAdapterV3.js +1 -1
- package/dist/node/rawQuicServerV3.d.ts +2 -2
- package/dist/node/rawQuicServerV3.js +1 -1
- package/dist/node/rawQuicTls.d.ts +2 -0
- package/dist/node/{rawQuicAdapter.js → rawQuicTls.js} +30 -45
- package/dist/node/tunnelRuntimeV3.js +2 -2
- package/dist/proxy/integration.d.ts +5 -5
- package/dist/proxy/integration.js +2 -2
- package/dist/public/streamHandlers.d.ts +0 -3
- package/dist/public/streamHandlers.js +2 -4
- package/dist/public/streamMetadata.js +2 -2
- package/dist/runtime/errors.d.ts +2 -2
- package/dist/testSupport/tlsFixture.d.ts +2 -0
- package/dist/testSupport/tlsFixture.js +8 -0
- package/dist/utils/errors.d.ts +0 -2
- package/dist/utils/errors.js +0 -80
- package/dist/v3/artifact.js +17 -3
- package/dist/v3/carrier.d.ts +2 -2
- package/dist/v3/protocol.js +2 -103
- package/dist/v3/retryDisposition.d.ts +2 -2
- package/dist/v3/retryDisposition.js +0 -7
- package/dist/vendor/tr46.d.ts +4 -0
- package/dist/vendor/tr46.js +37 -32
- package/package.json +21 -19
- package/sbom/cyclonedx.json +62 -62
- package/sbom/spdx.json +65 -65
- package/dist/browser/connectSession.d.ts +0 -13
- package/dist/browser/connectSession.js +0 -40
- package/dist/browser/runtimeCapability.d.ts +0 -13
- package/dist/browser/runtimeCapability.js +0 -27
- package/dist/browser/sessionRuntime.d.ts +0 -2
- package/dist/browser/sessionRuntime.js +0 -21
- package/dist/browser/v2.d.ts +0 -3
- package/dist/browser/v2.js +0 -2
- package/dist/browser/webTransportClient.d.ts +0 -8
- package/dist/browser/webTransportClient.js +0 -55
- package/dist/connectionController.d.ts +0 -55
- package/dist/connectionController.js +0 -441
- package/dist/connector/adapters/rawQuicCandidate.d.ts +0 -5
- package/dist/connector/adapters/rawQuicCandidate.js +0 -71
- package/dist/connector/adapters/webSocketCandidate.d.ts +0 -7
- package/dist/connector/adapters/webSocketCandidate.js +0 -116
- package/dist/connector/adapters/webTransportCandidate.d.ts +0 -5
- package/dist/connector/adapters/webTransportCandidate.js +0 -73
- package/dist/connector/admissionCommit.d.ts +0 -31
- package/dist/connector/admissionCommit.js +0 -239
- package/dist/connector/sessionAcceptor.d.ts +0 -38
- package/dist/connector/sessionAcceptor.js +0 -158
- package/dist/connector/sessionConfig.d.ts +0 -3
- package/dist/connector/sessionConfig.js +0 -30
- package/dist/connector/sessionConnector.d.ts +0 -47
- package/dist/connector/sessionConnector.js +0 -606
- package/dist/node/connectSession.d.ts +0 -23
- package/dist/node/connectSession.js +0 -93
- package/dist/node/controlplane.d.ts +0 -137
- package/dist/node/controlplane.js +0 -443
- package/dist/node/rawQuicAdapter.d.ts +0 -9
- package/dist/node/rawQuicServer.d.ts +0 -24
- package/dist/node/rawQuicServer.js +0 -37
- package/dist/node/runtimeCapability.d.ts +0 -14
- package/dist/node/runtimeCapability.js +0 -24
- package/dist/node/sessionRuntime.d.ts +0 -2
- package/dist/node/sessionRuntime.js +0 -13
- package/dist/node/tunnelRuntime.d.ts +0 -42
- package/dist/node/tunnelRuntime.js +0 -559
- package/dist/node/v2.d.ts +0 -11
- package/dist/node/v2.js +0 -6
- package/dist/node/webSocketServer.d.ts +0 -24
- package/dist/node/webSocketServer.js +0 -135
- package/dist/public/artifact.d.ts +0 -11
- package/dist/public/artifact.js +0 -44
- package/dist/public/artifactLease.d.ts +0 -10
- package/dist/public/artifactLease.js +0 -41
- package/dist/public/connectError.d.ts +0 -6
- package/dist/public/connectError.js +0 -9
- package/dist/transport/webSocketAdapter.d.ts +0 -31
- package/dist/transport/webSocketAdapter.js +0 -370
- package/dist/transport/webTransportAdapter.d.ts +0 -27
- package/dist/transport/webTransportAdapter.js +0 -534
- package/dist/v2/admissionError.d.ts +0 -4
- package/dist/v2/admissionError.js +0 -8
- package/dist/v2/artifact.d.ts +0 -128
- package/dist/v2/artifact.js +0 -1131
- package/dist/v2/artifactLease.d.ts +0 -1
- package/dist/v2/artifactLease.js +0 -7
- package/dist/v2/capability.d.ts +0 -29
- package/dist/v2/capability.js +0 -190
- package/dist/v2/carrier.d.ts +0 -84
- package/dist/v2/carrier.js +0 -411
- package/dist/v2/contract.d.ts +0 -46
- package/dist/v2/contract.js +0 -1
- package/dist/v2/handshake.d.ts +0 -80
- package/dist/v2/handshake.js +0 -470
- package/dist/v2/index.d.ts +0 -14
- package/dist/v2/index.js +0 -7
- package/dist/v2/opaqueArtifact.d.ts +0 -1
- package/dist/v2/opaqueArtifact.js +0 -2
- package/dist/v2/protocol.d.ts +0 -99
- package/dist/v2/protocol.js +0 -737
- package/dist/v2/publicSession.d.ts +0 -1
- package/dist/v2/publicSession.js +0 -281
- package/dist/v2/retryDisposition.d.ts +0 -16
- package/dist/v2/retryDisposition.js +0 -30
- package/dist/v2/session.d.ts +0 -310
- package/dist/v2/session.js +0 -2127
- package/dist/v2/streamLifetimeLedger.d.ts +0 -31
- package/dist/v2/streamLifetimeLedger.js +0 -131
- package/dist/v2/streamMetadata.d.ts +0 -1
- package/dist/v2/streamMetadata.js +0 -7
- package/dist/v2/unreliableMessage.d.ts +0 -43
- package/dist/v2/unreliableMessage.js +0 -254
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { CarrierError
|
|
3
|
-
export const NATIVE_TRANSPORT_CONTRACT_VERSION =
|
|
2
|
+
import { CarrierError } from "../v3/carrier.js";
|
|
3
|
+
export const NATIVE_TRANSPORT_CONTRACT_VERSION = 3;
|
|
4
4
|
const NATIVE_PACKAGE = "@floegence/flowersec-node-native";
|
|
5
5
|
const SERVER_PARITY_NATIVE_ADDON = "FLOWERSEC_SERVER_PARITY_NATIVE_ADDON";
|
|
6
6
|
export class NativeTransportUnavailableError extends Error {
|
|
@@ -45,31 +45,13 @@ export function createNativeRawQuicDriver(addon = loadNativeTransportAddon()) {
|
|
|
45
45
|
return Object.freeze({
|
|
46
46
|
async connectRawQuic(options, operation = {}) {
|
|
47
47
|
const native = await settle(addon.connectRawQuic(options), operation.signal);
|
|
48
|
-
return wrapSession(native
|
|
48
|
+
return wrapSession(native);
|
|
49
49
|
},
|
|
50
50
|
async bindRawQuic(options) {
|
|
51
51
|
const native = await addon.bindRawQuic(options);
|
|
52
52
|
return Object.freeze({
|
|
53
53
|
address: () => native.address(),
|
|
54
|
-
accept: async (operation = {}) => wrapSession(await settle(native.accept(), operation.signal)
|
|
55
|
-
async close() {
|
|
56
|
-
await native.close();
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export function createNativeRawQuicDriverV3(addon = loadNativeTransportAddon()) {
|
|
63
|
-
return Object.freeze({
|
|
64
|
-
async connectRawQuic(options, operation = {}) {
|
|
65
|
-
const native = await settle(addon.connectRawQuicV3(options), operation.signal);
|
|
66
|
-
return wrapSession(native, 3);
|
|
67
|
-
},
|
|
68
|
-
async bindRawQuic(options) {
|
|
69
|
-
const native = await addon.bindRawQuicV3(options);
|
|
70
|
-
return Object.freeze({
|
|
71
|
-
address: () => native.address(),
|
|
72
|
-
accept: async (operation = {}) => wrapSession(await settle(native.accept(), operation.signal), 3),
|
|
54
|
+
accept: async (operation = {}) => wrapSession(await settle(native.accept(), operation.signal)),
|
|
73
55
|
async close() {
|
|
74
56
|
await native.close();
|
|
75
57
|
},
|
|
@@ -92,12 +74,10 @@ function isNativeTransportAddon(value) {
|
|
|
92
74
|
}
|
|
93
75
|
return contractVersion === NATIVE_TRANSPORT_CONTRACT_VERSION &&
|
|
94
76
|
typeof candidate.connectRawQuic === "function" &&
|
|
95
|
-
typeof candidate.bindRawQuic === "function"
|
|
96
|
-
typeof candidate.connectRawQuicV3 === "function" &&
|
|
97
|
-
typeof candidate.bindRawQuicV3 === "function";
|
|
77
|
+
typeof candidate.bindRawQuic === "function";
|
|
98
78
|
}
|
|
99
|
-
function wrapSession(native
|
|
100
|
-
if (native.wireVersion !==
|
|
79
|
+
function wrapSession(native) {
|
|
80
|
+
if (native.wireVersion !== 3) {
|
|
101
81
|
native.abort();
|
|
102
82
|
throw new NativeTransportUnavailableError();
|
|
103
83
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StreamHandlers } from "../public/streamHandlers.js";
|
|
2
|
-
import {
|
|
3
|
-
export type StreamHandlerRegistrar = StreamHandlers |
|
|
2
|
+
import { SessionHandlersV3 } from "./acceptor.js";
|
|
3
|
+
export type StreamHandlerRegistrar = StreamHandlers | SessionHandlersV3;
|
|
4
4
|
export type ProxyServerOptions = Readonly<{
|
|
5
5
|
upstream: string;
|
|
6
6
|
upstreamOrigin: string;
|
package/dist/node/proxyServer.js
CHANGED
|
@@ -3,7 +3,7 @@ import { SessionError } from "../public/contract.js";
|
|
|
3
3
|
import { writeJsonFrame } from "../framing/jsonframe.js";
|
|
4
4
|
import { ProxyByteReader, writeAll } from "../proxy/stream.js";
|
|
5
5
|
import { StreamHandlers, registerStreamHandlersAtomically, } from "../public/streamHandlers.js";
|
|
6
|
-
import {
|
|
6
|
+
import { SessionHandlersV3, registerSessionStreamHandlersAtomically, } from "./acceptor.js";
|
|
7
7
|
const HTTP_KIND = "flowersec-proxy/http1";
|
|
8
8
|
const WS_KIND = "flowersec-proxy/ws";
|
|
9
9
|
const WIRE_VERSION = 1;
|
|
@@ -47,7 +47,7 @@ export class ProxyServer {
|
|
|
47
47
|
if (handlers instanceof StreamHandlers) {
|
|
48
48
|
registerStreamHandlersAtomically(handlers, registrations);
|
|
49
49
|
}
|
|
50
|
-
else if (handlers instanceof
|
|
50
|
+
else if (handlers instanceof SessionHandlersV3) {
|
|
51
51
|
registerSessionStreamHandlersAtomically(handlers, registrations);
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ArtifactV3, CanonicalArtifactCandidateV3 } from "../v3/artifact.js";
|
|
2
2
|
import type { NativeCarrierSessionV3 } from "../v3/carrier.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { NativeRawQuicDriver } from "./nativeTransportAddon.js";
|
|
4
4
|
type NodeTLSRootsV3 = string | Uint8Array | readonly (string | Uint8Array)[];
|
|
5
|
-
export declare function createNodeRawQuicClientV3(driver:
|
|
5
|
+
export declare function createNodeRawQuicClientV3(driver: NativeRawQuicDriver, candidate: CanonicalArtifactCandidateV3, artifact: ArtifactV3, attemptNowUnixSeconds: number, options?: Readonly<{
|
|
6
6
|
roots?: NodeTLSRootsV3;
|
|
7
7
|
signal?: AbortSignal;
|
|
8
8
|
handshakeTimeoutMs?: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rootCertificates } from "node:tls";
|
|
2
2
|
import { snapshotTransportSecurityPolicyV3, TransportFailureV3, } from "../v3/security.js";
|
|
3
|
-
import { normalizeCertificateChain } from "./
|
|
3
|
+
import { normalizeCertificateChain } from "./rawQuicTls.js";
|
|
4
4
|
import { alpnForPathV3 } from "../v3/transportConstants.js";
|
|
5
5
|
const DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
6
6
|
export async function createNodeRawQuicClientV3(driver, candidate, artifact, attemptNowUnixSeconds, options = {}) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CarrierSessionV3 } from "../v3/carrier.js";
|
|
2
2
|
import type { PathKind } from "../v3/contract.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { NativeRawQuicDriver } from "./nativeTransportAddon.js";
|
|
4
4
|
export type NodeRawQuicListenerOptionsV3 = Readonly<{
|
|
5
5
|
host: string;
|
|
6
6
|
port: number;
|
|
@@ -21,4 +21,4 @@ export type NodeRawQuicListenerV3 = Readonly<{
|
|
|
21
21
|
}>): Promise<CarrierSessionV3>;
|
|
22
22
|
close(): Promise<void>;
|
|
23
23
|
}>;
|
|
24
|
-
export declare function startNodeRawQuicListenerV3(driver:
|
|
24
|
+
export declare function startNodeRawQuicListenerV3(driver: NativeRawQuicDriver, options: NodeRawQuicListenerOptionsV3): Promise<NodeRawQuicListenerV3>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { adaptNativeCarrierSessionV3 } from "../v3/carrier.js";
|
|
2
|
-
import { normalizeCertificateChain, normalizePrivateKey } from "./
|
|
2
|
+
import { normalizeCertificateChain, normalizePrivateKey } from "./rawQuicTls.js";
|
|
3
3
|
export async function startNodeRawQuicListenerV3(driver, options) {
|
|
4
4
|
validateOptions(options);
|
|
5
5
|
let listener;
|
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
import { X509Certificate, createPrivateKey } from "node:crypto";
|
|
2
|
-
const DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
3
2
|
const CERTIFICATE_PEM_BEGIN = "-----BEGIN CERTIFICATE-----";
|
|
4
3
|
const CERTIFICATE_PEM_END = "-----END CERTIFICATE-----";
|
|
5
4
|
const MAX_CERTIFICATE_PEM_BYTES = 256 * 1024;
|
|
6
5
|
const MAX_CERTIFICATE_CHAIN_LENGTH = 32;
|
|
7
|
-
export async function createNodeRawQuicClientV2(driver, candidate, artifact, tls, signal, handshakeTimeoutMs = DEFAULT_HANDSHAKE_TIMEOUT_MS) {
|
|
8
|
-
const url = new URL(candidate.normalized_url);
|
|
9
|
-
if (candidate.carrier !== "raw_quic" || url.protocol !== "quic:" || url.port === "") {
|
|
10
|
-
throw new TypeError("invalid raw QUIC candidate");
|
|
11
|
-
}
|
|
12
|
-
const options = {
|
|
13
|
-
host: unbracket(url.hostname),
|
|
14
|
-
port: Number(url.port),
|
|
15
|
-
serverName: unbracket(url.hostname),
|
|
16
|
-
path: artifact.path.kind,
|
|
17
|
-
trustRootsDer: normalizeCertificateChain(tls.ca),
|
|
18
|
-
inboundBidirectionalStreamCapacity: artifact.session.max_inbound_streams + 2,
|
|
19
|
-
handshakeTimeoutMs,
|
|
20
|
-
};
|
|
21
|
-
return await driver.connectRawQuic(options, { signal });
|
|
22
|
-
}
|
|
23
6
|
export function normalizeCertificateChain(input) {
|
|
24
7
|
const values = Array.isArray(input) ? input : [input];
|
|
25
8
|
const certificates = [];
|
|
@@ -28,32 +11,46 @@ export function normalizeCertificateChain(input) {
|
|
|
28
11
|
if (typeof value !== "string" && !(value instanceof Uint8Array)) {
|
|
29
12
|
throw new TypeError("invalid raw QUIC certificate");
|
|
30
13
|
}
|
|
31
|
-
totalInputBytes += typeof value === "string"
|
|
32
|
-
|
|
14
|
+
totalInputBytes += typeof value === "string"
|
|
15
|
+
? Buffer.byteLength(value, "utf8")
|
|
16
|
+
: value.byteLength;
|
|
17
|
+
if (totalInputBytes > MAX_CERTIFICATE_PEM_BYTES) {
|
|
33
18
|
throw new TypeError("invalid raw QUIC certificate");
|
|
19
|
+
}
|
|
34
20
|
if (typeof value === "string") {
|
|
35
21
|
const blocks = splitCertificatePEM(value);
|
|
36
|
-
if (blocks.length === 0)
|
|
37
|
-
throw new TypeError("invalid raw QUIC certificate");
|
|
38
|
-
if (certificates.length + blocks.length > MAX_CERTIFICATE_CHAIN_LENGTH) {
|
|
22
|
+
if (blocks.length === 0 || certificates.length + blocks.length > MAX_CERTIFICATE_CHAIN_LENGTH) {
|
|
39
23
|
throw new TypeError("invalid raw QUIC certificate");
|
|
40
24
|
}
|
|
41
25
|
for (const block of blocks)
|
|
42
26
|
certificates.push(parseCertificate(block));
|
|
43
27
|
}
|
|
44
|
-
else if (value
|
|
45
|
-
if (certificates.length >= MAX_CERTIFICATE_CHAIN_LENGTH)
|
|
28
|
+
else if (value.length > 0) {
|
|
29
|
+
if (certificates.length >= MAX_CERTIFICATE_CHAIN_LENGTH) {
|
|
46
30
|
throw new TypeError("invalid raw QUIC certificate");
|
|
31
|
+
}
|
|
47
32
|
certificates.push(parseCertificate(value));
|
|
48
33
|
}
|
|
49
34
|
else {
|
|
50
35
|
throw new TypeError("invalid raw QUIC certificate");
|
|
51
36
|
}
|
|
52
37
|
}
|
|
53
|
-
if (certificates.length === 0)
|
|
38
|
+
if (certificates.length === 0) {
|
|
54
39
|
throw new TypeError("raw QUIC requires explicit trust roots");
|
|
40
|
+
}
|
|
55
41
|
return certificates;
|
|
56
42
|
}
|
|
43
|
+
export function normalizePrivateKey(input) {
|
|
44
|
+
if (input.length === 0)
|
|
45
|
+
throw new TypeError("invalid raw QUIC private key");
|
|
46
|
+
try {
|
|
47
|
+
const key = createPrivateKey(input);
|
|
48
|
+
return new Uint8Array(key.export({ format: "der", type: "pkcs8" }));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new TypeError("invalid raw QUIC private key");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
57
54
|
function splitCertificatePEM(value) {
|
|
58
55
|
if (Buffer.byteLength(value, "utf8") > MAX_CERTIFICATE_PEM_BYTES) {
|
|
59
56
|
throw new TypeError("invalid raw QUIC certificate");
|
|
@@ -63,37 +60,28 @@ function splitCertificatePEM(value) {
|
|
|
63
60
|
while (cursor < value.length) {
|
|
64
61
|
const begin = value.indexOf(CERTIFICATE_PEM_BEGIN, cursor);
|
|
65
62
|
if (begin < 0) {
|
|
66
|
-
if (value.slice(cursor).trim().length !== 0)
|
|
63
|
+
if (value.slice(cursor).trim().length !== 0) {
|
|
67
64
|
throw new TypeError("invalid raw QUIC certificate");
|
|
65
|
+
}
|
|
68
66
|
break;
|
|
69
67
|
}
|
|
70
|
-
if (value.slice(cursor, begin).trim().length !== 0)
|
|
68
|
+
if (value.slice(cursor, begin).trim().length !== 0) {
|
|
71
69
|
throw new TypeError("invalid raw QUIC certificate");
|
|
70
|
+
}
|
|
72
71
|
const contentStart = begin + CERTIFICATE_PEM_BEGIN.length;
|
|
73
72
|
const end = value.indexOf(CERTIFICATE_PEM_END, contentStart);
|
|
74
|
-
|
|
73
|
+
const nested = value.indexOf(CERTIFICATE_PEM_BEGIN, contentStart);
|
|
74
|
+
if (end < 0 || nested >= 0 && nested < end) {
|
|
75
75
|
throw new TypeError("invalid raw QUIC certificate");
|
|
76
76
|
}
|
|
77
77
|
blocks.push(value.slice(begin, end + CERTIFICATE_PEM_END.length));
|
|
78
|
-
if (blocks.length > MAX_CERTIFICATE_CHAIN_LENGTH)
|
|
78
|
+
if (blocks.length > MAX_CERTIFICATE_CHAIN_LENGTH) {
|
|
79
79
|
throw new TypeError("invalid raw QUIC certificate");
|
|
80
|
+
}
|
|
80
81
|
cursor = end + CERTIFICATE_PEM_END.length;
|
|
81
82
|
}
|
|
82
83
|
return blocks;
|
|
83
84
|
}
|
|
84
|
-
export function normalizePrivateKey(input) {
|
|
85
|
-
if ((typeof input === "string" && input.length === 0) ||
|
|
86
|
-
(input instanceof Uint8Array && input.length === 0)) {
|
|
87
|
-
throw new TypeError("invalid raw QUIC private key");
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
const key = createPrivateKey(input);
|
|
91
|
-
return new Uint8Array(key.export({ format: "der", type: "pkcs8" }));
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
throw new TypeError("invalid raw QUIC private key");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
85
|
function parseCertificate(input) {
|
|
98
86
|
try {
|
|
99
87
|
return new Uint8Array(new X509Certificate(input).raw);
|
|
@@ -102,6 +90,3 @@ function parseCertificate(input) {
|
|
|
102
90
|
throw new TypeError("invalid raw QUIC certificate");
|
|
103
91
|
}
|
|
104
92
|
}
|
|
105
|
-
function unbracket(host) {
|
|
106
|
-
return host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
107
|
-
}
|
|
@@ -2,7 +2,7 @@ import { createAdmissionReasonRegistryV3, receiveSessionAdmissionV3, rejectSessi
|
|
|
2
2
|
import { configureServerWebSocketCarrierRoleV3 } from "../v3/webSocketCarrier.js";
|
|
3
3
|
import { AdmissionStatusV3, encodeFSA3ResponseV3, } from "../v3/artifact.js";
|
|
4
4
|
import { startNodeWebSocketListenerV3 } from "./webSocketServerV3.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createNativeRawQuicDriver } from "./nativeTransportAddon.js";
|
|
6
6
|
import { startNodeRawQuicListenerV3 } from "./rawQuicServerV3.js";
|
|
7
7
|
import { consumeTunnelAuthorizationGrantV3, inspectTunnelAuthorizationGrantV3, retireTunnelAuthorizationGrantV3, runtimeAuthorizationRequestV3FromDecoded, validateTunnelAuthorizationGrantV3, } from "./runtimeAuthorizationV3.js";
|
|
8
8
|
const DEFAULT_PAIR_TIMEOUT_MS = 10_000;
|
|
@@ -107,7 +107,7 @@ async function startTunnelRuntimeV3(state) {
|
|
|
107
107
|
pendingSessionTimeoutMs: state.limits.admissionTimeoutMs,
|
|
108
108
|
cleanupTimeoutMs: state.limits.cleanupTimeoutMs,
|
|
109
109
|
})
|
|
110
|
-
: await startNodeRawQuicListenerV3(rawQuicDriver ??=
|
|
110
|
+
: await startNodeRawQuicListenerV3(rawQuicDriver ??= createNativeRawQuicDriver(), {
|
|
111
111
|
...listener,
|
|
112
112
|
path: "tunnel",
|
|
113
113
|
inboundBidirectionalStreamCapacity: state.options.maxInboundStreams + 2,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type {
|
|
1
|
+
import { type SessionOptionsV3 } from "../browser/connectSessionV3.js";
|
|
2
|
+
import type { ArtifactLeaseV3 } from "../v3/artifactLease.js";
|
|
3
3
|
import type { Session } from "../public/contract.js";
|
|
4
4
|
import type { ProxyRuntime, ProxyRuntimeOptions } from "./types.js";
|
|
5
5
|
import { type ProxyControllerWindowHandle, type RegisterProxyControllerWindowOptions } from "./windowBridge.js";
|
|
6
6
|
export type ProxyBrowserConnectOptions = Readonly<{
|
|
7
|
-
connect?:
|
|
7
|
+
connect?: SessionOptionsV3;
|
|
8
8
|
runtime?: Omit<ProxyRuntimeOptions, "session">;
|
|
9
9
|
serviceWorker?: Readonly<{
|
|
10
10
|
scriptUrl: string;
|
|
@@ -19,11 +19,11 @@ export type ProxyBrowserHandle = Readonly<{
|
|
|
19
19
|
runtime: ProxyRuntime;
|
|
20
20
|
dispose(): Promise<void>;
|
|
21
21
|
}>;
|
|
22
|
-
export declare function connectProxyBrowser(lease:
|
|
22
|
+
export declare function connectProxyBrowser(lease: ArtifactLeaseV3, options?: ProxyBrowserConnectOptions): Promise<ProxyBrowserHandle>;
|
|
23
23
|
export type ProxyControllerBrowserConnectOptions = ProxyBrowserConnectOptions & Readonly<{
|
|
24
24
|
controller: Omit<RegisterProxyControllerWindowOptions, "runtime">;
|
|
25
25
|
}>;
|
|
26
26
|
export type ProxyControllerBrowserHandle = ProxyBrowserHandle & Readonly<{
|
|
27
27
|
controller: ProxyControllerWindowHandle;
|
|
28
28
|
}>;
|
|
29
|
-
export declare function connectProxyControllerBrowser(lease:
|
|
29
|
+
export declare function connectProxyControllerBrowser(lease: ArtifactLeaseV3, options: ProxyControllerBrowserConnectOptions): Promise<ProxyControllerBrowserHandle>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { connectV3 } from "../browser/connectSessionV3.js";
|
|
2
2
|
import { createProxyRuntime } from "./runtime.js";
|
|
3
3
|
import { registerServiceWorkerAndEnsureControl } from "./registerServiceWorker.js";
|
|
4
4
|
import { registerProxyControllerWindow, } from "./windowBridge.js";
|
|
5
5
|
export async function connectProxyBrowser(lease, options = {}) {
|
|
6
|
-
const session = await
|
|
6
|
+
const session = await connectV3(lease, options.connect);
|
|
7
7
|
let runtime;
|
|
8
8
|
try {
|
|
9
9
|
if (options.serviceWorker !== undefined)
|
|
@@ -18,6 +18,3 @@ export declare class StreamHandlers {
|
|
|
18
18
|
handleStream(kind: string, handler: StreamHandler): void;
|
|
19
19
|
serve(session: Session, options?: OperationOptions): Promise<void>;
|
|
20
20
|
}
|
|
21
|
-
/** Explicit-compatibility application-stream handlers. */
|
|
22
|
-
export declare class LegacyStreamHandlers extends StreamHandlers {
|
|
23
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SessionError, } from "./contract.js";
|
|
2
|
-
import { validApplicationStreamKind } from "../
|
|
2
|
+
import { validApplicationStreamKind } from "../v3/protocol.js";
|
|
3
3
|
const DEFAULT_MAX_CONCURRENT_STREAMS = 64;
|
|
4
4
|
const MAX_CONCURRENT_STREAMS = 128;
|
|
5
5
|
export class HandlerRegistrationError extends Error {
|
|
@@ -11,6 +11,7 @@ export class HandlerRegistrationError extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
const streamHandlerStates = new WeakMap();
|
|
14
|
+
// The v2 identifier is denied so it cannot be repurposed as an application stream.
|
|
14
15
|
const RESERVED_RPC_KINDS = new Set(["flowersec.rpc.v2", "flowersec.rpc.v3"]);
|
|
15
16
|
/** Carrier-neutral application-stream handlers for any established Session. */
|
|
16
17
|
export class StreamHandlers {
|
|
@@ -38,9 +39,6 @@ export class StreamHandlers {
|
|
|
38
39
|
await serveFrozenStreamHandlers(freezeStreamHandlers(this), session, options, async () => await session.close());
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
|
-
/** Explicit-compatibility application-stream handlers. */
|
|
42
|
-
export class LegacyStreamHandlers extends StreamHandlers {
|
|
43
|
-
}
|
|
44
42
|
function mutableStreamHandlerState(handlers) {
|
|
45
43
|
const state = streamHandlerStates.get(handlers);
|
|
46
44
|
if (state === undefined)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { canonicalStreamMetadataJSONV3Internal } from "../v3/protocol.js";
|
|
2
2
|
export class StreamMetadataError extends Error {
|
|
3
3
|
constructor() {
|
|
4
4
|
super("invalid Flowersec stream metadata");
|
|
@@ -18,7 +18,7 @@ export class StreamMetadata {
|
|
|
18
18
|
}
|
|
19
19
|
export function createStreamMetadata(values) {
|
|
20
20
|
try {
|
|
21
|
-
const canonical =
|
|
21
|
+
const canonical = canonicalStreamMetadataJSONV3Internal(values);
|
|
22
22
|
return StreamMetadata.fromCanonicalValues(deepFreeze(JSON.parse(canonical)));
|
|
23
23
|
}
|
|
24
24
|
catch {
|
package/dist/runtime/errors.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type RuntimeErrorCode = "runtime_unsupported" | "runtime_start_failed" | "runtime_crashed";
|
|
2
2
|
export declare class RuntimeError extends Error {
|
|
3
3
|
readonly code: RuntimeErrorCode;
|
|
4
|
-
readonly cause?: unknown
|
|
5
|
-
constructor(code: RuntimeErrorCode, message: string, cause?: unknown
|
|
4
|
+
readonly cause?: unknown;
|
|
5
|
+
constructor(code: RuntimeErrorCode, message: string, cause?: unknown);
|
|
6
6
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const certificateDER = Buffer.from("MIIBjzCCAUGgAwIBAgIUW8hQEpQsUJN9a6qqF2g6hsNpSm8wBQYDK2VwMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yNjA3MjAxOTAxMjFaFw0zNjA3MTcxOTAxMjFaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAqMAUGAytlcAMhAAihki/Jec+1EaC6E6PsSxjMYFAazrgkNiUIlbj/+A/0o4GkMIGhMB0GA1UdDgQWBBQCuKxQmMQkAAy9KkfuD+WOmrrMbTAfBgNVHSMEGDAWgBQCuKxQmMQkAAy9KkfuD+WOmrrMbTAsBgNVHREEJTAjgglsb2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwBQYDK2VwA0EArZng3XitiH2E1pW/NTxQvEOBXJYpYE8coQmLV4yTjfI43CWHMG6lIrwk/so67oe6Z2R4iHGjUm3Tuy50Fl8hBw==", "base64");
|
|
2
|
+
const privateKeyDER = Buffer.from("MC4CAQAwBQYDK2VwBCIEICxYUWHqGoh0CBBohsaNg/NThm1n3UeWCzYuq6jS+Qi6", "base64");
|
|
3
|
+
export const testCertificatePEM = pem("CERTIFICATE", certificateDER);
|
|
4
|
+
export const testPrivateKeyPEM = pem("PRIVATE KEY", privateKeyDER);
|
|
5
|
+
function pem(label, der) {
|
|
6
|
+
const lines = Buffer.from(der).toString("base64").match(/.{1,64}/gu) ?? [];
|
|
7
|
+
return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
|
|
8
|
+
}
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -4,5 +4,3 @@ export declare class TimeoutError extends Error {
|
|
|
4
4
|
export declare class AbortError extends Error {
|
|
5
5
|
constructor(message?: string);
|
|
6
6
|
}
|
|
7
|
-
export type ConnectErrorPath = "auto" | "tunnel" | "direct";
|
|
8
|
-
export type ConnectErrorStage = "validate" | "connect" | "session" | "rpc" | "close";
|
package/dist/utils/errors.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ConnectError } from "../public/connectError.js";
|
|
2
1
|
export class TimeoutError extends Error {
|
|
3
2
|
constructor(message = "timeout") {
|
|
4
3
|
super(message);
|
|
@@ -11,87 +10,8 @@ export class AbortError extends Error {
|
|
|
11
10
|
this.name = "AbortError";
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
|
-
const internalDetails = new WeakMap();
|
|
15
|
-
/** @internal */
|
|
16
|
-
export function createConnectErrorInternal(args) {
|
|
17
|
-
const error = new ConnectError(publicCode(args.code));
|
|
18
|
-
internalDetails.set(error, Object.freeze({
|
|
19
|
-
code: args.code,
|
|
20
|
-
stage: args.stage,
|
|
21
|
-
...(args.cause === undefined ? {} : { cause: args.cause }),
|
|
22
|
-
diagnostics: Object.freeze((args.diagnostics ?? []).map((diagnostic) => Object.freeze({ ...diagnostic }))),
|
|
23
|
-
}));
|
|
24
|
-
return error;
|
|
25
|
-
}
|
|
26
|
-
/** @internal */
|
|
27
|
-
export function connectErrorDetailsInternal(error) {
|
|
28
|
-
return internalDetails.get(error) ?? Object.freeze({
|
|
29
|
-
code: internalCode(error.code),
|
|
30
|
-
stage: "connect",
|
|
31
|
-
diagnostics: Object.freeze([]),
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
/** @internal */
|
|
35
|
-
export function isTimeoutError(e) {
|
|
36
|
-
return e instanceof TimeoutError;
|
|
37
|
-
}
|
|
38
|
-
/** @internal */
|
|
39
|
-
export function isAbortError(e) {
|
|
40
|
-
return e instanceof AbortError;
|
|
41
|
-
}
|
|
42
|
-
/** @internal */
|
|
43
|
-
export function isConnectError(e) {
|
|
44
|
-
return e instanceof ConnectError;
|
|
45
|
-
}
|
|
46
13
|
/** @internal */
|
|
47
14
|
export function throwIfAborted(signal, message) {
|
|
48
15
|
if (signal?.aborted)
|
|
49
16
|
throw new AbortError(message);
|
|
50
17
|
}
|
|
51
|
-
function publicCode(code) {
|
|
52
|
-
switch (code) {
|
|
53
|
-
case "timeout": return "timeout";
|
|
54
|
-
case "canceled": return "canceled";
|
|
55
|
-
case "resolve_failed": return "resolve_failed";
|
|
56
|
-
case "credential_commit_failed": return "credential_spend_failed";
|
|
57
|
-
case "handshake_failed": return "handshake_failed";
|
|
58
|
-
case "rpc_failed": return "rpc_failed";
|
|
59
|
-
case "resource_exhausted": return "resource_exhausted";
|
|
60
|
-
case "not_connected": return "not_connected";
|
|
61
|
-
case "invalid_option": return "invalid_options";
|
|
62
|
-
case "timestamp_after_init_exp": return "expired_artifact";
|
|
63
|
-
case "dial_failed":
|
|
64
|
-
case "upgrade_failed":
|
|
65
|
-
case "attach_failed":
|
|
66
|
-
case "unsupported_capability":
|
|
67
|
-
case "too_many_connections":
|
|
68
|
-
case "policy_denied":
|
|
69
|
-
case "policy_error":
|
|
70
|
-
case "replace_rate_limited":
|
|
71
|
-
case "ping_failed":
|
|
72
|
-
case "rekey_failed":
|
|
73
|
-
case "mux_failed":
|
|
74
|
-
case "accept_stream_failed":
|
|
75
|
-
case "open_stream_failed":
|
|
76
|
-
case "stream_hello_failed":
|
|
77
|
-
return "connection_failed";
|
|
78
|
-
default:
|
|
79
|
-
return "invalid_input";
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function internalCode(code) {
|
|
83
|
-
switch (code) {
|
|
84
|
-
case "invalid_input": return "invalid_input";
|
|
85
|
-
case "invalid_options": return "invalid_option";
|
|
86
|
-
case "expired_artifact": return "timestamp_after_init_exp";
|
|
87
|
-
case "resolve_failed": return "resolve_failed";
|
|
88
|
-
case "credential_spend_failed": return "credential_commit_failed";
|
|
89
|
-
case "connection_failed": return "dial_failed";
|
|
90
|
-
case "timeout": return "timeout";
|
|
91
|
-
case "canceled": return "canceled";
|
|
92
|
-
case "handshake_failed": return "handshake_failed";
|
|
93
|
-
case "rpc_failed": return "rpc_failed";
|
|
94
|
-
case "resource_exhausted": return "resource_exhausted";
|
|
95
|
-
case "not_connected": return "not_connected";
|
|
96
|
-
}
|
|
97
|
-
}
|
package/dist/v3/artifact.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
2
|
import { base64urlDecode, base64urlEncode } from "../utils/base64url.js";
|
|
3
3
|
import { concatBytes, readU32be, u32be } from "../utils/bin.js";
|
|
4
|
-
import {
|
|
4
|
+
import { unicode151Assigned } from "../generated/unicode151.js";
|
|
5
|
+
import { toASCII, toUnicode } from "../vendor/tr46.js";
|
|
5
6
|
import { canonicalizeJCSV3 } from "./jcs.js";
|
|
6
7
|
import { preflightJSONV3 } from "./jsonPreflight.js";
|
|
7
8
|
import { FLOWERSEC_V3_CRYPTO_LABELS, FLOWERSEC_V3_PROFILE, wireProfileForPathV3, } from "./transportConstants.js";
|
|
@@ -671,14 +672,20 @@ function normalizeDNSOrIPv4(host) {
|
|
|
671
672
|
}
|
|
672
673
|
return parts.map((part) => String(Number(part))).join(".");
|
|
673
674
|
}
|
|
674
|
-
const
|
|
675
|
+
const options = {
|
|
675
676
|
checkHyphens: true,
|
|
676
677
|
checkBidi: true,
|
|
677
678
|
checkJoiners: true,
|
|
678
679
|
useSTD3ASCIIRules: true,
|
|
679
680
|
verifyDNSLength: true,
|
|
680
681
|
transitionalProcessing: false,
|
|
681
|
-
}
|
|
682
|
+
};
|
|
683
|
+
if (!hasOnlyUnicode151Scalars(host))
|
|
684
|
+
throw invalidCandidate("DNS label");
|
|
685
|
+
const decoded = toUnicode(host, options);
|
|
686
|
+
if (decoded.error || !hasOnlyUnicode151Scalars(decoded.domain))
|
|
687
|
+
throw invalidCandidate("DNS label");
|
|
688
|
+
const ascii = toASCII(host, options);
|
|
682
689
|
if (ascii === null || ascii.endsWith("."))
|
|
683
690
|
throw invalidCandidate("DNS label");
|
|
684
691
|
const normalized = ascii.toLowerCase();
|
|
@@ -688,6 +695,13 @@ function normalizeDNSOrIPv4(host) {
|
|
|
688
695
|
}
|
|
689
696
|
return normalized;
|
|
690
697
|
}
|
|
698
|
+
function hasOnlyUnicode151Scalars(value) {
|
|
699
|
+
for (const scalar of value) {
|
|
700
|
+
if (!unicode151Assigned(scalar.codePointAt(0)))
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
691
705
|
function requestFromValidatedArtifact(artifact, candidateSet, chosenCandidateID) {
|
|
692
706
|
const common = {
|
|
693
707
|
profile: PROFILE,
|
package/dist/v3/carrier.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { CarrierKind, OperationOptionsV3, PathKind } from "./contract.js";
|
|
|
2
2
|
export type CarrierErrorCode = "aborted" | "closed" | "reset" | "stop_sending" | "stop_sending_unavailable" | "write_closed" | "datagram_unavailable";
|
|
3
3
|
export declare class CarrierError extends Error {
|
|
4
4
|
readonly code: CarrierErrorCode;
|
|
5
|
-
readonly cause?: unknown
|
|
6
|
-
constructor(code: CarrierErrorCode, message: string, cause?: unknown
|
|
5
|
+
readonly cause?: unknown;
|
|
6
|
+
constructor(code: CarrierErrorCode, message: string, cause?: unknown);
|
|
7
7
|
}
|
|
8
8
|
export interface CarrierStreamV3 {
|
|
9
9
|
read(options?: OperationOptionsV3): Promise<Uint8Array | null>;
|