@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
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export declare const TOKEN_PREFIX = "FST2";
|
|
2
|
-
export type TokenPayload = Readonly<{
|
|
3
|
-
kid: string;
|
|
4
|
-
aud: string;
|
|
5
|
-
iss?: string;
|
|
6
|
-
channel_id: string;
|
|
7
|
-
role: 1 | 2;
|
|
8
|
-
token_id: string;
|
|
9
|
-
init_exp: number;
|
|
10
|
-
idle_timeout_seconds: number;
|
|
11
|
-
iat: number;
|
|
12
|
-
exp: number;
|
|
13
|
-
}>;
|
|
14
|
-
export type ParsedToken = Readonly<{
|
|
15
|
-
payload: TokenPayload;
|
|
16
|
-
signed: Uint8Array;
|
|
17
|
-
signature: Uint8Array;
|
|
18
|
-
}>;
|
|
19
|
-
export type TokenVerifyOptions = Readonly<{
|
|
20
|
-
nowUnixS?: number;
|
|
21
|
-
audience?: string;
|
|
22
|
-
issuer?: string;
|
|
23
|
-
clockSkewMs?: number;
|
|
24
|
-
}>;
|
|
25
|
-
export type TokenKeyLookup = ReadonlyMap<string, Uint8Array> | ((kid: string) => Uint8Array | undefined);
|
|
26
|
-
export declare class TokenError extends Error {
|
|
27
|
-
readonly code: string;
|
|
28
|
-
constructor(code: string, message?: string);
|
|
29
|
-
}
|
|
30
|
-
export declare function signToken(signingSeed: Uint8Array, payload: TokenPayload): string;
|
|
31
|
-
export declare function parseToken(token: string): ParsedToken;
|
|
32
|
-
export declare function verifyToken(token: string, keys: TokenKeyLookup, options?: TokenVerifyOptions): TokenPayload;
|
|
33
|
-
export declare function equalSignedTokenPart(left: string, right: string): boolean;
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { ed25519 } from "@noble/curves/ed25519";
|
|
2
|
-
import { base64urlDecode, base64urlEncode } from "../utils/base64url.js";
|
|
3
|
-
export const TOKEN_PREFIX = "FST2";
|
|
4
|
-
export class TokenError extends Error {
|
|
5
|
-
code;
|
|
6
|
-
constructor(code, message = code) {
|
|
7
|
-
super(message);
|
|
8
|
-
this.code = code;
|
|
9
|
-
this.name = "TokenError";
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export function signToken(signingSeed, payload) {
|
|
13
|
-
if (signingSeed.length !== 32)
|
|
14
|
-
throw new TokenError("invalid_signing_key");
|
|
15
|
-
const normalized = normalizePayload(payload, true);
|
|
16
|
-
const payloadJSON = new TextEncoder().encode(JSON.stringify(normalized));
|
|
17
|
-
const signedText = `${TOKEN_PREFIX}.${base64urlEncode(payloadJSON)}`;
|
|
18
|
-
const signature = ed25519.sign(new TextEncoder().encode(signedText), signingSeed);
|
|
19
|
-
return `${signedText}.${base64urlEncode(signature)}`;
|
|
20
|
-
}
|
|
21
|
-
export function parseToken(token) {
|
|
22
|
-
const parts = token.split(".");
|
|
23
|
-
if (parts.length !== 3 || parts[0] !== TOKEN_PREFIX)
|
|
24
|
-
throw new TokenError("invalid_format");
|
|
25
|
-
try {
|
|
26
|
-
const payload = JSON.parse(new TextDecoder().decode(base64urlDecode(parts[1])));
|
|
27
|
-
return {
|
|
28
|
-
payload,
|
|
29
|
-
signed: new TextEncoder().encode(`${TOKEN_PREFIX}.${parts[1]}`),
|
|
30
|
-
signature: base64urlDecode(parts[2]),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
if (error instanceof SyntaxError)
|
|
35
|
-
throw new TokenError("invalid_json");
|
|
36
|
-
throw new TokenError("invalid_base64url");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function verifyToken(token, keys, options = {}) {
|
|
40
|
-
const parsed = parseToken(token);
|
|
41
|
-
const payload = normalizePayload(parsed.payload, false);
|
|
42
|
-
const publicKey = typeof keys === "function" ? keys(payload.kid) : keys.get(payload.kid);
|
|
43
|
-
if (publicKey == null)
|
|
44
|
-
throw new TokenError("unknown_kid");
|
|
45
|
-
if (publicKey.length !== 32 || parsed.signature.length !== 64 || !ed25519.verify(parsed.signature, parsed.signed, publicKey)) {
|
|
46
|
-
throw new TokenError("invalid_signature");
|
|
47
|
-
}
|
|
48
|
-
if (options.audience !== undefined && !constantTimeTextEqual(payload.aud, options.audience))
|
|
49
|
-
throw new TokenError("invalid_audience");
|
|
50
|
-
if (options.issuer !== undefined && !constantTimeTextEqual(payload.iss ?? "", options.issuer))
|
|
51
|
-
throw new TokenError("invalid_issuer");
|
|
52
|
-
const skewMs = options.clockSkewMs ?? 0;
|
|
53
|
-
if (!Number.isFinite(skewMs) || skewMs < 0)
|
|
54
|
-
throw new TokenError("invalid_clock_skew");
|
|
55
|
-
const skewSeconds = Math.ceil(skewMs / 1000);
|
|
56
|
-
const now = options.nowUnixS ?? Math.floor(Date.now() / 1000);
|
|
57
|
-
if (!Number.isSafeInteger(now))
|
|
58
|
-
throw new TokenError("invalid_time");
|
|
59
|
-
if (payload.iat > now + skewSeconds)
|
|
60
|
-
throw new TokenError("iat_in_future");
|
|
61
|
-
if (payload.init_exp < now - skewSeconds)
|
|
62
|
-
throw new TokenError("init_expired");
|
|
63
|
-
if (payload.exp < now - skewSeconds)
|
|
64
|
-
throw new TokenError("expired");
|
|
65
|
-
return payload;
|
|
66
|
-
}
|
|
67
|
-
export function equalSignedTokenPart(left, right) {
|
|
68
|
-
const leftPart = left.lastIndexOf(".");
|
|
69
|
-
const rightPart = right.lastIndexOf(".");
|
|
70
|
-
if (leftPart <= 0 || rightPart <= 0)
|
|
71
|
-
return false;
|
|
72
|
-
return constantTimeTextEqual(left.slice(0, leftPart), right.slice(0, rightPart));
|
|
73
|
-
}
|
|
74
|
-
function normalizePayload(input, signing) {
|
|
75
|
-
const kid = String(input?.kid ?? "").trim();
|
|
76
|
-
const aud = String(input?.aud ?? "").trim();
|
|
77
|
-
const iss = String(input?.iss ?? "").trim();
|
|
78
|
-
const channelId = String(input?.channel_id ?? "").trim();
|
|
79
|
-
const tokenId = String(input?.token_id ?? "").trim();
|
|
80
|
-
if (kid === "" || tokenId === "" || (signing && aud === ""))
|
|
81
|
-
throw new TokenError("invalid_format");
|
|
82
|
-
if (channelId === "" || new TextEncoder().encode(channelId).length > 256)
|
|
83
|
-
throw new TokenError("invalid_format");
|
|
84
|
-
if (input.role !== 1 && input.role !== 2)
|
|
85
|
-
throw new TokenError("invalid_format");
|
|
86
|
-
for (const [name, value] of [["init_exp", input.init_exp], ["iat", input.iat], ["exp", input.exp], ["idle_timeout_seconds", input.idle_timeout_seconds]]) {
|
|
87
|
-
if (!Number.isSafeInteger(value))
|
|
88
|
-
throw new TokenError("invalid_format", `invalid ${name}`);
|
|
89
|
-
}
|
|
90
|
-
if (input.idle_timeout_seconds <= 0)
|
|
91
|
-
throw new TokenError("invalid_idle_timeout");
|
|
92
|
-
if (signing && (input.init_exp <= 0 || input.iat <= 0 || input.exp <= 0))
|
|
93
|
-
throw new TokenError("invalid_format");
|
|
94
|
-
if (input.exp > input.init_exp)
|
|
95
|
-
throw new TokenError("exp_after_init");
|
|
96
|
-
if (input.iat > input.exp)
|
|
97
|
-
throw new TokenError("invalid_format");
|
|
98
|
-
return {
|
|
99
|
-
kid,
|
|
100
|
-
aud,
|
|
101
|
-
...(iss === "" ? {} : { iss }),
|
|
102
|
-
channel_id: channelId,
|
|
103
|
-
role: input.role,
|
|
104
|
-
token_id: tokenId,
|
|
105
|
-
init_exp: input.init_exp,
|
|
106
|
-
idle_timeout_seconds: input.idle_timeout_seconds,
|
|
107
|
-
iat: input.iat,
|
|
108
|
-
exp: input.exp,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function constantTimeTextEqual(left, right) {
|
|
112
|
-
const a = new TextEncoder().encode(left);
|
|
113
|
-
const b = new TextEncoder().encode(right);
|
|
114
|
-
let diff = a.length ^ b.length;
|
|
115
|
-
const length = Math.max(a.length, b.length);
|
|
116
|
-
for (let index = 0; index < length; index++)
|
|
117
|
-
diff |= (a[index] ?? 0) ^ (b[index] ?? 0);
|
|
118
|
-
return diff === 0;
|
|
119
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ConnectOptionsBase } from "../client-connect/connectCore.js";
|
|
2
|
-
import type { ClientInternal } from "../client.js";
|
|
3
|
-
export type DirectConnectOptions = ConnectOptionsBase & Readonly<{
|
|
4
|
-
/** Type-only marker to prevent mixing direct and tunnel option types. */
|
|
5
|
-
__mode?: "direct";
|
|
6
|
-
/** Reserved for tunnel connects; forbidden for direct connects. */
|
|
7
|
-
endpointInstanceId?: never;
|
|
8
|
-
}>;
|
|
9
|
-
export declare function connectDirect(info: unknown, opts: DirectConnectOptions): Promise<ClientInternal>;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { assertDirectConnectInfo } from "../gen/flowersec/direct/v1.gen.js";
|
|
2
|
-
import { FlowersecError } from "../utils/errors.js";
|
|
3
|
-
import { connectCore } from "../client-connect/connectCore.js";
|
|
4
|
-
import { assertDirectConnectContract, assertValidPSK, prepareChannelId } from "../client-connect/contract.js";
|
|
5
|
-
function isRecord(v) {
|
|
6
|
-
return typeof v === "object" && v != null && !Array.isArray(v);
|
|
7
|
-
}
|
|
8
|
-
function hasOwn(o, key) {
|
|
9
|
-
return Object.prototype.hasOwnProperty.call(o, key);
|
|
10
|
-
}
|
|
11
|
-
// connectDirect connects to a direct websocket endpoint and returns an RPC-ready session.
|
|
12
|
-
export async function connectDirect(info, opts) {
|
|
13
|
-
const endpointInstanceId = opts?.endpointInstanceId;
|
|
14
|
-
if (endpointInstanceId != null) {
|
|
15
|
-
throw new FlowersecError({
|
|
16
|
-
stage: "validate",
|
|
17
|
-
code: "invalid_option",
|
|
18
|
-
path: "direct",
|
|
19
|
-
message: "endpointInstanceId is only valid for tunnel connects",
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
if (info == null) {
|
|
23
|
-
throw new FlowersecError({ stage: "validate", code: "missing_connect_info", path: "direct", message: "missing connect info" });
|
|
24
|
-
}
|
|
25
|
-
if (isRecord(info)) {
|
|
26
|
-
// Align missing/invalid field codes with Go: missing fields map to specific stable codes.
|
|
27
|
-
const okTypes = (!hasOwn(info, "ws_url") || typeof info["ws_url"] === "string") &&
|
|
28
|
-
(!hasOwn(info, "channel_id") || typeof info["channel_id"] === "string") &&
|
|
29
|
-
(!hasOwn(info, "channel_init_expire_at_unix_s") ||
|
|
30
|
-
(typeof info["channel_init_expire_at_unix_s"] === "number" && Number.isSafeInteger(info["channel_init_expire_at_unix_s"]))) &&
|
|
31
|
-
(!hasOwn(info, "e2ee_psk_b64u") || typeof info["e2ee_psk_b64u"] === "string") &&
|
|
32
|
-
(!hasOwn(info, "default_suite") || (typeof info["default_suite"] === "number" && Number.isSafeInteger(info["default_suite"])));
|
|
33
|
-
if (okTypes) {
|
|
34
|
-
if (!hasOwn(info, "ws_url")) {
|
|
35
|
-
throw new FlowersecError({ stage: "validate", code: "missing_ws_url", path: "direct", message: "missing ws_url" });
|
|
36
|
-
}
|
|
37
|
-
if (!hasOwn(info, "channel_id")) {
|
|
38
|
-
throw new FlowersecError({ stage: "validate", code: "missing_channel_id", path: "direct", message: "missing channel_id" });
|
|
39
|
-
}
|
|
40
|
-
if (!hasOwn(info, "channel_init_expire_at_unix_s")) {
|
|
41
|
-
throw new FlowersecError({
|
|
42
|
-
stage: "validate",
|
|
43
|
-
code: "missing_init_exp",
|
|
44
|
-
path: "direct",
|
|
45
|
-
message: "missing channel_init_expire_at_unix_s",
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
if (!hasOwn(info, "e2ee_psk_b64u")) {
|
|
49
|
-
throw new FlowersecError({ stage: "validate", code: "invalid_psk", path: "direct", message: "missing e2ee_psk_b64u" });
|
|
50
|
-
}
|
|
51
|
-
if (!hasOwn(info, "default_suite")) {
|
|
52
|
-
throw new FlowersecError({ stage: "validate", code: "invalid_suite", path: "direct", message: "missing default_suite" });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const suite = info["default_suite"];
|
|
56
|
-
// Keep "invalid_suite" as the stable error code even when the IDL validator rejects the enum value.
|
|
57
|
-
if (typeof suite === "number" && Number.isSafeInteger(suite) && suite !== 1 && suite !== 2) {
|
|
58
|
-
throw new FlowersecError({ stage: "validate", code: "invalid_suite", path: "direct", message: "invalid suite" });
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
let ready;
|
|
62
|
-
try {
|
|
63
|
-
ready = assertDirectConnectInfo(info);
|
|
64
|
-
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
throw new FlowersecError({ stage: "validate", code: "invalid_input", path: "direct", message: "invalid DirectConnectInfo", cause: e });
|
|
67
|
-
}
|
|
68
|
-
if (ready.ws_url === "") {
|
|
69
|
-
throw new FlowersecError({ stage: "validate", code: "missing_ws_url", path: "direct", message: "missing ws_url" });
|
|
70
|
-
}
|
|
71
|
-
const channelId = prepareChannelId(ready.channel_id, "direct");
|
|
72
|
-
if (ready.channel_init_expire_at_unix_s <= 0) {
|
|
73
|
-
throw new FlowersecError({
|
|
74
|
-
stage: "validate",
|
|
75
|
-
code: "missing_init_exp",
|
|
76
|
-
path: "direct",
|
|
77
|
-
message: "missing channel_init_expire_at_unix_s",
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
assertDirectConnectContract(ready);
|
|
81
|
-
assertValidPSK(ready.e2ee_psk_b64u, "direct");
|
|
82
|
-
return await connectCore({
|
|
83
|
-
path: "direct",
|
|
84
|
-
wsUrl: ready.ws_url,
|
|
85
|
-
channelId,
|
|
86
|
-
e2eePskB64u: ready.e2ee_psk_b64u,
|
|
87
|
-
defaultSuite: ready.default_suite,
|
|
88
|
-
opts,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./connect.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./connect.js";
|
package/dist/e2ee/constants.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare const HANDSHAKE_MAGIC = "FSEH";
|
|
2
|
-
export declare const RECORD_MAGIC = "FSEC";
|
|
3
|
-
export declare const PROTOCOL_VERSION: 1;
|
|
4
|
-
export declare const HANDSHAKE_TYPE_INIT: 1;
|
|
5
|
-
export declare const HANDSHAKE_TYPE_RESP: 2;
|
|
6
|
-
export declare const HANDSHAKE_TYPE_ACK: 3;
|
|
7
|
-
export declare const RECORD_FLAG_APP: 0;
|
|
8
|
-
export declare const RECORD_FLAG_PING: 1;
|
|
9
|
-
export declare const RECORD_FLAG_REKEY: 2;
|
package/dist/e2ee/constants.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// Handshake header prefix.
|
|
2
|
-
export const HANDSHAKE_MAGIC = "FSEH";
|
|
3
|
-
// Record header prefix.
|
|
4
|
-
export const RECORD_MAGIC = "FSEC";
|
|
5
|
-
// Wire-format version for E2EE framing.
|
|
6
|
-
export const PROTOCOL_VERSION = 1;
|
|
7
|
-
// Client->server init.
|
|
8
|
-
export const HANDSHAKE_TYPE_INIT = 1;
|
|
9
|
-
// Server response with ephemeral key and nonce.
|
|
10
|
-
export const HANDSHAKE_TYPE_RESP = 2;
|
|
11
|
-
// Client ack with auth tag.
|
|
12
|
-
export const HANDSHAKE_TYPE_ACK = 3;
|
|
13
|
-
// Application payload record.
|
|
14
|
-
export const RECORD_FLAG_APP = 0;
|
|
15
|
-
// Keepalive record.
|
|
16
|
-
export const RECORD_FLAG_PING = 1;
|
|
17
|
-
// Rekey record.
|
|
18
|
-
export const RECORD_FLAG_REKEY = 2;
|
package/dist/e2ee/errors.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export type E2EEHandshakeErrorCode = "auth_tag_mismatch" | "invalid_suite" | "invalid_version" | "timestamp_after_init_exp" | "timestamp_out_of_skew";
|
|
2
|
-
export declare class E2EEHandshakeError extends Error {
|
|
3
|
-
readonly code: E2EEHandshakeErrorCode;
|
|
4
|
-
constructor(code: E2EEHandshakeErrorCode, message: string);
|
|
5
|
-
}
|
package/dist/e2ee/errors.js
DELETED
package/dist/e2ee/framing.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare const HANDSHAKE_HEADER_LEN: number;
|
|
2
|
-
export declare const RECORD_HEADER_LEN: number;
|
|
3
|
-
export declare class FramingError extends Error {
|
|
4
|
-
}
|
|
5
|
-
export declare function encodeHandshakeFrame(handshakeType: number, payloadJsonUtf8: Uint8Array): Uint8Array;
|
|
6
|
-
export declare function decodeHandshakeFrame(frame: Uint8Array, maxPayloadBytes: number): {
|
|
7
|
-
handshakeType: number;
|
|
8
|
-
payloadJsonUtf8: Uint8Array;
|
|
9
|
-
};
|
|
10
|
-
export declare function looksLikeRecordFrame(frame: Uint8Array, maxCiphertextBytes: number): boolean;
|
|
11
|
-
export declare function encodeU64beBigint(n: bigint): Uint8Array;
|
|
12
|
-
export declare function decodeU64beBigint(buf: Uint8Array, off: number): bigint;
|
package/dist/e2ee/framing.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { concatBytes, readU32be, readU64be, u32be, u64be } from "../utils/bin.js";
|
|
2
|
-
import { HANDSHAKE_MAGIC, PROTOCOL_VERSION, RECORD_MAGIC } from "./constants.js";
|
|
3
|
-
const te = new TextEncoder();
|
|
4
|
-
const td = new TextDecoder();
|
|
5
|
-
// Handshake header byte size: magic + version + type + length.
|
|
6
|
-
export const HANDSHAKE_HEADER_LEN = 4 + 1 + 1 + 4;
|
|
7
|
-
// Record header byte size: magic + version + flags + seq + length.
|
|
8
|
-
export const RECORD_HEADER_LEN = 4 + 1 + 1 + 8 + 4;
|
|
9
|
-
// FramingError marks malformed or truncated frames.
|
|
10
|
-
export class FramingError extends Error {
|
|
11
|
-
}
|
|
12
|
-
// encodeHandshakeFrame builds the handshake header plus JSON payload.
|
|
13
|
-
export function encodeHandshakeFrame(handshakeType, payloadJsonUtf8) {
|
|
14
|
-
const header = new Uint8Array(HANDSHAKE_HEADER_LEN);
|
|
15
|
-
header.set(te.encode(HANDSHAKE_MAGIC), 0);
|
|
16
|
-
header[4] = PROTOCOL_VERSION;
|
|
17
|
-
header[5] = handshakeType & 0xff;
|
|
18
|
-
header.set(u32be(payloadJsonUtf8.length), 6);
|
|
19
|
-
return concatBytes([header, payloadJsonUtf8]);
|
|
20
|
-
}
|
|
21
|
-
// decodeHandshakeFrame validates the handshake header and extracts the payload.
|
|
22
|
-
export function decodeHandshakeFrame(frame, maxPayloadBytes) {
|
|
23
|
-
if (frame.length < HANDSHAKE_HEADER_LEN)
|
|
24
|
-
throw new FramingError("handshake frame too short");
|
|
25
|
-
if (td.decode(frame.slice(0, 4)) !== HANDSHAKE_MAGIC)
|
|
26
|
-
throw new FramingError("bad handshake magic");
|
|
27
|
-
if (frame[4] !== PROTOCOL_VERSION)
|
|
28
|
-
throw new FramingError("bad handshake version");
|
|
29
|
-
const handshakeType = frame[5];
|
|
30
|
-
const n = readU32be(frame, 6);
|
|
31
|
-
if (maxPayloadBytes > 0 && n > maxPayloadBytes)
|
|
32
|
-
throw new FramingError("handshake payload too large");
|
|
33
|
-
if (HANDSHAKE_HEADER_LEN + n !== frame.length)
|
|
34
|
-
throw new FramingError("handshake length mismatch");
|
|
35
|
-
return { handshakeType, payloadJsonUtf8: frame.slice(HANDSHAKE_HEADER_LEN) };
|
|
36
|
-
}
|
|
37
|
-
// looksLikeRecordFrame checks whether a frame matches the record header shape.
|
|
38
|
-
export function looksLikeRecordFrame(frame, maxCiphertextBytes) {
|
|
39
|
-
if (frame.length < RECORD_HEADER_LEN)
|
|
40
|
-
return false;
|
|
41
|
-
if (td.decode(frame.slice(0, 4)) !== RECORD_MAGIC)
|
|
42
|
-
return false;
|
|
43
|
-
if (frame[4] !== PROTOCOL_VERSION)
|
|
44
|
-
return false;
|
|
45
|
-
const n = readU32be(frame, 14);
|
|
46
|
-
if (maxCiphertextBytes > 0 && n > maxCiphertextBytes)
|
|
47
|
-
return false;
|
|
48
|
-
return RECORD_HEADER_LEN + n === frame.length;
|
|
49
|
-
}
|
|
50
|
-
// encodeU64beBigint converts a bigint into an 8-byte big-endian buffer.
|
|
51
|
-
export function encodeU64beBigint(n) {
|
|
52
|
-
return u64be(n);
|
|
53
|
-
}
|
|
54
|
-
// decodeU64beBigint reads a bigint from an 8-byte big-endian buffer.
|
|
55
|
-
export function decodeU64beBigint(buf, off) {
|
|
56
|
-
return readU64be(buf, off);
|
|
57
|
-
}
|
package/dist/e2ee/handshake.d.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { E2EE_Init } from "../gen/flowersec/e2ee/v1.gen.js";
|
|
2
|
-
import { SecureChannel, type BinaryTransport } from "./secureChannel.js";
|
|
3
|
-
export type Suite = 1 | 2;
|
|
4
|
-
export type HandshakeClientOptions = Readonly<{
|
|
5
|
-
/** Channel identifier shared with the server. */
|
|
6
|
-
channelId: string;
|
|
7
|
-
/** Cipher suite selection (see Suite). */
|
|
8
|
-
suite: Suite;
|
|
9
|
-
/** 32-byte pre-shared key for authenticating the handshake. */
|
|
10
|
-
psk: Uint8Array;
|
|
11
|
-
/** Client feature bitset advertised during handshake. */
|
|
12
|
-
clientFeatures: number;
|
|
13
|
-
/** Maximum allowed bytes for a handshake JSON payload. */
|
|
14
|
-
maxHandshakePayload: number;
|
|
15
|
-
/** Maximum record size for encrypted frames after handshake. */
|
|
16
|
-
maxRecordBytes: number;
|
|
17
|
-
/** Preferred plaintext bytes per outbound record. */
|
|
18
|
-
outboundRecordChunkBytes?: number;
|
|
19
|
-
/** Maximum queued inbound plaintext bytes for the secure channel. */
|
|
20
|
-
maxBufferedBytes?: number;
|
|
21
|
-
/** Maximum queued outbound plaintext bytes for the secure channel. */
|
|
22
|
-
maxOutboundBufferedBytes?: number;
|
|
23
|
-
/** Optional AbortSignal to cancel the handshake. */
|
|
24
|
-
signal?: AbortSignal;
|
|
25
|
-
/** Optional total handshake timeout in milliseconds (>= 0; 0 disables). */
|
|
26
|
-
timeoutMs?: number;
|
|
27
|
-
}>;
|
|
28
|
-
export type HandshakeServerOptions = Readonly<{
|
|
29
|
-
/** Channel identifier expected from the client. */
|
|
30
|
-
channelId: string;
|
|
31
|
-
/** Cipher suite selection (see Suite). */
|
|
32
|
-
suite: Suite;
|
|
33
|
-
/** 32-byte pre-shared key for authenticating the handshake. */
|
|
34
|
-
psk: Uint8Array;
|
|
35
|
-
/** Server feature bitset advertised during handshake. */
|
|
36
|
-
serverFeatures: number;
|
|
37
|
-
/** Absolute expiry (Unix seconds) for the init message. */
|
|
38
|
-
initExpireAtUnixS: number;
|
|
39
|
-
/** Allowed clock skew (seconds) for timestamp validation. */
|
|
40
|
-
clockSkewSeconds: number;
|
|
41
|
-
/** Maximum allowed bytes for a handshake JSON payload. */
|
|
42
|
-
maxHandshakePayload: number;
|
|
43
|
-
/** Maximum record size for encrypted frames after handshake. */
|
|
44
|
-
maxRecordBytes: number;
|
|
45
|
-
/** Preferred plaintext bytes per outbound record. */
|
|
46
|
-
outboundRecordChunkBytes?: number;
|
|
47
|
-
/** Maximum queued inbound plaintext bytes for the secure channel. */
|
|
48
|
-
maxBufferedBytes?: number;
|
|
49
|
-
/** Maximum queued outbound plaintext bytes for the secure channel. */
|
|
50
|
-
maxOutboundBufferedBytes?: number;
|
|
51
|
-
/** Optional AbortSignal to cancel the handshake. */
|
|
52
|
-
signal?: AbortSignal;
|
|
53
|
-
/** Optional total handshake timeout in milliseconds (>= 0; 0 disables). */
|
|
54
|
-
timeoutMs?: number;
|
|
55
|
-
}>;
|
|
56
|
-
export declare function clientHandshake(transport: BinaryTransport, opts: HandshakeClientOptions): Promise<SecureChannel>;
|
|
57
|
-
type ServerCacheEntry = {
|
|
58
|
-
/** Stable fingerprint of the init message for retries. */
|
|
59
|
-
initKey: string;
|
|
60
|
-
/** Suite used for this cached handshake. */
|
|
61
|
-
suite: Suite;
|
|
62
|
-
/** Server ephemeral private key for ECDH. */
|
|
63
|
-
serverPriv: Uint8Array;
|
|
64
|
-
/** Server ephemeral public key bytes. */
|
|
65
|
-
serverPub: Uint8Array;
|
|
66
|
-
/** Server nonce (32 bytes). */
|
|
67
|
-
nonceS: Uint8Array;
|
|
68
|
-
/** Handshake identifier returned to the client. */
|
|
69
|
-
handshakeId: string;
|
|
70
|
-
/** Server feature bitset from this handshake. */
|
|
71
|
-
serverFeatures: number;
|
|
72
|
-
/** Cache insert time (ms since epoch) for TTL eviction. */
|
|
73
|
-
createdAtMs: number;
|
|
74
|
-
};
|
|
75
|
-
export declare class ServerHandshakeCache {
|
|
76
|
-
private readonly m;
|
|
77
|
-
private readonly ttlMs;
|
|
78
|
-
private readonly maxEntries;
|
|
79
|
-
constructor(opts?: Readonly<{
|
|
80
|
-
ttlMs?: number;
|
|
81
|
-
maxEntries?: number;
|
|
82
|
-
}>);
|
|
83
|
-
private cleanup;
|
|
84
|
-
getOrCreate(init: E2EE_Init, suite: Suite, serverFeatures: number): ServerCacheEntry;
|
|
85
|
-
delete(init: E2EE_Init): void;
|
|
86
|
-
}
|
|
87
|
-
export declare function serverHandshake(transport: BinaryTransport, cache: ServerHandshakeCache, opts: HandshakeServerOptions): Promise<SecureChannel>;
|
|
88
|
-
export {};
|