@floegence/flowersec-core 0.27.0 → 2.1.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.
Files changed (268) hide show
  1. package/README.md +91 -22
  2. package/THIRD_PARTY_NOTICES.md +141 -0
  3. package/dist/browser/connectSession.d.ts +13 -0
  4. package/dist/browser/connectSession.js +40 -0
  5. package/dist/browser/index.d.ts +3 -10
  6. package/dist/browser/index.js +2 -5
  7. package/dist/browser/runtimeCapability.d.ts +13 -0
  8. package/dist/browser/runtimeCapability.js +27 -0
  9. package/dist/browser/sessionRuntime.d.ts +2 -0
  10. package/dist/browser/sessionRuntime.js +21 -0
  11. package/dist/browser/webTransportClient.d.ts +8 -0
  12. package/dist/browser/webTransportClient.js +55 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +126 -0
  15. package/dist/cliSpendMarker.d.ts +1 -0
  16. package/dist/cliSpendMarker.js +22 -0
  17. package/dist/connectionController.d.ts +54 -0
  18. package/dist/connectionController.js +438 -0
  19. package/dist/connector/adapters/webSocketCandidate.d.ts +7 -0
  20. package/dist/connector/adapters/webSocketCandidate.js +116 -0
  21. package/dist/connector/adapters/webTransportCandidate.d.ts +5 -0
  22. package/dist/connector/adapters/webTransportCandidate.js +73 -0
  23. package/dist/connector/admissionCommit.d.ts +31 -0
  24. package/dist/connector/admissionCommit.js +239 -0
  25. package/dist/connector/sessionAcceptor.d.ts +16 -0
  26. package/dist/connector/sessionAcceptor.js +114 -0
  27. package/dist/connector/sessionConfig.d.ts +3 -0
  28. package/dist/connector/sessionConfig.js +30 -0
  29. package/dist/connector/sessionConnector.d.ts +45 -0
  30. package/dist/connector/sessionConnector.js +603 -0
  31. package/dist/defaults.d.ts +7 -7
  32. package/dist/defaults.js +7 -7
  33. package/dist/facade.d.ts +12 -27
  34. package/dist/facade.js +6 -24
  35. package/dist/node/connectSession.d.ts +21 -0
  36. package/dist/node/connectSession.js +62 -0
  37. package/dist/node/index.d.ts +3 -11
  38. package/dist/node/index.js +2 -8
  39. package/dist/node/runtimeCapability.d.ts +7 -0
  40. package/dist/node/runtimeCapability.js +10 -0
  41. package/dist/node/sessionRuntime.d.ts +2 -0
  42. package/dist/node/sessionRuntime.js +13 -0
  43. package/dist/node/webTransportClient.d.ts +9 -0
  44. package/dist/node/webTransportClient.js +56 -0
  45. package/dist/node/webTransportServer.d.ts +22 -0
  46. package/dist/node/webTransportServer.js +100 -0
  47. package/dist/node/wsFactory.d.ts +3 -1
  48. package/dist/node/wsFactory.js +4 -3
  49. package/dist/proxy/controllerGuard.d.ts +4 -4
  50. package/dist/proxy/controllerGuard.js +83 -177
  51. package/dist/proxy/disableUpstreamServiceWorkerRegister.d.ts +3 -1
  52. package/dist/proxy/disableUpstreamServiceWorkerRegister.js +19 -17
  53. package/dist/proxy/index.d.ts +16 -15
  54. package/dist/proxy/index.js +8 -14
  55. package/dist/proxy/integration.d.ts +23 -71
  56. package/dist/proxy/integration.js +37 -340
  57. package/dist/proxy/registerServiceWorker.d.ts +1 -10
  58. package/dist/proxy/registerServiceWorker.js +43 -105
  59. package/dist/proxy/runtime.d.ts +3 -63
  60. package/dist/proxy/runtime.js +349 -462
  61. package/dist/proxy/scope.d.ts +6 -0
  62. package/dist/proxy/scope.js +131 -0
  63. package/dist/proxy/serviceWorker.d.ts +5 -16
  64. package/dist/proxy/serviceWorker.js +230 -617
  65. package/dist/proxy/stream.d.ts +9 -0
  66. package/dist/proxy/stream.js +40 -0
  67. package/dist/proxy/types.d.ts +78 -30
  68. package/dist/proxy/windowBridge.d.ts +61 -0
  69. package/dist/proxy/windowBridge.js +344 -0
  70. package/dist/proxy/wsPatch.d.ts +4 -14
  71. package/dist/proxy/wsPatch.js +173 -268
  72. package/dist/public/artifact.d.ts +11 -0
  73. package/dist/public/artifact.js +44 -0
  74. package/dist/public/artifactLease.d.ts +10 -0
  75. package/dist/public/artifactLease.js +48 -0
  76. package/dist/public/connectError.d.ts +6 -0
  77. package/dist/public/connectError.js +9 -0
  78. package/dist/public/contract.d.ts +83 -0
  79. package/dist/public/contract.js +17 -0
  80. package/dist/public/streamMetadata.d.ts +10 -0
  81. package/dist/public/streamMetadata.js +40 -0
  82. package/dist/rpc/caller.d.ts +1 -1
  83. package/dist/rpc/client.d.ts +1 -4
  84. package/dist/rpc/client.js +0 -21
  85. package/dist/rpc/rpcProxy.d.ts +1 -1
  86. package/dist/rpc/server.d.ts +1 -1
  87. package/dist/rpc/validate.d.ts +1 -1
  88. package/dist/rpc/wire.d.ts +15 -0
  89. package/dist/runtime/errors.d.ts +6 -0
  90. package/dist/runtime/errors.js +10 -0
  91. package/dist/transport/webSocketAdapter.d.ts +24 -0
  92. package/dist/transport/webSocketAdapter.js +234 -0
  93. package/dist/transport/webTransportAdapter.d.ts +27 -0
  94. package/dist/transport/webTransportAdapter.js +519 -0
  95. package/dist/utils/errors.d.ts +2 -20
  96. package/dist/utils/errors.js +73 -20
  97. package/dist/v2/admissionError.d.ts +4 -0
  98. package/dist/v2/admissionError.js +8 -0
  99. package/dist/v2/artifact.d.ts +128 -0
  100. package/dist/v2/artifact.js +1126 -0
  101. package/dist/v2/artifactLease.d.ts +1 -0
  102. package/dist/v2/artifactLease.js +7 -0
  103. package/dist/v2/capability.d.ts +29 -0
  104. package/dist/v2/capability.js +190 -0
  105. package/dist/v2/carrier.d.ts +79 -0
  106. package/dist/v2/carrier.js +405 -0
  107. package/dist/v2/contract.d.ts +37 -0
  108. package/dist/v2/contract.js +1 -0
  109. package/dist/v2/handshake.d.ts +80 -0
  110. package/dist/v2/handshake.js +470 -0
  111. package/dist/v2/opaqueArtifact.d.ts +1 -0
  112. package/dist/v2/opaqueArtifact.js +2 -0
  113. package/dist/v2/protocol.d.ts +99 -0
  114. package/dist/v2/protocol.js +739 -0
  115. package/dist/v2/publicSession.d.ts +1 -0
  116. package/dist/v2/publicSession.js +179 -0
  117. package/dist/v2/retryDisposition.d.ts +16 -0
  118. package/dist/v2/retryDisposition.js +30 -0
  119. package/dist/v2/session.d.ts +277 -0
  120. package/dist/v2/session.js +1879 -0
  121. package/dist/v2/streamLifetimeLedger.d.ts +31 -0
  122. package/dist/v2/streamLifetimeLedger.js +131 -0
  123. package/dist/v2/streamMetadata.d.ts +1 -0
  124. package/dist/v2/streamMetadata.js +7 -0
  125. package/dist/v2/unreliableMessage.d.ts +43 -0
  126. package/dist/v2/unreliableMessage.js +252 -0
  127. package/dist/vendor/tr46.d.ts +10 -0
  128. package/dist/vendor/tr46.js +501 -0
  129. package/dist/ws-client/binaryTransport.d.ts +0 -3
  130. package/dist/ws-client/binaryTransport.js +15 -39
  131. package/dist/yamux/errors.d.ts +0 -4
  132. package/dist/yamux/errors.js +0 -9
  133. package/dist/yamux/session.d.ts +0 -5
  134. package/dist/yamux/session.js +4 -70
  135. package/dist/yamux/stream.d.ts +1 -0
  136. package/dist/yamux/stream.js +4 -0
  137. package/package.json +29 -81
  138. package/sbom/cyclonedx.json +2764 -0
  139. package/sbom/spdx.json +1947 -0
  140. package/YAMUX_ALIGNMENT.md +0 -127
  141. package/dist/_examples/flowersec/demo/v1.facade.gen.d.ts +0 -12
  142. package/dist/_examples/flowersec/demo/v1.facade.gen.js +0 -15
  143. package/dist/_examples/flowersec/demo/v1.gen.d.ts +0 -16
  144. package/dist/_examples/flowersec/demo/v1.gen.js +0 -86
  145. package/dist/_examples/flowersec/demo/v1.rpc.gen.d.ts +0 -11
  146. package/dist/_examples/flowersec/demo/v1.rpc.gen.js +0 -22
  147. package/dist/browser/connect.d.ts +0 -13
  148. package/dist/browser/connect.js +0 -31
  149. package/dist/browser/reconnectConfig.d.ts +0 -15
  150. package/dist/browser/reconnectConfig.js +0 -20
  151. package/dist/client-connect/common.d.ts +0 -26
  152. package/dist/client-connect/common.js +0 -167
  153. package/dist/client-connect/connectCore.d.ts +0 -61
  154. package/dist/client-connect/connectCore.js +0 -572
  155. package/dist/client-connect/contract.d.ts +0 -8
  156. package/dist/client-connect/contract.js +0 -51
  157. package/dist/client-connect/termination.d.ts +0 -6
  158. package/dist/client-connect/termination.js +0 -7
  159. package/dist/client-connect/transportSecurity.d.ts +0 -27
  160. package/dist/client-connect/transportSecurity.js +0 -199
  161. package/dist/client-connect/tunnelAttachCloseReason.d.ts +0 -3
  162. package/dist/client-connect/tunnelAttachCloseReason.js +0 -23
  163. package/dist/client.d.ts +0 -23
  164. package/dist/connect/artifact.d.ts +0 -36
  165. package/dist/connect/artifact.js +0 -213
  166. package/dist/connect/resolveArtifact.d.ts +0 -22
  167. package/dist/connect/resolveArtifact.js +0 -87
  168. package/dist/controlplane/channelInit.d.ts +0 -27
  169. package/dist/controlplane/channelInit.js +0 -116
  170. package/dist/controlplane/http.d.ts +0 -16
  171. package/dist/controlplane/http.js +0 -59
  172. package/dist/controlplane/index.d.ts +0 -6
  173. package/dist/controlplane/index.js +0 -5
  174. package/dist/controlplane/issuer.d.ts +0 -18
  175. package/dist/controlplane/issuer.js +0 -113
  176. package/dist/controlplane/request.d.ts +0 -51
  177. package/dist/controlplane/request.js +0 -273
  178. package/dist/controlplane/token.d.ts +0 -33
  179. package/dist/controlplane/token.js +0 -119
  180. package/dist/direct-client/connect.d.ts +0 -9
  181. package/dist/direct-client/connect.js +0 -90
  182. package/dist/direct-client/index.d.ts +0 -1
  183. package/dist/direct-client/index.js +0 -1
  184. package/dist/e2ee/constants.d.ts +0 -9
  185. package/dist/e2ee/constants.js +0 -18
  186. package/dist/e2ee/errors.d.ts +0 -5
  187. package/dist/e2ee/errors.js +0 -8
  188. package/dist/e2ee/framing.d.ts +0 -12
  189. package/dist/e2ee/framing.js +0 -57
  190. package/dist/e2ee/handshake.d.ts +0 -88
  191. package/dist/e2ee/handshake.js +0 -353
  192. package/dist/e2ee/index.d.ts +0 -7
  193. package/dist/e2ee/index.js +0 -7
  194. package/dist/e2ee/kdf.d.ts +0 -15
  195. package/dist/e2ee/kdf.js +0 -39
  196. package/dist/e2ee/record.d.ts +0 -11
  197. package/dist/e2ee/record.js +0 -80
  198. package/dist/e2ee/secureChannel.d.ts +0 -93
  199. package/dist/e2ee/secureChannel.js +0 -342
  200. package/dist/e2ee/transcript.d.ts +0 -23
  201. package/dist/e2ee/transcript.js +0 -31
  202. package/dist/endpoint/index.d.ts +0 -84
  203. package/dist/endpoint/index.js +0 -557
  204. package/dist/endpoint/node.d.ts +0 -9
  205. package/dist/endpoint/node.js +0 -51
  206. package/dist/gen/flowersec/controlplane/v1.gen.d.ts +0 -36
  207. package/dist/gen/flowersec/controlplane/v1.gen.js +0 -135
  208. package/dist/gen/flowersec/direct/v1.gen.d.ts +0 -21
  209. package/dist/gen/flowersec/direct/v1.gen.js +0 -101
  210. package/dist/gen/flowersec/e2ee/v1.gen.d.ts +0 -68
  211. package/dist/gen/flowersec/e2ee/v1.gen.js +0 -194
  212. package/dist/gen/flowersec/rpc/v1.gen.d.ts +0 -30
  213. package/dist/gen/flowersec/rpc/v1.gen.js +0 -107
  214. package/dist/gen/flowersec/tunnel/v1.gen.d.ts +0 -23
  215. package/dist/gen/flowersec/tunnel/v1.gen.js +0 -104
  216. package/dist/index.d.ts +0 -22
  217. package/dist/index.js +0 -22
  218. package/dist/node/connect.d.ts +0 -10
  219. package/dist/node/connect.js +0 -29
  220. package/dist/node/reconnectConfig.d.ts +0 -16
  221. package/dist/node/reconnectConfig.js +0 -20
  222. package/dist/observability/index.d.ts +0 -1
  223. package/dist/observability/index.js +0 -1
  224. package/dist/observability/observer.d.ts +0 -52
  225. package/dist/observability/observer.js +0 -314
  226. package/dist/proxy/appWindow.d.ts +0 -37
  227. package/dist/proxy/appWindow.js +0 -273
  228. package/dist/proxy/bootstrap.d.ts +0 -35
  229. package/dist/proxy/bootstrap.js +0 -119
  230. package/dist/proxy/constants.d.ts +0 -7
  231. package/dist/proxy/constants.js +0 -8
  232. package/dist/proxy/controllerWindow.d.ts +0 -12
  233. package/dist/proxy/controllerWindow.js +0 -384
  234. package/dist/proxy/cookieJar.d.ts +0 -7
  235. package/dist/proxy/cookieJar.js +0 -136
  236. package/dist/proxy/headerPolicy.d.ts +0 -14
  237. package/dist/proxy/headerPolicy.js +0 -134
  238. package/dist/proxy/portStream.d.ts +0 -5
  239. package/dist/proxy/portStream.js +0 -256
  240. package/dist/proxy/preset.d.ts +0 -29
  241. package/dist/proxy/preset.js +0 -111
  242. package/dist/proxy/runtimeScope.d.ts +0 -57
  243. package/dist/proxy/runtimeScope.js +0 -218
  244. package/dist/proxy/server.d.ts +0 -28
  245. package/dist/proxy/server.js +0 -833
  246. package/dist/proxy/windowBridgeProtocol.d.ts +0 -65
  247. package/dist/proxy/windowBridgeProtocol.js +0 -11
  248. package/dist/reconnect/artifactControlplane.d.ts +0 -16
  249. package/dist/reconnect/artifactControlplane.js +0 -35
  250. package/dist/reconnect/index.d.ts +0 -36
  251. package/dist/reconnect/index.js +0 -388
  252. package/dist/rpc-proxy/index.d.ts +0 -1
  253. package/dist/rpc-proxy/index.js +0 -1
  254. package/dist/rpc-proxy/rpcProxy.d.ts +0 -1
  255. package/dist/rpc-proxy/rpcProxy.js +0 -1
  256. package/dist/streamhello/index.d.ts +0 -1
  257. package/dist/streamhello/index.js +0 -1
  258. package/dist/streamhello/streamHello.d.ts +0 -3
  259. package/dist/streamhello/streamHello.js +0 -13
  260. package/dist/streamio/index.d.ts +0 -32
  261. package/dist/streamio/index.js +0 -87
  262. package/dist/tunnel-client/connect.d.ts +0 -9
  263. package/dist/tunnel-client/connect.js +0 -147
  264. package/dist/tunnel-client/index.d.ts +0 -1
  265. package/dist/tunnel-client/index.js +0 -1
  266. package/dist/ws/index.d.ts +0 -1
  267. package/dist/ws/index.js +0 -1
  268. /package/dist/{client.js → rpc/wire.js} +0 -0
@@ -1,342 +0,0 @@
1
- import { RECORD_FLAG_APP, RECORD_FLAG_PING, RECORD_FLAG_REKEY } from "./constants.js";
2
- import { decryptRecord, encryptRecord, maxPlaintextBytes } from "./record.js";
3
- import { deriveRekeyKey } from "./kdf.js";
4
- import { SDK_DEFAULTS } from "../defaults.js";
5
- const maxRecordSeq = (1n << 64n) - 1n;
6
- class RecordSeqExhaustedError extends Error {
7
- constructor() {
8
- super("record seq exhausted");
9
- this.name = "RecordSeqExhaustedError";
10
- }
11
- }
12
- // SecureChannel encrypts/decrypts records and buffers application payloads.
13
- export class SecureChannel {
14
- // Underlying transport for encrypted record frames.
15
- transport;
16
- // Maximum allowed bytes per record frame.
17
- maxRecordBytes;
18
- outboundRecordChunkBytes;
19
- maxInboundBufferedBytes;
20
- maxOutboundBufferedBytes;
21
- // Active encryption keys and nonce prefixes for the current epoch.
22
- sendKey;
23
- recvKey;
24
- sendNoncePrefix;
25
- recvNoncePrefix;
26
- // Rekey base secret derived from the handshake.
27
- rekeyBase;
28
- // Transcript hash binding rekeys to the handshake.
29
- transcriptHash;
30
- // Rekey direction identifiers for send/recv.
31
- sendDir;
32
- recvDir;
33
- // Monotonic record sequence numbers per direction.
34
- sendSeq;
35
- recvSeq;
36
- // Send queue and waiters for backpressure.
37
- sendQueue = [];
38
- sendQueueHead = 0;
39
- sendWaiters = [];
40
- sendWaitersHead = 0;
41
- sendQueueBytes = 0;
42
- sendClosed = false;
43
- sendErr = null;
44
- // Receive queue and waiters for plaintext delivery.
45
- recvQueue = [];
46
- recvQueueHead = 0;
47
- recvQueueBytes = 0;
48
- recvWaiters = [];
49
- readErr = null;
50
- closed = false;
51
- constructor(args) {
52
- this.transport = args.transport;
53
- this.maxRecordBytes = args.maxRecordBytes;
54
- const maxPlain = Math.max(1, maxPlaintextBytes(this.maxRecordBytes));
55
- this.outboundRecordChunkBytes = args.outboundRecordChunkBytes ?? Math.min(SDK_DEFAULTS.e2ee.outboundRecordChunkBytes, maxPlain);
56
- if (!Number.isSafeInteger(this.outboundRecordChunkBytes) || this.outboundRecordChunkBytes <= 0 || this.outboundRecordChunkBytes > maxPlain) {
57
- throw new RangeError("outboundRecordChunkBytes must be a positive integer within the record plaintext limit");
58
- }
59
- this.maxInboundBufferedBytes = Math.max(0, args.maxBufferedBytes ?? SDK_DEFAULTS.e2ee.maxInboundBufferedBytes);
60
- const maxOutboundBufferedBytes = args.maxOutboundBufferedBytes ?? SDK_DEFAULTS.e2ee.maxOutboundBufferedBytes;
61
- if (!Number.isSafeInteger(maxOutboundBufferedBytes) || maxOutboundBufferedBytes < 0) {
62
- throw new RangeError("maxOutboundBufferedBytes must be a non-negative safe integer");
63
- }
64
- this.maxOutboundBufferedBytes = maxOutboundBufferedBytes === 0 ? SDK_DEFAULTS.e2ee.maxOutboundBufferedBytes : maxOutboundBufferedBytes;
65
- this.sendKey = args.sendKey.slice();
66
- this.recvKey = args.recvKey.slice();
67
- this.sendNoncePrefix = args.sendNoncePrefix;
68
- this.recvNoncePrefix = args.recvNoncePrefix;
69
- this.rekeyBase = args.rekeyBase.slice();
70
- this.transcriptHash = args.transcriptHash;
71
- this.sendDir = args.sendDir;
72
- this.recvDir = args.recvDir;
73
- this.sendSeq = args.sendSeq ?? 1n;
74
- this.recvSeq = args.recvSeq ?? 1n;
75
- void this.readLoop();
76
- void this.sendLoop();
77
- }
78
- // write splits payloads into record-sized chunks and queues them for send.
79
- async write(plaintext) {
80
- if (plaintext.length === 0)
81
- return;
82
- await this.enqueueSend("app", plaintext);
83
- }
84
- // read resolves with the next plaintext chunk or throws on errors/close.
85
- async read() {
86
- while (true) {
87
- if (this.recvQueueHead < this.recvQueue.length) {
88
- const b = this.recvQueue[this.recvQueueHead];
89
- this.recvQueueHead++;
90
- if (this.recvQueueHead === this.recvQueue.length) {
91
- this.recvQueue = [];
92
- this.recvQueueHead = 0;
93
- }
94
- else if (this.recvQueueHead > 1024 && this.recvQueueHead * 2 > this.recvQueue.length) {
95
- this.recvQueue.splice(0, this.recvQueueHead);
96
- this.recvQueueHead = 0;
97
- }
98
- this.recvQueueBytes -= b.length;
99
- return b;
100
- }
101
- if (this.readErr != null)
102
- throw this.readErr;
103
- if (this.closed)
104
- throw new Error("closed");
105
- await new Promise((resolve) => this.recvWaiters.push(resolve));
106
- }
107
- }
108
- // close shuts down the transport and rejects any pending senders.
109
- close() {
110
- if (this.closed)
111
- return;
112
- this.closed = true;
113
- this.sendClosed = true;
114
- this.rejectQueuedSenders(this.sendErr ?? new Error("closed"));
115
- this.wakeSendWaiters();
116
- const ws = this.recvWaiters;
117
- this.recvWaiters = [];
118
- for (const w of ws)
119
- w();
120
- try {
121
- this.transport.close();
122
- }
123
- finally {
124
- this.clearKeyMaterial();
125
- }
126
- }
127
- // sendPing emits a keepalive record.
128
- async sendPing() {
129
- await this.enqueueSend("ping");
130
- }
131
- // rekeyNow emits a rekey record and advances the send key.
132
- async rekeyNow() {
133
- await this.enqueueSend("rekey");
134
- }
135
- enqueueSend(kind, payload) {
136
- if (this.sendErr != null)
137
- return Promise.reject(this.sendErr);
138
- if (this.closed || this.sendClosed)
139
- return Promise.reject(new Error("closed"));
140
- const bufferedBytes = payload?.byteLength ?? 0;
141
- if (this.sendQueueBytes + bufferedBytes > this.maxOutboundBufferedBytes) {
142
- return Promise.reject(new Error("secure channel outbound buffer exceeded"));
143
- }
144
- return new Promise((resolve, reject) => {
145
- if (this.sendErr != null) {
146
- reject(this.sendErr);
147
- return;
148
- }
149
- if (this.closed || this.sendClosed) {
150
- reject(new Error("closed"));
151
- return;
152
- }
153
- if (this.sendQueueBytes + bufferedBytes > this.maxOutboundBufferedBytes) {
154
- reject(new Error("secure channel outbound buffer exceeded"));
155
- return;
156
- }
157
- const retainedPayload = payload?.slice();
158
- const req = retainedPayload === undefined
159
- ? { kind, bufferedBytes, resolve, reject }
160
- : { kind, payload: retainedPayload, bufferedBytes, resolve, reject };
161
- this.sendQueueBytes += bufferedBytes;
162
- this.sendQueue.push(req);
163
- const w = this.shiftSendWaiter();
164
- if (w != null)
165
- w();
166
- });
167
- }
168
- async nextSend() {
169
- const immediate = this.dequeueSend();
170
- if (immediate != null)
171
- return immediate;
172
- if (this.closed || this.sendClosed)
173
- return null;
174
- return await new Promise((resolve) => {
175
- this.sendWaiters.push(() => resolve(this.dequeueSend()));
176
- });
177
- }
178
- dequeueSend() {
179
- if (this.sendQueueHead >= this.sendQueue.length)
180
- return null;
181
- const req = this.sendQueue[this.sendQueueHead];
182
- this.sendQueueHead++;
183
- if (this.sendQueueHead === this.sendQueue.length) {
184
- this.sendQueue = [];
185
- this.sendQueueHead = 0;
186
- }
187
- else if (this.sendQueueHead > 1024 && this.sendQueueHead * 2 > this.sendQueue.length) {
188
- this.sendQueue.splice(0, this.sendQueueHead);
189
- this.sendQueueHead = 0;
190
- }
191
- return req;
192
- }
193
- shiftSendWaiter() {
194
- if (this.sendWaitersHead >= this.sendWaiters.length)
195
- return undefined;
196
- const w = this.sendWaiters[this.sendWaitersHead];
197
- this.sendWaitersHead++;
198
- if (this.sendWaitersHead === this.sendWaiters.length) {
199
- this.sendWaiters = [];
200
- this.sendWaitersHead = 0;
201
- }
202
- else if (this.sendWaitersHead > 1024 && this.sendWaitersHead * 2 > this.sendWaiters.length) {
203
- this.sendWaiters.splice(0, this.sendWaitersHead);
204
- this.sendWaitersHead = 0;
205
- }
206
- return w;
207
- }
208
- wakeSendWaiters() {
209
- const ws = this.sendWaiters;
210
- const start = this.sendWaitersHead;
211
- this.sendWaiters = [];
212
- this.sendWaitersHead = 0;
213
- for (let i = start; i < ws.length; i++)
214
- ws[i]();
215
- }
216
- rejectQueuedSenders(err) {
217
- const queued = this.sendQueue;
218
- const start = this.sendQueueHead;
219
- this.sendQueue = [];
220
- this.sendQueueHead = 0;
221
- for (let i = start; i < queued.length; i++) {
222
- const req = queued[i];
223
- this.sendQueueBytes = Math.max(0, this.sendQueueBytes - req.bufferedBytes);
224
- req.reject(err);
225
- }
226
- }
227
- failSend(err) {
228
- if (this.sendErr != null)
229
- return;
230
- this.sendErr = err;
231
- this.rejectQueuedSenders(err);
232
- this.wakeSendWaiters();
233
- }
234
- reserveSendSeq() {
235
- if (this.sendSeq >= maxRecordSeq) {
236
- const err = new RecordSeqExhaustedError();
237
- this.failSend(err);
238
- throw err;
239
- }
240
- const seq = this.sendSeq;
241
- this.sendSeq++;
242
- return seq;
243
- }
244
- async sendLoop() {
245
- while (true) {
246
- const req = await this.nextSend();
247
- if (req == null)
248
- return;
249
- try {
250
- if (this.sendErr != null) {
251
- req.reject(this.sendErr);
252
- continue;
253
- }
254
- if (this.closed || this.sendClosed) {
255
- req.reject(new Error("closed"));
256
- continue;
257
- }
258
- let frame;
259
- if (req.kind === "app") {
260
- const payload = req.payload ?? new Uint8Array();
261
- for (let offset = 0; offset < payload.length; offset += this.outboundRecordChunkBytes) {
262
- if (this.closed || this.sendClosed)
263
- throw new Error("closed");
264
- const chunk = payload.subarray(offset, Math.min(payload.length, offset + this.outboundRecordChunkBytes));
265
- const seq = this.reserveSendSeq();
266
- frame = encryptRecord(this.sendKey, this.sendNoncePrefix, RECORD_FLAG_APP, seq, chunk, this.maxRecordBytes);
267
- await this.transport.writeBinary(frame);
268
- }
269
- req.resolve();
270
- continue;
271
- }
272
- else if (req.kind === "ping") {
273
- const seq = this.reserveSendSeq();
274
- frame = encryptRecord(this.sendKey, this.sendNoncePrefix, RECORD_FLAG_PING, seq, new Uint8Array(), this.maxRecordBytes);
275
- }
276
- else {
277
- const seq = this.reserveSendSeq();
278
- frame = encryptRecord(this.sendKey, this.sendNoncePrefix, RECORD_FLAG_REKEY, seq, new Uint8Array(), this.maxRecordBytes);
279
- // Update the send key after enqueuing the rekey frame.
280
- this.sendKey = deriveRekeyKey(this.rekeyBase, this.transcriptHash, seq, this.sendDir);
281
- }
282
- await this.transport.writeBinary(frame);
283
- req.resolve();
284
- }
285
- catch (e) {
286
- req.reject(e);
287
- this.failSend(e);
288
- this.close();
289
- return;
290
- }
291
- finally {
292
- this.sendQueueBytes = Math.max(0, this.sendQueueBytes - req.bufferedBytes);
293
- }
294
- }
295
- }
296
- async readLoop() {
297
- try {
298
- while (!this.closed) {
299
- const frame = await this.transport.readBinary();
300
- if (this.closed)
301
- return;
302
- const { flags, seq, plaintext } = decryptRecord(this.recvKey, this.recvNoncePrefix, frame, this.recvSeq, this.maxRecordBytes);
303
- if (seq >= maxRecordSeq) {
304
- throw new RecordSeqExhaustedError();
305
- }
306
- this.recvSeq = seq + 1n;
307
- if (flags === RECORD_FLAG_APP) {
308
- if (this.maxInboundBufferedBytes > 0 && this.recvQueueBytes + plaintext.length > this.maxInboundBufferedBytes) {
309
- throw new Error("recv buffer exceeded");
310
- }
311
- this.recvQueue.push(plaintext);
312
- this.recvQueueBytes += plaintext.length;
313
- const ws = this.recvWaiters;
314
- this.recvWaiters = [];
315
- for (const w of ws)
316
- w();
317
- continue;
318
- }
319
- if (flags === RECORD_FLAG_PING)
320
- continue;
321
- if (flags === RECORD_FLAG_REKEY) {
322
- this.recvKey = deriveRekeyKey(this.rekeyBase, this.transcriptHash, seq, this.recvDir);
323
- continue;
324
- }
325
- throw new Error(`unknown record flag ${flags}`);
326
- }
327
- }
328
- catch (e) {
329
- this.readErr = e;
330
- const ws = this.recvWaiters;
331
- this.recvWaiters = [];
332
- for (const w of ws)
333
- w();
334
- this.close();
335
- }
336
- }
337
- clearKeyMaterial() {
338
- this.sendKey.fill(0);
339
- this.recvKey.fill(0);
340
- this.rekeyBase.fill(0);
341
- }
342
- }
@@ -1,23 +0,0 @@
1
- export type TranscriptInputs = Readonly<{
2
- /** Protocol version byte used in the transcript. */
3
- version: number;
4
- /** Numeric suite identifier (see e2ee suite). */
5
- suite: number;
6
- /** Role byte (client=1, server=2). */
7
- role: number;
8
- /** Client feature bitset. */
9
- clientFeatures: number;
10
- /** Server feature bitset. */
11
- serverFeatures: number;
12
- /** Channel identifier shared by both endpoints. */
13
- channelId: string;
14
- /** Client nonce (32 bytes). */
15
- nonceC: Uint8Array;
16
- /** Server nonce (32 bytes). */
17
- nonceS: Uint8Array;
18
- /** Client ephemeral public key bytes. */
19
- clientEphPub: Uint8Array;
20
- /** Server ephemeral public key bytes. */
21
- serverEphPub: Uint8Array;
22
- }>;
23
- export declare function transcriptHash(inputs: TranscriptInputs): Uint8Array;
@@ -1,31 +0,0 @@
1
- import { sha256 } from "@noble/hashes/sha256";
2
- import { concatBytes, u16be, u32be } from "../utils/bin.js";
3
- const te = new TextEncoder();
4
- // transcriptHash computes the SHA-256 hash of the handshake transcript.
5
- export function transcriptHash(inputs) {
6
- if (inputs.nonceC.length !== 32 || inputs.nonceS.length !== 32)
7
- throw new Error("nonce must be 32 bytes");
8
- const channelIdBytes = te.encode(inputs.channelId);
9
- if (channelIdBytes.length > 0xffff)
10
- throw new Error("channel_id too long");
11
- if (inputs.clientEphPub.length > 0xffff || inputs.serverEphPub.length > 0xffff)
12
- throw new Error("pub too long");
13
- const prefix = te.encode("flowersec-e2ee-v1");
14
- const body = concatBytes([
15
- prefix,
16
- new Uint8Array([inputs.version & 0xff]),
17
- u16be(inputs.suite),
18
- new Uint8Array([inputs.role & 0xff]),
19
- u32be(inputs.clientFeatures >>> 0),
20
- u32be(inputs.serverFeatures >>> 0),
21
- u16be(channelIdBytes.length),
22
- channelIdBytes,
23
- inputs.nonceC,
24
- inputs.nonceS,
25
- u16be(inputs.clientEphPub.length),
26
- inputs.clientEphPub,
27
- u16be(inputs.serverEphPub.length),
28
- inputs.serverEphPub
29
- ]);
30
- return sha256(body);
31
- }
@@ -1,84 +0,0 @@
1
- import { type TransportSecurityPolicy } from "../client-connect/transportSecurity.js";
2
- import { serverHandshake, ServerHandshakeCache, type Suite } from "../e2ee/handshake.js";
3
- import { type YamuxLimits } from "../yamux/session.js";
4
- import type { YamuxStream } from "../yamux/stream.js";
5
- import { type RpcRouter, type RpcServerOptions } from "../rpc/server.js";
6
- import { type WebSocketLike, type WebSocketLimits } from "../ws-client/binaryTransport.js";
7
- export type { Suite } from "../e2ee/handshake.js";
8
- export type EndpointPath = "direct" | "tunnel";
9
- export type DirectHandshakeInit = Readonly<{
10
- channelId: string;
11
- version: number;
12
- suite: Suite;
13
- clientFeatures: number;
14
- }>;
15
- export type DirectHandshakeCredential = Readonly<{
16
- psk: Uint8Array | string;
17
- initExpireAtUnixS: number;
18
- commitAuthenticated?: () => void | Promise<void>;
19
- }>;
20
- export type DirectCredentialResolver = (init: DirectHandshakeInit) => DirectHandshakeCredential | Promise<DirectHandshakeCredential>;
21
- export type EndpointOptions = Readonly<{
22
- signal?: AbortSignal;
23
- handshakeTimeoutMs?: number;
24
- handshakeClockSkewMs?: number;
25
- serverFeatures?: number;
26
- maxHandshakePayload?: number;
27
- maxRecordBytes?: number;
28
- maxBufferedBytes?: number;
29
- maxOutboundBufferedBytes?: number;
30
- outboundRecordChunkBytes?: number;
31
- webSocketLimits?: Partial<WebSocketLimits>;
32
- yamuxLimits?: Partial<YamuxLimits>;
33
- handshakeCache?: ServerHandshakeCache;
34
- }>;
35
- export type DirectAcceptOptions = EndpointOptions & Readonly<{
36
- secureTransport?: boolean;
37
- transportSecurityPolicy?: TransportSecurityPolicy;
38
- }>;
39
- export type TunnelEndpointOptions = EndpointOptions & Readonly<{
40
- origin: string;
41
- connectTimeoutMs?: number;
42
- endpointInstanceId?: string;
43
- wsFactory: (url: string, origin: string) => WebSocketLike;
44
- transportSecurityPolicy?: TransportSecurityPolicy;
45
- }>;
46
- export type EndpointStream = Readonly<{
47
- kind: string;
48
- stream: YamuxStream;
49
- }>;
50
- export declare class Session {
51
- private readonly secure;
52
- private readonly mux;
53
- readonly path: EndpointPath;
54
- readonly endpointInstanceId: string | undefined;
55
- private readonly streams;
56
- private readonly waiters;
57
- private terminalError;
58
- private constructor();
59
- static create(path: EndpointPath, secure: Awaited<ReturnType<typeof serverHandshake>>, options?: Readonly<{
60
- yamuxLimits?: Partial<YamuxLimits>;
61
- endpointInstanceId?: string;
62
- }>): Session;
63
- openStream(kind: string, options?: Readonly<{
64
- signal?: AbortSignal;
65
- }>): Promise<YamuxStream>;
66
- acceptStream(options?: Readonly<{
67
- signal?: AbortSignal;
68
- }>): Promise<EndpointStream>;
69
- serveRPC(router: RpcRouter, options?: RpcServerOptions & Readonly<{
70
- signal?: AbortSignal;
71
- }>): Promise<void>;
72
- probeLiveness(timeoutMs?: 10000): Promise<number>;
73
- rekey(): Promise<void>;
74
- close(): void;
75
- private pushStream;
76
- private acceptRawStream;
77
- private fail;
78
- }
79
- export declare function acceptDirect(websocket: WebSocketLike, handshake: Readonly<{
80
- channelId: string;
81
- suite: Suite;
82
- }> & DirectHandshakeCredential, options?: DirectAcceptOptions): Promise<Session>;
83
- export declare function acceptDirectResolved(websocket: WebSocketLike, resolver: DirectCredentialResolver, options?: DirectAcceptOptions): Promise<Session>;
84
- export declare function connectTunnel(grantInput: unknown, options: TunnelEndpointOptions): Promise<Session>;