@floegence/flowersec-core 0.27.0 → 2.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 +91 -22
- package/THIRD_PARTY_NOTICES.md +141 -0
- package/dist/browser/connectSession.d.ts +13 -0
- package/dist/browser/connectSession.js +40 -0
- package/dist/browser/index.d.ts +3 -10
- package/dist/browser/index.js +2 -5
- package/dist/browser/runtimeCapability.d.ts +13 -0
- package/dist/browser/runtimeCapability.js +27 -0
- package/dist/browser/sessionRuntime.d.ts +2 -0
- package/dist/browser/sessionRuntime.js +21 -0
- package/dist/browser/webTransportClient.d.ts +8 -0
- package/dist/browser/webTransportClient.js +55 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +126 -0
- package/dist/cliSpendMarker.d.ts +1 -0
- package/dist/cliSpendMarker.js +22 -0
- package/dist/connectionController.d.ts +54 -0
- package/dist/connectionController.js +438 -0
- package/dist/connector/adapters/webSocketCandidate.d.ts +7 -0
- package/dist/connector/adapters/webSocketCandidate.js +116 -0
- package/dist/connector/adapters/webTransportCandidate.d.ts +5 -0
- package/dist/connector/adapters/webTransportCandidate.js +73 -0
- package/dist/connector/admissionCommit.d.ts +31 -0
- package/dist/connector/admissionCommit.js +239 -0
- package/dist/connector/sessionAcceptor.d.ts +16 -0
- package/dist/connector/sessionAcceptor.js +114 -0
- package/dist/connector/sessionConfig.d.ts +3 -0
- package/dist/connector/sessionConfig.js +30 -0
- package/dist/connector/sessionConnector.d.ts +45 -0
- package/dist/connector/sessionConnector.js +603 -0
- package/dist/defaults.d.ts +7 -7
- package/dist/defaults.js +7 -7
- package/dist/facade.d.ts +12 -27
- package/dist/facade.js +6 -24
- package/dist/node/connectSession.d.ts +21 -0
- package/dist/node/connectSession.js +62 -0
- package/dist/node/index.d.ts +3 -11
- package/dist/node/index.js +2 -8
- package/dist/node/runtimeCapability.d.ts +7 -0
- package/dist/node/runtimeCapability.js +10 -0
- package/dist/node/sessionRuntime.d.ts +2 -0
- package/dist/node/sessionRuntime.js +13 -0
- package/dist/node/webTransportClient.d.ts +9 -0
- package/dist/node/webTransportClient.js +56 -0
- package/dist/node/webTransportServer.d.ts +22 -0
- package/dist/node/webTransportServer.js +100 -0
- package/dist/node/wsFactory.d.ts +3 -1
- package/dist/node/wsFactory.js +4 -3
- package/dist/proxy/controllerGuard.d.ts +4 -4
- package/dist/proxy/controllerGuard.js +83 -177
- package/dist/proxy/disableUpstreamServiceWorkerRegister.d.ts +3 -1
- package/dist/proxy/disableUpstreamServiceWorkerRegister.js +19 -17
- package/dist/proxy/index.d.ts +16 -15
- package/dist/proxy/index.js +8 -14
- package/dist/proxy/integration.d.ts +23 -71
- package/dist/proxy/integration.js +37 -340
- package/dist/proxy/registerServiceWorker.d.ts +1 -10
- package/dist/proxy/registerServiceWorker.js +43 -105
- package/dist/proxy/runtime.d.ts +3 -63
- package/dist/proxy/runtime.js +349 -462
- package/dist/proxy/scope.d.ts +6 -0
- package/dist/proxy/scope.js +131 -0
- package/dist/proxy/serviceWorker.d.ts +5 -16
- package/dist/proxy/serviceWorker.js +230 -617
- package/dist/proxy/stream.d.ts +9 -0
- package/dist/proxy/stream.js +40 -0
- package/dist/proxy/types.d.ts +78 -30
- package/dist/proxy/windowBridge.d.ts +61 -0
- package/dist/proxy/windowBridge.js +344 -0
- package/dist/proxy/wsPatch.d.ts +4 -14
- package/dist/proxy/wsPatch.js +173 -268
- package/dist/public/artifact.d.ts +11 -0
- package/dist/public/artifact.js +44 -0
- package/dist/public/artifactLease.d.ts +10 -0
- package/dist/public/artifactLease.js +48 -0
- package/dist/public/connectError.d.ts +6 -0
- package/dist/public/connectError.js +9 -0
- package/dist/public/contract.d.ts +83 -0
- package/dist/public/contract.js +17 -0
- package/dist/public/streamMetadata.d.ts +10 -0
- package/dist/public/streamMetadata.js +40 -0
- package/dist/rpc/caller.d.ts +1 -1
- package/dist/rpc/client.d.ts +1 -4
- package/dist/rpc/client.js +0 -21
- package/dist/rpc/rpcProxy.d.ts +1 -1
- package/dist/rpc/server.d.ts +1 -1
- package/dist/rpc/validate.d.ts +1 -1
- package/dist/rpc/wire.d.ts +15 -0
- package/dist/runtime/errors.d.ts +6 -0
- package/dist/runtime/errors.js +10 -0
- package/dist/transport/webSocketAdapter.d.ts +24 -0
- package/dist/transport/webSocketAdapter.js +234 -0
- package/dist/transport/webTransportAdapter.d.ts +27 -0
- package/dist/transport/webTransportAdapter.js +519 -0
- package/dist/utils/errors.d.ts +2 -20
- package/dist/utils/errors.js +73 -20
- package/dist/v2/admissionError.d.ts +4 -0
- package/dist/v2/admissionError.js +8 -0
- package/dist/v2/artifact.d.ts +128 -0
- package/dist/v2/artifact.js +1126 -0
- package/dist/v2/artifactLease.d.ts +1 -0
- package/dist/v2/artifactLease.js +7 -0
- package/dist/v2/capability.d.ts +29 -0
- package/dist/v2/capability.js +190 -0
- package/dist/v2/carrier.d.ts +79 -0
- package/dist/v2/carrier.js +405 -0
- package/dist/v2/contract.d.ts +37 -0
- package/dist/v2/contract.js +1 -0
- package/dist/v2/handshake.d.ts +80 -0
- package/dist/v2/handshake.js +470 -0
- package/dist/v2/opaqueArtifact.d.ts +1 -0
- package/dist/v2/opaqueArtifact.js +2 -0
- package/dist/v2/protocol.d.ts +99 -0
- package/dist/v2/protocol.js +739 -0
- package/dist/v2/publicSession.d.ts +1 -0
- package/dist/v2/publicSession.js +179 -0
- package/dist/v2/retryDisposition.d.ts +16 -0
- package/dist/v2/retryDisposition.js +30 -0
- package/dist/v2/session.d.ts +277 -0
- package/dist/v2/session.js +1879 -0
- package/dist/v2/streamLifetimeLedger.d.ts +31 -0
- package/dist/v2/streamLifetimeLedger.js +131 -0
- package/dist/v2/streamMetadata.d.ts +1 -0
- package/dist/v2/streamMetadata.js +7 -0
- package/dist/v2/unreliableMessage.d.ts +43 -0
- package/dist/v2/unreliableMessage.js +252 -0
- package/dist/vendor/tr46.d.ts +10 -0
- package/dist/vendor/tr46.js +501 -0
- package/dist/ws-client/binaryTransport.d.ts +0 -3
- package/dist/ws-client/binaryTransport.js +15 -39
- package/dist/yamux/errors.d.ts +0 -4
- package/dist/yamux/errors.js +0 -9
- package/dist/yamux/session.d.ts +0 -5
- package/dist/yamux/session.js +4 -70
- package/dist/yamux/stream.d.ts +1 -0
- package/dist/yamux/stream.js +4 -0
- package/package.json +29 -81
- package/sbom/cyclonedx.json +2764 -0
- package/sbom/spdx.json +1947 -0
- package/YAMUX_ALIGNMENT.md +0 -127
- package/dist/_examples/flowersec/demo/v1.facade.gen.d.ts +0 -12
- package/dist/_examples/flowersec/demo/v1.facade.gen.js +0 -15
- package/dist/_examples/flowersec/demo/v1.gen.d.ts +0 -16
- package/dist/_examples/flowersec/demo/v1.gen.js +0 -86
- package/dist/_examples/flowersec/demo/v1.rpc.gen.d.ts +0 -11
- package/dist/_examples/flowersec/demo/v1.rpc.gen.js +0 -22
- package/dist/browser/connect.d.ts +0 -13
- package/dist/browser/connect.js +0 -31
- package/dist/browser/reconnectConfig.d.ts +0 -15
- package/dist/browser/reconnectConfig.js +0 -20
- package/dist/client-connect/common.d.ts +0 -26
- package/dist/client-connect/common.js +0 -167
- package/dist/client-connect/connectCore.d.ts +0 -61
- package/dist/client-connect/connectCore.js +0 -572
- package/dist/client-connect/contract.d.ts +0 -8
- package/dist/client-connect/contract.js +0 -51
- package/dist/client-connect/termination.d.ts +0 -6
- package/dist/client-connect/termination.js +0 -7
- package/dist/client-connect/transportSecurity.d.ts +0 -27
- package/dist/client-connect/transportSecurity.js +0 -199
- package/dist/client-connect/tunnelAttachCloseReason.d.ts +0 -3
- package/dist/client-connect/tunnelAttachCloseReason.js +0 -23
- package/dist/client.d.ts +0 -23
- package/dist/connect/artifact.d.ts +0 -36
- package/dist/connect/artifact.js +0 -213
- package/dist/connect/resolveArtifact.d.ts +0 -22
- package/dist/connect/resolveArtifact.js +0 -87
- package/dist/controlplane/channelInit.d.ts +0 -27
- package/dist/controlplane/channelInit.js +0 -116
- package/dist/controlplane/http.d.ts +0 -16
- package/dist/controlplane/http.js +0 -59
- package/dist/controlplane/index.d.ts +0 -6
- package/dist/controlplane/index.js +0 -5
- package/dist/controlplane/issuer.d.ts +0 -18
- package/dist/controlplane/issuer.js +0 -113
- package/dist/controlplane/request.d.ts +0 -51
- package/dist/controlplane/request.js +0 -273
- package/dist/controlplane/token.d.ts +0 -33
- package/dist/controlplane/token.js +0 -119
- package/dist/direct-client/connect.d.ts +0 -9
- package/dist/direct-client/connect.js +0 -90
- package/dist/direct-client/index.d.ts +0 -1
- package/dist/direct-client/index.js +0 -1
- package/dist/e2ee/constants.d.ts +0 -9
- package/dist/e2ee/constants.js +0 -18
- package/dist/e2ee/errors.d.ts +0 -5
- package/dist/e2ee/errors.js +0 -8
- package/dist/e2ee/framing.d.ts +0 -12
- package/dist/e2ee/framing.js +0 -57
- package/dist/e2ee/handshake.d.ts +0 -88
- package/dist/e2ee/handshake.js +0 -353
- package/dist/e2ee/index.d.ts +0 -7
- package/dist/e2ee/index.js +0 -7
- package/dist/e2ee/kdf.d.ts +0 -15
- package/dist/e2ee/kdf.js +0 -39
- package/dist/e2ee/record.d.ts +0 -11
- package/dist/e2ee/record.js +0 -80
- package/dist/e2ee/secureChannel.d.ts +0 -93
- package/dist/e2ee/secureChannel.js +0 -342
- package/dist/e2ee/transcript.d.ts +0 -23
- package/dist/e2ee/transcript.js +0 -31
- package/dist/endpoint/index.d.ts +0 -84
- package/dist/endpoint/index.js +0 -557
- package/dist/endpoint/node.d.ts +0 -9
- package/dist/endpoint/node.js +0 -51
- package/dist/gen/flowersec/controlplane/v1.gen.d.ts +0 -36
- package/dist/gen/flowersec/controlplane/v1.gen.js +0 -135
- package/dist/gen/flowersec/direct/v1.gen.d.ts +0 -21
- package/dist/gen/flowersec/direct/v1.gen.js +0 -101
- package/dist/gen/flowersec/e2ee/v1.gen.d.ts +0 -68
- package/dist/gen/flowersec/e2ee/v1.gen.js +0 -194
- package/dist/gen/flowersec/rpc/v1.gen.d.ts +0 -30
- package/dist/gen/flowersec/rpc/v1.gen.js +0 -107
- package/dist/gen/flowersec/tunnel/v1.gen.d.ts +0 -23
- package/dist/gen/flowersec/tunnel/v1.gen.js +0 -104
- package/dist/index.d.ts +0 -22
- package/dist/index.js +0 -22
- package/dist/node/connect.d.ts +0 -10
- package/dist/node/connect.js +0 -29
- package/dist/node/reconnectConfig.d.ts +0 -16
- package/dist/node/reconnectConfig.js +0 -20
- package/dist/observability/index.d.ts +0 -1
- package/dist/observability/index.js +0 -1
- package/dist/observability/observer.d.ts +0 -52
- package/dist/observability/observer.js +0 -314
- package/dist/proxy/appWindow.d.ts +0 -37
- package/dist/proxy/appWindow.js +0 -273
- package/dist/proxy/bootstrap.d.ts +0 -35
- package/dist/proxy/bootstrap.js +0 -119
- package/dist/proxy/constants.d.ts +0 -7
- package/dist/proxy/constants.js +0 -8
- package/dist/proxy/controllerWindow.d.ts +0 -12
- package/dist/proxy/controllerWindow.js +0 -384
- package/dist/proxy/cookieJar.d.ts +0 -7
- package/dist/proxy/cookieJar.js +0 -136
- package/dist/proxy/headerPolicy.d.ts +0 -14
- package/dist/proxy/headerPolicy.js +0 -134
- package/dist/proxy/portStream.d.ts +0 -5
- package/dist/proxy/portStream.js +0 -256
- package/dist/proxy/preset.d.ts +0 -29
- package/dist/proxy/preset.js +0 -111
- package/dist/proxy/runtimeScope.d.ts +0 -57
- package/dist/proxy/runtimeScope.js +0 -218
- package/dist/proxy/server.d.ts +0 -28
- package/dist/proxy/server.js +0 -833
- package/dist/proxy/windowBridgeProtocol.d.ts +0 -65
- package/dist/proxy/windowBridgeProtocol.js +0 -11
- package/dist/reconnect/artifactControlplane.d.ts +0 -16
- package/dist/reconnect/artifactControlplane.js +0 -35
- package/dist/reconnect/index.d.ts +0 -36
- package/dist/reconnect/index.js +0 -388
- package/dist/rpc-proxy/index.d.ts +0 -1
- package/dist/rpc-proxy/index.js +0 -1
- package/dist/rpc-proxy/rpcProxy.d.ts +0 -1
- package/dist/rpc-proxy/rpcProxy.js +0 -1
- package/dist/streamhello/index.d.ts +0 -1
- package/dist/streamhello/index.js +0 -1
- package/dist/streamhello/streamHello.d.ts +0 -3
- package/dist/streamhello/streamHello.js +0 -13
- package/dist/streamio/index.d.ts +0 -32
- package/dist/streamio/index.js +0 -87
- package/dist/tunnel-client/connect.d.ts +0 -9
- package/dist/tunnel-client/connect.js +0 -147
- package/dist/tunnel-client/index.d.ts +0 -1
- package/dist/tunnel-client/index.js +0 -1
- package/dist/ws/index.d.ts +0 -1
- package/dist/ws/index.js +0 -1
- /package/dist/{client.js → rpc/wire.js} +0 -0
package/dist/endpoint/index.js
DELETED
|
@@ -1,557 +0,0 @@
|
|
|
1
|
-
import { Role as ControlRole, assertChannelInitGrant } from "../gen/flowersec/controlplane/v1.gen.js";
|
|
2
|
-
import { Role as TunnelRole } from "../gen/flowersec/tunnel/v1.gen.js";
|
|
3
|
-
import { withAbortAndTimeout } from "../client-connect/common.js";
|
|
4
|
-
import { assertTunnelGrantContract, assertValidPSK, prepareChannelId } from "../client-connect/contract.js";
|
|
5
|
-
import { enforceTransportSecurity } from "../client-connect/transportSecurity.js";
|
|
6
|
-
import { SDK_DEFAULTS } from "../defaults.js";
|
|
7
|
-
import { serverHandshake, ServerHandshakeCache } from "../e2ee/handshake.js";
|
|
8
|
-
import { decodeHandshakeFrame } from "../e2ee/framing.js";
|
|
9
|
-
import { HANDSHAKE_TYPE_INIT, PROTOCOL_VERSION } from "../e2ee/constants.js";
|
|
10
|
-
import { readStreamHello, writeStreamHello } from "../streamhello/streamHello.js";
|
|
11
|
-
import { ByteReader } from "../yamux/byteReader.js";
|
|
12
|
-
import { isYamuxPingTimeoutError } from "../yamux/errors.js";
|
|
13
|
-
import { YamuxSession } from "../yamux/session.js";
|
|
14
|
-
import { RpcServer } from "../rpc/server.js";
|
|
15
|
-
import { base64urlDecode, base64urlEncode } from "../utils/base64url.js";
|
|
16
|
-
import { AbortError, FlowersecError, TimeoutError, throwIfAborted } from "../utils/errors.js";
|
|
17
|
-
import { WebSocketBinaryTransport } from "../ws-client/binaryTransport.js";
|
|
18
|
-
export class Session {
|
|
19
|
-
secure;
|
|
20
|
-
mux;
|
|
21
|
-
path;
|
|
22
|
-
endpointInstanceId;
|
|
23
|
-
streams = [];
|
|
24
|
-
waiters = [];
|
|
25
|
-
terminalError;
|
|
26
|
-
constructor(path, secure, mux, endpointInstanceId) {
|
|
27
|
-
this.secure = secure;
|
|
28
|
-
this.mux = mux;
|
|
29
|
-
this.path = path;
|
|
30
|
-
this.endpointInstanceId = endpointInstanceId;
|
|
31
|
-
}
|
|
32
|
-
static create(path, secure, options = {}) {
|
|
33
|
-
let session;
|
|
34
|
-
const mux = new YamuxSession({
|
|
35
|
-
read: () => secure.read(),
|
|
36
|
-
write: (bytes) => secure.write(bytes),
|
|
37
|
-
close: () => secure.close(),
|
|
38
|
-
}, {
|
|
39
|
-
client: false,
|
|
40
|
-
...(options.yamuxLimits === undefined ? {} : { limits: options.yamuxLimits }),
|
|
41
|
-
onIncomingStream: (stream) => session.pushStream(stream),
|
|
42
|
-
onTerminal: (error) => session.fail(error),
|
|
43
|
-
});
|
|
44
|
-
session = new Session(path, secure, mux, options.endpointInstanceId);
|
|
45
|
-
return session;
|
|
46
|
-
}
|
|
47
|
-
async openStream(kind, options = {}) {
|
|
48
|
-
const streamKind = normalizeStreamKind(kind, this.path);
|
|
49
|
-
const stream = await this.mux.openStream(options);
|
|
50
|
-
try {
|
|
51
|
-
await writeStreamHello((bytes) => stream.write(bytes), streamKind);
|
|
52
|
-
return stream;
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
await stream.reset(asError(error));
|
|
56
|
-
throw new FlowersecError({ path: this.path, stage: "rpc", code: "stream_hello_failed", message: "failed to write stream hello", cause: error });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
async acceptStream(options = {}) {
|
|
60
|
-
const stream = await this.acceptRawStream(options.signal);
|
|
61
|
-
try {
|
|
62
|
-
const reader = new ByteReader(() => stream.read());
|
|
63
|
-
const hello = await readStreamHello((length) => reader.readExactly(length));
|
|
64
|
-
return { kind: hello.kind, stream };
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
await stream.reset(asError(error));
|
|
68
|
-
throw new FlowersecError({ path: this.path, stage: "rpc", code: "stream_hello_failed", message: "failed to read stream hello", cause: error });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
async serveRPC(router, options = {}) {
|
|
72
|
-
while (true) {
|
|
73
|
-
const accepted = await this.acceptStream(options.signal === undefined ? {} : { signal: options.signal });
|
|
74
|
-
if (accepted.kind !== "rpc") {
|
|
75
|
-
await accepted.stream.reset(new Error(`unexpected stream kind ${accepted.kind}`));
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
const reader = new ByteReader(() => accepted.stream.read());
|
|
79
|
-
const server = new RpcServer({
|
|
80
|
-
readExactly: (length) => reader.readExactly(length),
|
|
81
|
-
write: (bytes) => accepted.stream.write(bytes),
|
|
82
|
-
close: (error) => { void accepted.stream.reset(asError(error)); },
|
|
83
|
-
}, options, router);
|
|
84
|
-
await server.serve(options.signal);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
async probeLiveness(timeoutMs = SDK_DEFAULTS.transport.handshakeTimeoutMs) {
|
|
89
|
-
try {
|
|
90
|
-
return await this.mux.probeLiveness(timeoutMs);
|
|
91
|
-
}
|
|
92
|
-
catch (error) {
|
|
93
|
-
throw new FlowersecError({
|
|
94
|
-
path: this.path,
|
|
95
|
-
stage: "yamux",
|
|
96
|
-
code: isYamuxPingTimeoutError(error) ? "timeout" : "ping_failed",
|
|
97
|
-
message: "endpoint liveness probe failed",
|
|
98
|
-
cause: error,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async rekey() {
|
|
103
|
-
try {
|
|
104
|
-
await this.secure.rekeyNow();
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
throw new FlowersecError({ path: this.path, stage: "secure", code: "rekey_failed", message: "endpoint rekey failed", cause: error });
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
close() {
|
|
111
|
-
this.fail(new Error("endpoint session closed"));
|
|
112
|
-
this.mux.close();
|
|
113
|
-
this.secure.close();
|
|
114
|
-
}
|
|
115
|
-
pushStream(stream) {
|
|
116
|
-
const waiter = this.waiters.shift();
|
|
117
|
-
if (waiter == null) {
|
|
118
|
-
this.streams.push(stream);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
cleanupWaiter(waiter);
|
|
122
|
-
waiter.resolve(stream);
|
|
123
|
-
}
|
|
124
|
-
acceptRawStream(signal) {
|
|
125
|
-
if (signal?.aborted)
|
|
126
|
-
return Promise.reject(new AbortError("accept stream aborted"));
|
|
127
|
-
if (this.terminalError != null)
|
|
128
|
-
return Promise.reject(this.terminalError);
|
|
129
|
-
const stream = this.streams.shift();
|
|
130
|
-
if (stream != null)
|
|
131
|
-
return Promise.resolve(stream);
|
|
132
|
-
return new Promise((resolve, reject) => {
|
|
133
|
-
const waiter = { resolve, reject, ...(signal === undefined ? {} : { signal }) };
|
|
134
|
-
waiter.onAbort = () => {
|
|
135
|
-
const index = this.waiters.indexOf(waiter);
|
|
136
|
-
if (index >= 0)
|
|
137
|
-
this.waiters.splice(index, 1);
|
|
138
|
-
cleanupWaiter(waiter);
|
|
139
|
-
reject(new AbortError("accept stream aborted"));
|
|
140
|
-
};
|
|
141
|
-
signal?.addEventListener("abort", waiter.onAbort, { once: true });
|
|
142
|
-
this.waiters.push(waiter);
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
fail(error) {
|
|
146
|
-
if (this.terminalError != null)
|
|
147
|
-
return;
|
|
148
|
-
this.terminalError = error;
|
|
149
|
-
for (const waiter of this.waiters.splice(0)) {
|
|
150
|
-
cleanupWaiter(waiter);
|
|
151
|
-
waiter.reject(error);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
export async function acceptDirect(websocket, handshake, options = {}) {
|
|
156
|
-
const handshakeTimeoutMs = options.handshakeTimeoutMs ?? SDK_DEFAULTS.transport.handshakeTimeoutMs;
|
|
157
|
-
if (!Number.isFinite(handshakeTimeoutMs) || handshakeTimeoutMs < 0) {
|
|
158
|
-
throw new FlowersecError({
|
|
159
|
-
path: "direct",
|
|
160
|
-
stage: "validate",
|
|
161
|
-
code: "invalid_option",
|
|
162
|
-
message: "handshakeTimeoutMs must be a non-negative number",
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
await enforceIncomingDirectTransport(options);
|
|
166
|
-
const deadline = createHandshakeDeadline(handshakeTimeoutMs);
|
|
167
|
-
const transport = new WebSocketBinaryTransport(websocket, webSocketTransportOptions(options));
|
|
168
|
-
return await establishSession("direct", transport, handshake, options, undefined, deadline);
|
|
169
|
-
}
|
|
170
|
-
export async function acceptDirectResolved(websocket, resolver, options = {}) {
|
|
171
|
-
const handshakeTimeoutMs = options.handshakeTimeoutMs ?? SDK_DEFAULTS.transport.handshakeTimeoutMs;
|
|
172
|
-
if (!Number.isFinite(handshakeTimeoutMs) || handshakeTimeoutMs < 0) {
|
|
173
|
-
throw new FlowersecError({
|
|
174
|
-
path: "direct",
|
|
175
|
-
stage: "validate",
|
|
176
|
-
code: "invalid_option",
|
|
177
|
-
message: "handshakeTimeoutMs must be a non-negative number",
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
await enforceIncomingDirectTransport(options);
|
|
181
|
-
const deadline = createHandshakeDeadline(handshakeTimeoutMs);
|
|
182
|
-
const transport = new WebSocketBinaryTransport(websocket, webSocketTransportOptions(options));
|
|
183
|
-
let first;
|
|
184
|
-
try {
|
|
185
|
-
first = await runHandshakeStep(deadline, options.signal, () => transport.readBinary({
|
|
186
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
187
|
-
timeoutMs: remainingHandshakeTimeoutMs(deadline),
|
|
188
|
-
}));
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
transport.close();
|
|
192
|
-
throw endpointHandshakeError("direct", error, "failed to read handshake init");
|
|
193
|
-
}
|
|
194
|
-
let init;
|
|
195
|
-
let channelId;
|
|
196
|
-
try {
|
|
197
|
-
const decoded = decodeHandshakeFrame(first, options.maxHandshakePayload ?? SDK_DEFAULTS.e2ee.maxHandshakePayloadBytes);
|
|
198
|
-
if (decoded.handshakeType !== HANDSHAKE_TYPE_INIT)
|
|
199
|
-
throw new Error("expected handshake init");
|
|
200
|
-
init = JSON.parse(new TextDecoder().decode(decoded.payloadJsonUtf8));
|
|
201
|
-
if (init.version !== PROTOCOL_VERSION || init.role !== 1 || (init.suite !== 1 && init.suite !== 2))
|
|
202
|
-
throw new Error("invalid handshake init");
|
|
203
|
-
channelId = prepareChannelId(init.channel_id, "direct");
|
|
204
|
-
if (channelId !== init.channel_id) {
|
|
205
|
-
throw new FlowersecError({
|
|
206
|
-
path: "direct",
|
|
207
|
-
stage: "validate",
|
|
208
|
-
code: "invalid_input",
|
|
209
|
-
message: "channel_id must not have leading or trailing whitespace",
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
catch (error) {
|
|
214
|
-
transport.close();
|
|
215
|
-
if (error instanceof FlowersecError)
|
|
216
|
-
throw error;
|
|
217
|
-
throw new FlowersecError({ path: "direct", stage: "handshake", code: "handshake_failed", message: "invalid handshake init", cause: error });
|
|
218
|
-
}
|
|
219
|
-
let credential;
|
|
220
|
-
try {
|
|
221
|
-
credential = await runHandshakeStep(deadline, options.signal, () => resolver({
|
|
222
|
-
channelId,
|
|
223
|
-
version: init.version,
|
|
224
|
-
suite: init.suite,
|
|
225
|
-
clientFeatures: init.client_features >>> 0,
|
|
226
|
-
}));
|
|
227
|
-
}
|
|
228
|
-
catch (error) {
|
|
229
|
-
transport.close();
|
|
230
|
-
const interrupted = endpointHandshakeInterruption("direct", error);
|
|
231
|
-
if (interrupted != null)
|
|
232
|
-
throw interrupted;
|
|
233
|
-
throw new FlowersecError({ path: "direct", stage: "validate", code: "resolve_failed", message: "credential resolution failed", cause: error });
|
|
234
|
-
}
|
|
235
|
-
const replay = new PrefetchedTransport(transport, first);
|
|
236
|
-
return await establishSession("direct", replay, {
|
|
237
|
-
channelId,
|
|
238
|
-
suite: init.suite,
|
|
239
|
-
...credential,
|
|
240
|
-
}, options, undefined, deadline);
|
|
241
|
-
}
|
|
242
|
-
export async function connectTunnel(grantInput, options) {
|
|
243
|
-
let grant;
|
|
244
|
-
try {
|
|
245
|
-
grant = assertChannelInitGrant(unwrapServerGrant(grantInput));
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "invalid_input", message: "invalid ChannelInitGrant", cause: error });
|
|
249
|
-
}
|
|
250
|
-
assertTunnelGrantContract(grant, ControlRole.Role_server);
|
|
251
|
-
const channelId = prepareChannelId(grant.channel_id, "tunnel");
|
|
252
|
-
const tunnelUrl = grant.tunnel_url.trim();
|
|
253
|
-
if (tunnelUrl === "")
|
|
254
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "missing_tunnel_url", message: "missing tunnel_url" });
|
|
255
|
-
if (grant.token.trim() === "")
|
|
256
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "missing_token", message: "missing token" });
|
|
257
|
-
if (grant.channel_init_expire_at_unix_s <= 0)
|
|
258
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "missing_init_exp", message: "missing channel init expiry" });
|
|
259
|
-
const origin = options.origin.trim();
|
|
260
|
-
if (origin === "")
|
|
261
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "missing_origin", message: "missing origin" });
|
|
262
|
-
const connectTimeoutMs = options.connectTimeoutMs ?? SDK_DEFAULTS.transport.connectTimeoutMs;
|
|
263
|
-
if (!Number.isFinite(connectTimeoutMs) || connectTimeoutMs < 0) {
|
|
264
|
-
throw new FlowersecError({
|
|
265
|
-
path: "tunnel",
|
|
266
|
-
stage: "validate",
|
|
267
|
-
code: "invalid_option",
|
|
268
|
-
message: "connectTimeoutMs must be a non-negative number",
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
const handshakeTimeoutMs = options.handshakeTimeoutMs ?? SDK_DEFAULTS.transport.handshakeTimeoutMs;
|
|
272
|
-
if (!Number.isFinite(handshakeTimeoutMs) || handshakeTimeoutMs < 0) {
|
|
273
|
-
throw new FlowersecError({
|
|
274
|
-
path: "tunnel",
|
|
275
|
-
stage: "validate",
|
|
276
|
-
code: "invalid_option",
|
|
277
|
-
message: "handshakeTimeoutMs must be a non-negative number",
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
const psk = assertValidPSK(grant.e2ee_psk_b64u, "tunnel");
|
|
281
|
-
await enforceTransportSecurity({ rawUrl: tunnelUrl, path: "tunnel", ...(options.transportSecurityPolicy === undefined ? {} : { policy: options.transportSecurityPolicy }) });
|
|
282
|
-
const endpointInstanceId = normalizeEndpointInstanceId(options.endpointInstanceId);
|
|
283
|
-
let transport;
|
|
284
|
-
try {
|
|
285
|
-
throwIfAborted(options.signal, "connect aborted");
|
|
286
|
-
const websocket = options.wsFactory(tunnelUrl, origin);
|
|
287
|
-
transport = new WebSocketBinaryTransport(websocket, webSocketTransportOptions(options));
|
|
288
|
-
await waitForOpen(websocket, connectTimeoutMs, options.signal);
|
|
289
|
-
throwIfAborted(options.signal, "connect aborted");
|
|
290
|
-
const attach = {
|
|
291
|
-
v: 1,
|
|
292
|
-
channel_id: channelId,
|
|
293
|
-
role: TunnelRole.Role_server,
|
|
294
|
-
token: grant.token.trim(),
|
|
295
|
-
endpoint_instance_id: endpointInstanceId,
|
|
296
|
-
};
|
|
297
|
-
websocket.send(JSON.stringify(attach));
|
|
298
|
-
return await establishSession("tunnel", transport, {
|
|
299
|
-
channelId,
|
|
300
|
-
suite: grant.default_suite,
|
|
301
|
-
psk,
|
|
302
|
-
initExpireAtUnixS: grant.channel_init_expire_at_unix_s,
|
|
303
|
-
}, options, endpointInstanceId);
|
|
304
|
-
}
|
|
305
|
-
catch (error) {
|
|
306
|
-
transport?.close();
|
|
307
|
-
if (error instanceof FlowersecError)
|
|
308
|
-
throw error;
|
|
309
|
-
if (error instanceof TimeoutError) {
|
|
310
|
-
throw new FlowersecError({ path: "tunnel", stage: "connect", code: "timeout", message: "endpoint tunnel connect timed out", cause: error });
|
|
311
|
-
}
|
|
312
|
-
if (error instanceof AbortError) {
|
|
313
|
-
throw new FlowersecError({ path: "tunnel", stage: "connect", code: "canceled", message: "endpoint tunnel connect canceled", cause: error });
|
|
314
|
-
}
|
|
315
|
-
throw new FlowersecError({ path: "tunnel", stage: "connect", code: "dial_failed", message: "endpoint tunnel connect failed", cause: error });
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
async function establishSession(path, transport, handshake, options, endpointInstanceId, deadline) {
|
|
319
|
-
let psk;
|
|
320
|
-
try {
|
|
321
|
-
psk = normalizePSK(handshake.psk, path);
|
|
322
|
-
}
|
|
323
|
-
catch (error) {
|
|
324
|
-
transport.close();
|
|
325
|
-
throw error;
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
const startHandshake = () => serverHandshake(transport, options.handshakeCache ?? new ServerHandshakeCache(), {
|
|
329
|
-
channelId: prepareChannelId(handshake.channelId, path),
|
|
330
|
-
suite: handshake.suite,
|
|
331
|
-
psk,
|
|
332
|
-
serverFeatures: options.serverFeatures ?? 0,
|
|
333
|
-
initExpireAtUnixS: handshake.initExpireAtUnixS,
|
|
334
|
-
clockSkewSeconds: Math.ceil((options.handshakeClockSkewMs ?? SDK_DEFAULTS.transport.handshakeClockSkewMs) / 1000),
|
|
335
|
-
maxHandshakePayload: options.maxHandshakePayload ?? SDK_DEFAULTS.e2ee.maxHandshakePayloadBytes,
|
|
336
|
-
maxRecordBytes: options.maxRecordBytes ?? SDK_DEFAULTS.e2ee.maxRecordBytes,
|
|
337
|
-
outboundRecordChunkBytes: options.outboundRecordChunkBytes ?? SDK_DEFAULTS.e2ee.outboundRecordChunkBytes,
|
|
338
|
-
maxBufferedBytes: options.maxBufferedBytes ?? SDK_DEFAULTS.e2ee.maxInboundBufferedBytes,
|
|
339
|
-
maxOutboundBufferedBytes: options.maxOutboundBufferedBytes ?? SDK_DEFAULTS.e2ee.maxOutboundBufferedBytes,
|
|
340
|
-
timeoutMs: deadline == null
|
|
341
|
-
? options.handshakeTimeoutMs ?? SDK_DEFAULTS.transport.handshakeTimeoutMs
|
|
342
|
-
: remainingHandshakeTimeoutMs(deadline),
|
|
343
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
344
|
-
});
|
|
345
|
-
const secure = deadline == null
|
|
346
|
-
? await startHandshake()
|
|
347
|
-
: await runHandshakeStep(deadline, options.signal, startHandshake);
|
|
348
|
-
try {
|
|
349
|
-
if (handshake.commitAuthenticated != null) {
|
|
350
|
-
if (deadline == null) {
|
|
351
|
-
await handshake.commitAuthenticated();
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
await runHandshakeStep(deadline, options.signal, handshake.commitAuthenticated);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
catch (error) {
|
|
359
|
-
secure.close();
|
|
360
|
-
const interrupted = endpointHandshakeInterruption(path, error);
|
|
361
|
-
if (interrupted != null)
|
|
362
|
-
throw interrupted;
|
|
363
|
-
throw new FlowersecError({ path, stage: "handshake", code: "credential_commit_failed", message: "credential commit failed", cause: error });
|
|
364
|
-
}
|
|
365
|
-
try {
|
|
366
|
-
throwIfAborted(options.signal, "handshake canceled");
|
|
367
|
-
if (deadline != null)
|
|
368
|
-
remainingHandshakeTimeoutMs(deadline);
|
|
369
|
-
return Session.create(path, secure, {
|
|
370
|
-
...(options.yamuxLimits === undefined ? {} : { yamuxLimits: options.yamuxLimits }),
|
|
371
|
-
...(endpointInstanceId === undefined ? {} : { endpointInstanceId }),
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
catch (error) {
|
|
375
|
-
secure.close();
|
|
376
|
-
throw error;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
transport.close();
|
|
381
|
-
if (error instanceof FlowersecError)
|
|
382
|
-
throw error;
|
|
383
|
-
const interrupted = endpointHandshakeInterruption(path, error);
|
|
384
|
-
if (interrupted != null)
|
|
385
|
-
throw interrupted;
|
|
386
|
-
throw new FlowersecError({ path, stage: "handshake", code: "handshake_failed", message: "endpoint handshake failed", cause: error });
|
|
387
|
-
}
|
|
388
|
-
finally {
|
|
389
|
-
psk.fill(0);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
class PrefetchedTransport {
|
|
393
|
-
inner;
|
|
394
|
-
first;
|
|
395
|
-
constructor(inner, first) {
|
|
396
|
-
this.inner = inner;
|
|
397
|
-
this.first = first;
|
|
398
|
-
}
|
|
399
|
-
readBinary(options) {
|
|
400
|
-
if (this.first != null) {
|
|
401
|
-
const first = this.first;
|
|
402
|
-
this.first = undefined;
|
|
403
|
-
return Promise.resolve(first);
|
|
404
|
-
}
|
|
405
|
-
return this.inner.readBinary(options);
|
|
406
|
-
}
|
|
407
|
-
writeBinary(frame, options) {
|
|
408
|
-
return this.inner.writeBinary(frame, options);
|
|
409
|
-
}
|
|
410
|
-
close() {
|
|
411
|
-
this.inner.close();
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
function normalizePSK(input, path) {
|
|
415
|
-
try {
|
|
416
|
-
const psk = typeof input === "string" ? base64urlDecode(input.trim()) : input.slice();
|
|
417
|
-
if (psk.length !== 32)
|
|
418
|
-
throw new Error("psk must be 32 bytes");
|
|
419
|
-
return psk;
|
|
420
|
-
}
|
|
421
|
-
catch (error) {
|
|
422
|
-
throw new FlowersecError({ path, stage: "validate", code: "invalid_psk", message: "invalid psk", cause: error });
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
function normalizeEndpointInstanceId(input) {
|
|
426
|
-
const value = input ?? randomEndpointInstanceId();
|
|
427
|
-
try {
|
|
428
|
-
const bytes = base64urlDecode(value);
|
|
429
|
-
if (bytes.length < 16 || bytes.length > 32)
|
|
430
|
-
throw new Error("endpoint instance ID must decode to 16..32 bytes");
|
|
431
|
-
}
|
|
432
|
-
catch (error) {
|
|
433
|
-
throw new FlowersecError({ path: "tunnel", stage: "validate", code: "invalid_endpoint_instance_id", message: "invalid endpoint instance ID", cause: error });
|
|
434
|
-
}
|
|
435
|
-
return value;
|
|
436
|
-
}
|
|
437
|
-
function randomEndpointInstanceId() {
|
|
438
|
-
const bytes = new Uint8Array(24);
|
|
439
|
-
crypto.getRandomValues(bytes);
|
|
440
|
-
return base64urlEncode(bytes);
|
|
441
|
-
}
|
|
442
|
-
function normalizeStreamKind(kind, path) {
|
|
443
|
-
const value = kind.trim();
|
|
444
|
-
if (value === "")
|
|
445
|
-
throw new FlowersecError({ path, stage: "rpc", code: "missing_stream_kind", message: "missing stream kind" });
|
|
446
|
-
return value;
|
|
447
|
-
}
|
|
448
|
-
function unwrapServerGrant(input) {
|
|
449
|
-
if (typeof input !== "object" || input == null || Array.isArray(input))
|
|
450
|
-
return input;
|
|
451
|
-
const record = input;
|
|
452
|
-
return record["grant_server"] ?? input;
|
|
453
|
-
}
|
|
454
|
-
function webSocketTransportOptions(options) {
|
|
455
|
-
return options.webSocketLimits === undefined ? {} : { webSocketLimits: options.webSocketLimits };
|
|
456
|
-
}
|
|
457
|
-
async function enforceIncomingDirectTransport(options) {
|
|
458
|
-
const rawUrl = options.secureTransport === false ? "ws://127.0.0.1/" : "wss://127.0.0.1/";
|
|
459
|
-
await enforceTransportSecurity({ rawUrl, path: "direct", ...(options.transportSecurityPolicy === undefined ? {} : { policy: options.transportSecurityPolicy }) });
|
|
460
|
-
}
|
|
461
|
-
function waitForOpen(websocket, timeoutMs, signal) {
|
|
462
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs < 0)
|
|
463
|
-
return Promise.reject(new RangeError("connectTimeoutMs must be non-negative"));
|
|
464
|
-
try {
|
|
465
|
-
throwIfAborted(signal, "connect aborted");
|
|
466
|
-
}
|
|
467
|
-
catch (error) {
|
|
468
|
-
return Promise.reject(error);
|
|
469
|
-
}
|
|
470
|
-
if (websocket.readyState === 1)
|
|
471
|
-
return Promise.resolve();
|
|
472
|
-
if (websocket.readyState >= 2)
|
|
473
|
-
return Promise.reject(new Error("websocket closed before open"));
|
|
474
|
-
return new Promise((resolve, reject) => {
|
|
475
|
-
let settled = false;
|
|
476
|
-
let timer;
|
|
477
|
-
const cleanup = () => {
|
|
478
|
-
if (timer != null)
|
|
479
|
-
clearTimeout(timer);
|
|
480
|
-
websocket.removeEventListener("open", onOpen);
|
|
481
|
-
websocket.removeEventListener("error", onError);
|
|
482
|
-
websocket.removeEventListener("close", onClose);
|
|
483
|
-
signal?.removeEventListener("abort", onAbort);
|
|
484
|
-
};
|
|
485
|
-
const finish = (error) => {
|
|
486
|
-
if (settled)
|
|
487
|
-
return;
|
|
488
|
-
settled = true;
|
|
489
|
-
cleanup();
|
|
490
|
-
if (error == null)
|
|
491
|
-
resolve();
|
|
492
|
-
else
|
|
493
|
-
reject(error);
|
|
494
|
-
};
|
|
495
|
-
const onOpen = () => finish();
|
|
496
|
-
const onError = () => finish(new Error("websocket open failed"));
|
|
497
|
-
const onClose = () => finish(new Error("websocket closed before open"));
|
|
498
|
-
const onAbort = () => finish(new AbortError("connect aborted"));
|
|
499
|
-
websocket.addEventListener("open", onOpen);
|
|
500
|
-
websocket.addEventListener("error", onError);
|
|
501
|
-
websocket.addEventListener("close", onClose);
|
|
502
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
503
|
-
if (signal?.aborted) {
|
|
504
|
-
onAbort();
|
|
505
|
-
}
|
|
506
|
-
else if (websocket.readyState === 1) {
|
|
507
|
-
onOpen();
|
|
508
|
-
}
|
|
509
|
-
else if (websocket.readyState >= 2) {
|
|
510
|
-
onClose();
|
|
511
|
-
}
|
|
512
|
-
if (!settled && timeoutMs > 0)
|
|
513
|
-
timer = setTimeout(() => finish(new TimeoutError("websocket open timeout")), timeoutMs);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
function cleanupWaiter(waiter) {
|
|
517
|
-
if (waiter.onAbort != null)
|
|
518
|
-
waiter.signal?.removeEventListener("abort", waiter.onAbort);
|
|
519
|
-
}
|
|
520
|
-
function createHandshakeDeadline(timeoutMs) {
|
|
521
|
-
return timeoutMs > 0 ? { expiresAtMs: Date.now() + timeoutMs } : {};
|
|
522
|
-
}
|
|
523
|
-
function remainingHandshakeTimeoutMs(deadline) {
|
|
524
|
-
if (deadline.expiresAtMs === undefined)
|
|
525
|
-
return 0;
|
|
526
|
-
const remaining = deadline.expiresAtMs - Date.now();
|
|
527
|
-
if (remaining <= 0)
|
|
528
|
-
throw new TimeoutError("handshake timeout");
|
|
529
|
-
return remaining;
|
|
530
|
-
}
|
|
531
|
-
async function runHandshakeStep(deadline, signal, operation) {
|
|
532
|
-
throwIfAborted(signal, "handshake canceled");
|
|
533
|
-
const timeoutMs = remainingHandshakeTimeoutMs(deadline);
|
|
534
|
-
const result = await withAbortAndTimeout(Promise.resolve().then(operation), {
|
|
535
|
-
timeoutMs,
|
|
536
|
-
...(signal === undefined ? {} : { signal }),
|
|
537
|
-
});
|
|
538
|
-
throwIfAborted(signal, "handshake canceled");
|
|
539
|
-
remainingHandshakeTimeoutMs(deadline);
|
|
540
|
-
return result;
|
|
541
|
-
}
|
|
542
|
-
function endpointHandshakeInterruption(path, error) {
|
|
543
|
-
if (error instanceof TimeoutError) {
|
|
544
|
-
return new FlowersecError({ path, stage: "handshake", code: "timeout", message: "endpoint handshake timed out", cause: error });
|
|
545
|
-
}
|
|
546
|
-
if (error instanceof AbortError) {
|
|
547
|
-
return new FlowersecError({ path, stage: "handshake", code: "canceled", message: "endpoint handshake canceled", cause: error });
|
|
548
|
-
}
|
|
549
|
-
return undefined;
|
|
550
|
-
}
|
|
551
|
-
function endpointHandshakeError(path, error, message) {
|
|
552
|
-
return endpointHandshakeInterruption(path, error)
|
|
553
|
-
?? new FlowersecError({ path, stage: "handshake", code: "handshake_failed", message, cause: error });
|
|
554
|
-
}
|
|
555
|
-
function asError(error) {
|
|
556
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
557
|
-
}
|
package/dist/endpoint/node.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { WebSocketLike } from "../ws-client/binaryTransport.js";
|
|
2
|
-
import { type DirectAcceptOptions, type DirectCredentialResolver, type DirectHandshakeCredential, type Session, type Suite, type TunnelEndpointOptions } from "./index.js";
|
|
3
|
-
export declare function adaptNodeWebSocket(websocket: unknown): WebSocketLike;
|
|
4
|
-
export declare function acceptDirectNode(websocket: unknown, handshake: Readonly<{
|
|
5
|
-
channelId: string;
|
|
6
|
-
suite: Suite;
|
|
7
|
-
}> & DirectHandshakeCredential, options?: DirectAcceptOptions): Promise<Session>;
|
|
8
|
-
export declare function acceptDirectResolvedNode(websocket: unknown, resolver: DirectCredentialResolver, options?: DirectAcceptOptions): Promise<Session>;
|
|
9
|
-
export declare function connectTunnelEndpointNode(grant: unknown, options: Omit<TunnelEndpointOptions, "wsFactory">): Promise<Session>;
|
package/dist/endpoint/node.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { createNodeWsFactory } from "../node/wsFactory.js";
|
|
2
|
-
import { acceptDirect, acceptDirectResolved, connectTunnel, } from "./index.js";
|
|
3
|
-
export function adaptNodeWebSocket(websocket) {
|
|
4
|
-
const raw = websocket;
|
|
5
|
-
if (raw == null || typeof raw.send !== "function" || typeof raw.close !== "function") {
|
|
6
|
-
throw new TypeError("a Node WebSocket is required");
|
|
7
|
-
}
|
|
8
|
-
if (typeof raw.addEventListener === "function" && typeof raw.removeEventListener === "function") {
|
|
9
|
-
return raw;
|
|
10
|
-
}
|
|
11
|
-
const listeners = new Map();
|
|
12
|
-
return {
|
|
13
|
-
get binaryType() { return String(raw.binaryType ?? "nodebuffer"); },
|
|
14
|
-
set binaryType(value) { raw.binaryType = value; },
|
|
15
|
-
get readyState() { return Number(raw.readyState); },
|
|
16
|
-
get bufferedAmount() { return Number(raw.bufferedAmount ?? 0); },
|
|
17
|
-
send(data) { raw.send(data); },
|
|
18
|
-
close(code, reason) { raw.close(code, reason); },
|
|
19
|
-
addEventListener(type, listener) {
|
|
20
|
-
const wrapped = (...args) => {
|
|
21
|
-
if (type === "message")
|
|
22
|
-
listener({ data: args[0] });
|
|
23
|
-
else if (type === "close")
|
|
24
|
-
listener({ code: args[0], reason: args[1]?.toString?.() ?? "" });
|
|
25
|
-
else
|
|
26
|
-
listener(args[0]);
|
|
27
|
-
};
|
|
28
|
-
const byListener = listeners.get(type) ?? new Map();
|
|
29
|
-
byListener.set(listener, wrapped);
|
|
30
|
-
listeners.set(type, byListener);
|
|
31
|
-
raw.on(type, wrapped);
|
|
32
|
-
},
|
|
33
|
-
removeEventListener(type, listener) {
|
|
34
|
-
const byListener = listeners.get(type);
|
|
35
|
-
const wrapped = byListener?.get(listener);
|
|
36
|
-
if (wrapped == null)
|
|
37
|
-
return;
|
|
38
|
-
byListener.delete(listener);
|
|
39
|
-
raw.off(type, wrapped);
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
export function acceptDirectNode(websocket, handshake, options = {}) {
|
|
44
|
-
return acceptDirect(adaptNodeWebSocket(websocket), handshake, options);
|
|
45
|
-
}
|
|
46
|
-
export function acceptDirectResolvedNode(websocket, resolver, options = {}) {
|
|
47
|
-
return acceptDirectResolved(adaptNodeWebSocket(websocket), resolver, options);
|
|
48
|
-
}
|
|
49
|
-
export function connectTunnelEndpointNode(grant, options) {
|
|
50
|
-
return connectTunnel(grant, { ...options, wsFactory: createNodeWsFactory() });
|
|
51
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/** Endpoint role for tunnel attach. */
|
|
2
|
-
export declare enum Role {
|
|
3
|
-
/** Client endpoint. */
|
|
4
|
-
Role_client = 1,
|
|
5
|
-
/** Server endpoint. */
|
|
6
|
-
Role_server = 2
|
|
7
|
-
}
|
|
8
|
-
/** E2EE cipher suite identifier. */
|
|
9
|
-
export declare enum Suite {
|
|
10
|
-
/** P-256 + HKDF-SHA256 + AES-256-GCM. */
|
|
11
|
-
Suite_P256_HKDF_SHA256_AES_256_GCM = 2,
|
|
12
|
-
/** X25519 + HKDF-SHA256 + AES-256-GCM. */
|
|
13
|
-
Suite_X25519_HKDF_SHA256_AES_256_GCM = 1
|
|
14
|
-
}
|
|
15
|
-
/** Grant issued by controlplane to attach and start E2EE. */
|
|
16
|
-
export interface ChannelInitGrant {
|
|
17
|
-
/** WebSocket URL of the tunnel server. */
|
|
18
|
-
tunnel_url: string;
|
|
19
|
-
/** Channel identifier shared by both endpoints. */
|
|
20
|
-
channel_id: string;
|
|
21
|
-
/** Unix timestamp when the grant expires. */
|
|
22
|
-
channel_init_expire_at_unix_s: number;
|
|
23
|
-
/** Server idle timeout hint in seconds. */
|
|
24
|
-
idle_timeout_seconds: number;
|
|
25
|
-
/** Role for this grant (client or server). */
|
|
26
|
-
role: Role;
|
|
27
|
-
/** Signed tunnel attach token. */
|
|
28
|
-
token: string;
|
|
29
|
-
/** Base64url-encoded 32-byte PSK. */
|
|
30
|
-
e2ee_psk_b64u: string;
|
|
31
|
-
/** Allowed E2EE cipher suites. */
|
|
32
|
-
allowed_suites: Suite[];
|
|
33
|
-
/** Default E2EE cipher suite. */
|
|
34
|
-
default_suite: Suite;
|
|
35
|
-
}
|
|
36
|
-
export declare function assertChannelInitGrant(v: unknown): ChannelInitGrant;
|