werift 0.22.9 → 0.24.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 (173) hide show
  1. package/README.md +46 -0
  2. package/lib/common/src/transport.d.ts +22 -9
  3. package/lib/common/src/transport.js +152 -25
  4. package/lib/common/src/transport.js.map +1 -1
  5. package/lib/dtls/src/flight/server/flight6.js +12 -2
  6. package/lib/dtls/src/flight/server/flight6.js.map +1 -1
  7. package/lib/dtls/src/server.js +6 -1
  8. package/lib/dtls/src/server.js.map +1 -1
  9. package/lib/dtls/src/socket.d.ts +1 -0
  10. package/lib/dtls/src/socket.js +3 -0
  11. package/lib/dtls/src/socket.js.map +1 -1
  12. package/lib/ice/src/candidate.d.ts +16 -1
  13. package/lib/ice/src/candidate.js +99 -15
  14. package/lib/ice/src/candidate.js.map +1 -1
  15. package/lib/ice/src/ice.d.ts +2 -0
  16. package/lib/ice/src/ice.js +171 -41
  17. package/lib/ice/src/ice.js.map +1 -1
  18. package/lib/ice/src/iceBase.d.ts +23 -2
  19. package/lib/ice/src/iceBase.js +63 -1
  20. package/lib/ice/src/iceBase.js.map +1 -1
  21. package/lib/ice/src/index.d.ts +2 -0
  22. package/lib/ice/src/index.js +2 -0
  23. package/lib/ice/src/index.js.map +1 -1
  24. package/lib/ice/src/stun/const.d.ts +1 -26
  25. package/lib/ice/src/stun/const.js +15 -54
  26. package/lib/ice/src/stun/const.js.map +1 -1
  27. package/lib/ice/src/stun/message.d.ts +1 -25
  28. package/lib/ice/src/stun/message.js +15 -149
  29. package/lib/ice/src/stun/message.js.map +1 -1
  30. package/lib/ice/src/stun/protocol.d.ts +1 -1
  31. package/lib/ice/src/stun/protocol.js +2 -2
  32. package/lib/ice/src/stun/protocol.js.map +1 -1
  33. package/lib/ice/src/stun/tcpFrame.d.ts +5 -0
  34. package/lib/ice/src/stun/tcpFrame.js +26 -0
  35. package/lib/ice/src/stun/tcpFrame.js.map +1 -0
  36. package/lib/ice/src/stun/tcpProtocol.d.ts +51 -0
  37. package/lib/ice/src/stun/tcpProtocol.js +326 -0
  38. package/lib/ice/src/stun/tcpProtocol.js.map +1 -0
  39. package/lib/ice/src/stun/transaction.d.ts +2 -1
  40. package/lib/ice/src/stun/transaction.js +9 -3
  41. package/lib/ice/src/stun/transaction.js.map +1 -1
  42. package/lib/ice/src/turn/frame.d.ts +1 -0
  43. package/lib/ice/src/turn/frame.js +18 -0
  44. package/lib/ice/src/turn/frame.js.map +1 -0
  45. package/lib/ice/src/turn/protocol.d.ts +9 -7
  46. package/lib/ice/src/turn/protocol.js +32 -44
  47. package/lib/ice/src/turn/protocol.js.map +1 -1
  48. package/lib/ice/src/types/model.d.ts +1 -1
  49. package/lib/ice/src/types/model.js.map +1 -1
  50. package/lib/{ice → ice-server}/src/stun/attributes.d.ts +12 -5
  51. package/lib/{ice → ice-server}/src/stun/attributes.js +60 -19
  52. package/lib/ice-server/src/stun/attributes.js.map +1 -0
  53. package/lib/ice-server/src/stun/const.d.ts +28 -0
  54. package/lib/ice-server/src/stun/const.js +88 -0
  55. package/lib/ice-server/src/stun/const.js.map +1 -0
  56. package/lib/ice-server/src/stun/message.d.ts +37 -0
  57. package/lib/ice-server/src/stun/message.js +190 -0
  58. package/lib/ice-server/src/stun/message.js.map +1 -0
  59. package/lib/ice-server/src/turn/auth.d.ts +1 -0
  60. package/lib/ice-server/src/turn/auth.js +10 -0
  61. package/lib/ice-server/src/turn/auth.js.map +1 -0
  62. package/lib/ice-server/src/turn/frame.d.ts +13 -0
  63. package/lib/ice-server/src/turn/frame.js +69 -0
  64. package/lib/ice-server/src/turn/frame.js.map +1 -0
  65. package/lib/index.mjs +3075 -883
  66. package/lib/nonstandard/index.mjs +1964 -447
  67. package/lib/rtp/src/extra/container/mp4/container.d.ts +9 -6
  68. package/lib/rtp/src/extra/container/mp4/container.js +258 -173
  69. package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
  70. package/lib/rtp/src/extra/container/mp4/h264.d.ts +1 -0
  71. package/lib/rtp/src/extra/container/mp4/h264.js +13 -0
  72. package/lib/rtp/src/extra/container/mp4/h264.js.map +1 -1
  73. package/lib/rtp/src/extra/processor/mp4.d.ts +11 -7
  74. package/lib/rtp/src/extra/processor/mp4.js +115 -60
  75. package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
  76. package/lib/rtp/src/extra/processor/mp4Callback.d.ts +2 -3
  77. package/lib/rtp/src/extra/processor/mp4Callback.js +5 -3
  78. package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
  79. package/lib/rtp/src/index.d.ts +1 -0
  80. package/lib/rtp/src/index.js +1 -0
  81. package/lib/rtp/src/index.js.map +1 -1
  82. package/lib/rtp/src/srtp/cipher/ctr.d.ts +3 -3
  83. package/lib/rtp/src/srtp/cipher/ctr.js +25 -14
  84. package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
  85. package/lib/rtp/src/srtp/cipher/gcm.d.ts +3 -3
  86. package/lib/rtp/src/srtp/cipher/gcm.js +57 -20
  87. package/lib/rtp/src/srtp/cipher/gcm.js.map +1 -1
  88. package/lib/rtp/src/srtp/cipher/index.d.ts +1 -1
  89. package/lib/rtp/src/srtp/cipher/index.js +1 -1
  90. package/lib/rtp/src/srtp/cipher/index.js.map +1 -1
  91. package/lib/rtp/src/srtp/context/srtp.d.ts +2 -1
  92. package/lib/rtp/src/srtp/context/srtp.js +22 -5
  93. package/lib/rtp/src/srtp/context/srtp.js.map +1 -1
  94. package/lib/rtp/src/srtp/error.d.ts +3 -0
  95. package/lib/rtp/src/srtp/error.js +11 -0
  96. package/lib/rtp/src/srtp/error.js.map +1 -0
  97. package/lib/rtp/src/srtp/packet.d.ts +5 -0
  98. package/lib/rtp/src/srtp/packet.js +48 -0
  99. package/lib/rtp/src/srtp/packet.js.map +1 -0
  100. package/lib/webrtc/src/dataChannel.d.ts +4 -2
  101. package/lib/webrtc/src/dataChannel.js +14 -4
  102. package/lib/webrtc/src/dataChannel.js.map +1 -1
  103. package/lib/webrtc/src/errors.d.ts +3 -0
  104. package/lib/webrtc/src/errors.js +11 -0
  105. package/lib/webrtc/src/errors.js.map +1 -0
  106. package/lib/webrtc/src/helper.d.ts +5 -1
  107. package/lib/webrtc/src/helper.js +33 -1
  108. package/lib/webrtc/src/helper.js.map +1 -1
  109. package/lib/webrtc/src/media/receiver/statistics.d.ts +4 -1
  110. package/lib/webrtc/src/media/receiver/statistics.js +22 -0
  111. package/lib/webrtc/src/media/receiver/statistics.js.map +1 -1
  112. package/lib/webrtc/src/media/rtpReceiver.d.ts +15 -2
  113. package/lib/webrtc/src/media/rtpReceiver.js +135 -20
  114. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  115. package/lib/webrtc/src/media/rtpSender.d.ts +32 -7
  116. package/lib/webrtc/src/media/rtpSender.js +177 -28
  117. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  118. package/lib/webrtc/src/media/rtpTransceiver.d.ts +13 -4
  119. package/lib/webrtc/src/media/rtpTransceiver.js +26 -5
  120. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  121. package/lib/webrtc/src/media/stats.d.ts +15 -1
  122. package/lib/webrtc/src/media/stats.js +55 -1
  123. package/lib/webrtc/src/media/stats.js.map +1 -1
  124. package/lib/webrtc/src/media/track.d.ts +2 -1
  125. package/lib/webrtc/src/media/track.js +7 -1
  126. package/lib/webrtc/src/media/track.js.map +1 -1
  127. package/lib/webrtc/src/nonstandard/dummyMedia.d.ts +19 -0
  128. package/lib/webrtc/src/nonstandard/dummyMedia.js +157 -0
  129. package/lib/webrtc/src/nonstandard/dummyMedia.js.map +1 -0
  130. package/lib/webrtc/src/nonstandard/navigator.d.ts +18 -8
  131. package/lib/webrtc/src/nonstandard/navigator.js +96 -32
  132. package/lib/webrtc/src/nonstandard/navigator.js.map +1 -1
  133. package/lib/webrtc/src/nonstandard/userMedia/packetizer.d.ts +16 -0
  134. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js +360 -0
  135. package/lib/webrtc/src/nonstandard/userMedia/packetizer.js.map +1 -0
  136. package/lib/webrtc/src/nonstandard/userMedia.d.ts +71 -31
  137. package/lib/webrtc/src/nonstandard/userMedia.js +454 -108
  138. package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
  139. package/lib/webrtc/src/peerConnection.d.ts +185 -49
  140. package/lib/webrtc/src/peerConnection.js +477 -107
  141. package/lib/webrtc/src/peerConnection.js.map +1 -1
  142. package/lib/webrtc/src/sctpManager.d.ts +2 -2
  143. package/lib/webrtc/src/sctpManager.js +30 -9
  144. package/lib/webrtc/src/sctpManager.js.map +1 -1
  145. package/lib/webrtc/src/sdp.d.ts +10 -7
  146. package/lib/webrtc/src/sdp.js +39 -9
  147. package/lib/webrtc/src/sdp.js.map +1 -1
  148. package/lib/webrtc/src/sdpManager.d.ts +5 -4
  149. package/lib/webrtc/src/sdpManager.js +53 -31
  150. package/lib/webrtc/src/sdpManager.js.map +1 -1
  151. package/lib/webrtc/src/secureTransportManager.d.ts +13 -4
  152. package/lib/webrtc/src/secureTransportManager.js +101 -23
  153. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  154. package/lib/webrtc/src/transceiverManager.d.ts +5 -4
  155. package/lib/webrtc/src/transceiverManager.js +64 -64
  156. package/lib/webrtc/src/transceiverManager.js.map +1 -1
  157. package/lib/webrtc/src/transport/dtls.d.ts +16 -4
  158. package/lib/webrtc/src/transport/dtls.js +208 -35
  159. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  160. package/lib/webrtc/src/transport/ice.d.ts +21 -3
  161. package/lib/webrtc/src/transport/ice.js +159 -30
  162. package/lib/webrtc/src/transport/ice.js.map +1 -1
  163. package/lib/webrtc/src/transport/sctp.d.ts +10 -3
  164. package/lib/webrtc/src/transport/sctp.js +44 -13
  165. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  166. package/lib/webrtc/src/utils.d.ts +14 -4
  167. package/lib/webrtc/src/utils.js +138 -16
  168. package/lib/webrtc/src/utils.js.map +1 -1
  169. package/package.json +7 -4
  170. package/lib/ice/src/stun/attributes.js.map +0 -1
  171. package/lib/rtp/src/extra/container/mp4/mp4box.d.ts +0 -5
  172. package/lib/rtp/src/extra/container/mp4/mp4box.js +0 -32
  173. package/lib/rtp/src/extra/container/mp4/mp4box.js.map +0 -1
@@ -5,11 +5,33 @@ const x509_1 = require("@fidm/x509");
5
5
  const crypto_1 = require("crypto");
6
6
  const promises_1 = require("timers/promises");
7
7
  const common_1 = require("../imports/common");
8
+ const helper_1 = require("../helper");
8
9
  const dtls_1 = require("../imports/dtls");
9
10
  const rtp_1 = require("../imports/rtp");
10
11
  const stats_1 = require("../media/stats");
11
12
  const utils_1 = require("../utils");
12
13
  const log = (0, rtp_1.debug)("werift:packages/webrtc/src/transport/dtls.ts");
14
+ function formatDtlsVersion(version) {
15
+ if (!version) {
16
+ return;
17
+ }
18
+ if (version.major === 0xfe && version.minor === 0xfd) {
19
+ return "DTLS 1.2";
20
+ }
21
+ if (version.major === 0xfe && version.minor === 0xff) {
22
+ return "DTLS 1.0";
23
+ }
24
+ }
25
+ function formatSrtpCipher(profile) {
26
+ switch (profile) {
27
+ case 0x0001:
28
+ return "AES_CM_128_HMAC_SHA1_80";
29
+ case 0x0007:
30
+ return "AEAD_AES_128_GCM";
31
+ default:
32
+ return;
33
+ }
34
+ }
13
35
  class RTCDtlsTransport {
14
36
  constructor(config, iceTransport, localCertificate, srtpProfiles = []) {
15
37
  Object.defineProperty(this, "config", {
@@ -133,19 +155,53 @@ class RTCDtlsTransport {
133
155
  writable: true,
134
156
  value: new common_1.Event()
135
157
  });
158
+ Object.defineProperty(this, "events", {
159
+ enumerable: true,
160
+ configurable: true,
161
+ writable: true,
162
+ value: new helper_1.EventTarget()
163
+ });
164
+ Object.defineProperty(this, "onstatechange", {
165
+ enumerable: true,
166
+ configurable: true,
167
+ writable: true,
168
+ value: void 0
169
+ });
136
170
  Object.defineProperty(this, "remoteParameters", {
137
171
  enumerable: true,
138
172
  configurable: true,
139
173
  writable: true,
140
174
  value: void 0
141
175
  });
176
+ Object.defineProperty(this, "addEventListener", {
177
+ enumerable: true,
178
+ configurable: true,
179
+ writable: true,
180
+ value: (type, listener, options) => {
181
+ this.events.addEventListener(type, listener, options);
182
+ }
183
+ });
184
+ Object.defineProperty(this, "removeEventListener", {
185
+ enumerable: true,
186
+ configurable: true,
187
+ writable: true,
188
+ value: (type, listener) => {
189
+ this.events.removeEventListener(type, listener);
190
+ }
191
+ });
192
+ Object.defineProperty(this, "dispatchEvent", {
193
+ enumerable: true,
194
+ configurable: true,
195
+ writable: true,
196
+ value: (event) => this.events.dispatchEvent(event)
197
+ });
142
198
  Object.defineProperty(this, "sendData", {
143
199
  enumerable: true,
144
200
  configurable: true,
145
201
  writable: true,
146
202
  value: async (data) => {
147
- if (this.config.debug.outboundPacketLoss &&
148
- this.config.debug.outboundPacketLoss / 100 < Math.random()) {
203
+ if (this.config.debug?.outboundPacketLoss &&
204
+ this.config.debug?.outboundPacketLoss / 100 < Math.random()) {
149
205
  return;
150
206
  }
151
207
  if (!this.dtls) {
@@ -177,13 +233,21 @@ class RTCDtlsTransport {
177
233
  return this.localCertificatePromise;
178
234
  }
179
235
  setRemoteParams(remoteParameters) {
180
- this.remoteParameters = remoteParameters;
236
+ const fingerprints = deduplicateFingerprints([
237
+ ...(this.remoteParameters?.fingerprints ?? []),
238
+ ...remoteParameters.fingerprints,
239
+ ]);
240
+ const role = remoteParameters.role === "auto" && this.remoteParameters?.role
241
+ ? this.remoteParameters.role
242
+ : remoteParameters.role;
243
+ this.remoteParameters = new RTCDtlsParameters(fingerprints, role);
181
244
  }
182
245
  async start() {
183
246
  if (this.state !== "new") {
184
247
  throw new Error("state must be new");
185
248
  }
186
- if (this.remoteParameters?.fingerprints.length === 0) {
249
+ if (!this.remoteParameters ||
250
+ this.remoteParameters.fingerprints.length === 0) {
187
251
  throw new Error("remote fingerprint not exist");
188
252
  }
189
253
  if (this.role === "auto") {
@@ -204,7 +268,7 @@ class RTCDtlsTransport {
204
268
  transport: createIceTransport(this.iceTransport.connection),
205
269
  srtpProfiles: this.srtpProfiles,
206
270
  extendedMasterSecret: true,
207
- // certificateRequest: true,
271
+ certificateRequest: true,
208
272
  });
209
273
  }
210
274
  else {
@@ -218,14 +282,16 @@ class RTCDtlsTransport {
218
282
  });
219
283
  }
220
284
  this.dtls.onData.subscribe((buf) => {
221
- if (this.config.debug.inboundPacketLoss &&
222
- this.config.debug.inboundPacketLoss / 100 < Math.random()) {
285
+ if (this.config.debug?.inboundPacketLoss &&
286
+ this.config.debug?.inboundPacketLoss / 100 < Math.random()) {
223
287
  return;
224
288
  }
225
289
  this.dataReceiver(buf);
226
290
  });
227
291
  this.dtls.onClose.subscribe(() => {
228
- this.setState("closed");
292
+ if (this.state !== "failed") {
293
+ this.setState("closed");
294
+ }
229
295
  });
230
296
  this.dtls.onConnect.once(r);
231
297
  this.dtls.onError.once((error) => {
@@ -242,16 +308,56 @@ class RTCDtlsTransport {
242
308
  });
243
309
  }
244
310
  });
311
+ try {
312
+ this.verifyRemoteCertificateFingerprint();
313
+ }
314
+ catch (error) {
315
+ this.setState("failed");
316
+ this.dtls?.close();
317
+ throw error;
318
+ }
245
319
  if (this.srtpProfiles.length > 0) {
246
320
  this.startSrtp();
247
321
  }
248
- this.dtls.onConnect.subscribe(() => {
249
- this.updateSrtpSession();
250
- this.setState("connected");
251
- });
252
322
  this.setState("connected");
253
323
  log("dtls connected");
254
324
  }
325
+ verifyRemoteCertificateFingerprint() {
326
+ if (!this.remoteParameters ||
327
+ this.remoteParameters.fingerprints.length === 0) {
328
+ throw new Error("remote fingerprint not exist");
329
+ }
330
+ const remoteCertificate = this.dtls?.remoteCertificate;
331
+ if (!remoteCertificate) {
332
+ throw new Error("remote certificate not available");
333
+ }
334
+ const supportedFingerprints = this.remoteParameters.fingerprints.flatMap(({ algorithm, value }) => {
335
+ const normalizedAlgorithm = (0, utils_1.normalizeFingerprintAlgorithm)(algorithm);
336
+ if (!normalizedAlgorithm) {
337
+ return [];
338
+ }
339
+ const normalizedValue = (0, utils_1.normalizeFingerprintValue)(value);
340
+ if (!normalizedValue) {
341
+ throw new Error("remote fingerprint value is empty");
342
+ }
343
+ return [{ normalizedAlgorithm, normalizedValue }];
344
+ });
345
+ if (supportedFingerprints.length === 0) {
346
+ throw new Error("no supported remote fingerprint algorithms");
347
+ }
348
+ const preferredAlgorithm = selectPreferredFingerprintAlgorithm(supportedFingerprints);
349
+ const expectedFingerprints = supportedFingerprints.filter(({ normalizedAlgorithm }) => normalizedAlgorithm === preferredAlgorithm);
350
+ const actualFingerprints = expectedFingerprints.reduce((acc, { normalizedAlgorithm }) => {
351
+ if (!acc.has(normalizedAlgorithm)) {
352
+ acc.set(normalizedAlgorithm, (0, utils_1.normalizeFingerprintValue)((0, utils_1.fingerprint)(remoteCertificate, normalizedAlgorithm)));
353
+ }
354
+ return acc;
355
+ }, new Map());
356
+ const matched = expectedFingerprints.some(({ normalizedAlgorithm, normalizedValue }) => actualFingerprints.get(normalizedAlgorithm) === normalizedValue);
357
+ if (!matched) {
358
+ throw new Error("remote certificate fingerprint mismatch");
359
+ }
360
+ }
255
361
  updateSrtpSession() {
256
362
  if (!this.dtls)
257
363
  throw new Error();
@@ -279,8 +385,8 @@ class RTCDtlsTransport {
279
385
  this.srtpStarted = true;
280
386
  this.updateSrtpSession();
281
387
  this.iceTransport.connection.onData.subscribe((data) => {
282
- if (this.config.debug.inboundPacketLoss &&
283
- this.config.debug.inboundPacketLoss / 100 < Math.random()) {
388
+ if (this.config.debug?.inboundPacketLoss &&
389
+ this.config.debug?.inboundPacketLoss / 100 < Math.random()) {
284
390
  return;
285
391
  }
286
392
  if (!(0, rtp_1.isMedia)(data))
@@ -289,8 +395,25 @@ class RTCDtlsTransport {
289
395
  this.bytesReceived += data.length;
290
396
  this.packetsReceived++;
291
397
  if ((0, rtp_1.isRtcp)(data)) {
292
- const dec = this.srtcp.decrypt(data);
293
- const rtcpPackets = rtp_1.RtcpPacketConverter.deSerialize(dec);
398
+ let dec;
399
+ try {
400
+ dec = this.srtcp.decrypt(data);
401
+ }
402
+ catch (error) {
403
+ if (error instanceof rtp_1.SrtpAuthenticationError) {
404
+ log("dropping invalid SRTCP packet", error);
405
+ return;
406
+ }
407
+ throw error;
408
+ }
409
+ let rtcpPackets;
410
+ try {
411
+ rtcpPackets = rtp_1.RtcpPacketConverter.deSerialize(dec);
412
+ }
413
+ catch (error) {
414
+ log("dropping malformed SRTCP packet", error);
415
+ return;
416
+ }
294
417
  for (const rtcp of rtcpPackets) {
295
418
  try {
296
419
  this.onRtcp.execute(rtcp);
@@ -301,8 +424,25 @@ class RTCDtlsTransport {
301
424
  }
302
425
  }
303
426
  else {
304
- const dec = this.srtp.decrypt(data);
305
- const rtp = rtp_1.RtpPacket.deSerialize(dec);
427
+ let dec;
428
+ try {
429
+ dec = this.srtp.decrypt(data);
430
+ }
431
+ catch (error) {
432
+ if (error instanceof rtp_1.SrtpAuthenticationError) {
433
+ log("dropping invalid SRTP packet", error);
434
+ return;
435
+ }
436
+ throw error;
437
+ }
438
+ let rtp;
439
+ try {
440
+ rtp = rtp_1.RtpPacket.deSerialize(dec);
441
+ }
442
+ catch (error) {
443
+ log("dropping malformed SRTP packet", error);
444
+ return;
445
+ }
306
446
  try {
307
447
  this.onRtp.execute(rtp);
308
448
  }
@@ -315,8 +455,8 @@ class RTCDtlsTransport {
315
455
  async sendRtp(payload, header) {
316
456
  try {
317
457
  const enc = this.srtp.encrypt(payload, header);
318
- if (this.config.debug.outboundPacketLoss &&
319
- this.config.debug.outboundPacketLoss / 100 < Math.random()) {
458
+ if (this.config.debug?.outboundPacketLoss &&
459
+ this.config.debug?.outboundPacketLoss / 100 < Math.random()) {
320
460
  return enc.length;
321
461
  }
322
462
  // Track statistics
@@ -333,8 +473,8 @@ class RTCDtlsTransport {
333
473
  async sendRtcp(packets) {
334
474
  const payload = Buffer.concat(packets.map((packet) => packet.serialize()));
335
475
  const enc = this.srtcp.encrypt(payload);
336
- if (this.config.debug.outboundPacketLoss &&
337
- this.config.debug.outboundPacketLoss / 100 < Math.random()) {
476
+ if (this.config.debug?.outboundPacketLoss &&
477
+ this.config.debug?.outboundPacketLoss / 100 < Math.random()) {
338
478
  return enc.length;
339
479
  }
340
480
  // Track statistics
@@ -342,19 +482,22 @@ class RTCDtlsTransport {
342
482
  this.packetsSent++;
343
483
  await this.iceTransport.connection.send(enc).catch(() => { });
344
484
  }
345
- setState(state) {
485
+ setState(state, emitEvent = true) {
346
486
  if (state != this.state) {
347
487
  this.state = state;
348
488
  this.onStateChange.execute(state);
489
+ if (emitEvent) {
490
+ this.onstatechange?.();
491
+ this.events.emit("statechange");
492
+ }
349
493
  }
350
494
  }
351
495
  async stop() {
352
- this.setState("closed");
496
+ this.setState("closed", false);
353
497
  // todo impl send alert
354
498
  await this.iceTransport.stop();
355
499
  }
356
- async getStats() {
357
- const timestamp = (0, stats_1.getStatsTimestamp)();
500
+ async getStats(timestamp = (0, stats_1.getStatsTimestamp)()) {
358
501
  const stats = [];
359
502
  const transportId = (0, stats_1.generateStatsId)("transport", this.id);
360
503
  // Transport stats
@@ -368,16 +511,24 @@ class RTCDtlsTransport {
368
511
  packetsReceived: this.packetsReceived,
369
512
  dtlsState: this.state,
370
513
  iceState: this.iceTransport.state,
514
+ iceRole: this.iceTransport.role === "unknown"
515
+ ? undefined
516
+ : this.iceTransport.role,
517
+ iceLocalUsernameFragment: this.iceTransport.localParameters.usernameFragment,
371
518
  selectedCandidatePairId: this.iceTransport.connection.nominated
372
- ? (0, stats_1.generateStatsId)("candidate-pair", this.iceTransport.connection.nominated.localCandidate.foundation, this.iceTransport.connection.nominated.remoteCandidate.foundation)
519
+ ? (0, stats_1.generateStatsId)("candidate-pair", this.iceTransport.connection.nominated.id)
373
520
  : undefined,
374
521
  localCertificateId: this.localCertificate
375
- ? (0, stats_1.generateStatsId)("certificate", "local")
522
+ ? (0, stats_1.generateStatsId)("certificate", this.id, "local")
376
523
  : undefined,
377
- remoteCertificateId: this.remoteParameters
378
- ? (0, stats_1.generateStatsId)("certificate", "remote")
524
+ remoteCertificateId: this.dtls?.remoteCertificate
525
+ ? (0, stats_1.generateStatsId)("certificate", this.id, "remote")
379
526
  : undefined,
380
527
  dtlsRole: this.role === "auto" ? undefined : this.role,
528
+ tlsVersion: formatDtlsVersion(this.dtls?.dtls.version),
529
+ dtlsCipher: this.dtls?.cipher.cipher?.name,
530
+ srtpCipher: formatSrtpCipher(this.dtls?.srtp.srtpProfile),
531
+ iceRestarts: this.iceTransport.iceRestarts,
381
532
  };
382
533
  stats.push(transportStats);
383
534
  // Certificate stats
@@ -386,7 +537,7 @@ class RTCDtlsTransport {
386
537
  if (fingerprints.length > 0) {
387
538
  const certStats = {
388
539
  type: "certificate",
389
- id: (0, stats_1.generateStatsId)("certificate", "local"),
540
+ id: (0, stats_1.generateStatsId)("certificate", this.id, "local"),
390
541
  timestamp,
391
542
  fingerprint: fingerprints[0].value,
392
543
  fingerprintAlgorithm: fingerprints[0].algorithm,
@@ -396,19 +547,20 @@ class RTCDtlsTransport {
396
547
  }
397
548
  }
398
549
  if (this.remoteParameters &&
399
- this.remoteParameters.fingerprints.length > 0) {
550
+ this.remoteParameters.fingerprints.length > 0 &&
551
+ this.dtls?.remoteCertificate) {
400
552
  const certStats = {
401
553
  type: "certificate",
402
- id: (0, stats_1.generateStatsId)("certificate", "remote"),
554
+ id: (0, stats_1.generateStatsId)("certificate", this.id, "remote"),
403
555
  timestamp,
404
556
  fingerprint: this.remoteParameters.fingerprints[0].value,
405
557
  fingerprintAlgorithm: this.remoteParameters.fingerprints[0].algorithm,
406
- base64Certificate: "", // Remote certificate content not available
558
+ base64Certificate: Buffer.from(this.dtls.remoteCertificate).toString("base64"),
407
559
  };
408
560
  stats.push(certStats);
409
561
  }
410
562
  // Get ICE stats
411
- const iceStats = await this.iceTransport.getStats();
563
+ const iceStats = await this.iceTransport.getStats(timestamp, transportId);
412
564
  stats.push(...iceStats);
413
565
  return stats;
414
566
  }
@@ -492,6 +644,27 @@ class RTCDtlsParameters {
492
644
  }
493
645
  }
494
646
  exports.RTCDtlsParameters = RTCDtlsParameters;
647
+ const deduplicateFingerprints = (fingerprints) => {
648
+ const seen = new Set();
649
+ return fingerprints.filter(({ algorithm, value }) => {
650
+ const key = `${(0, utils_1.normalizeFingerprintAlgorithm)(algorithm) ?? algorithm.trim().toLowerCase()}:${(0, utils_1.normalizeFingerprintValue)(value)}`;
651
+ if (seen.has(key)) {
652
+ return false;
653
+ }
654
+ seen.add(key);
655
+ return true;
656
+ });
657
+ };
658
+ const preferredFingerprintAlgorithms = [
659
+ "sha512",
660
+ "sha384",
661
+ "sha256",
662
+ "sha224",
663
+ "sha1",
664
+ ];
665
+ const selectPreferredFingerprintAlgorithm = (fingerprints) => {
666
+ return (preferredFingerprintAlgorithms.find((algorithm) => fingerprints.some(({ normalizedAlgorithm }) => normalizedAlgorithm === algorithm)) ?? fingerprints[0].normalizedAlgorithm);
667
+ };
495
668
  class IceTransport {
496
669
  constructor(ice) {
497
670
  Object.defineProperty(this, "ice", {
@@ -1 +1 @@
1
- {"version":3,"file":"dtls.js","sourceRoot":"","sources":["../../../../src/transport/dtls.ts"],"names":[],"mappings":"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","sourcesContent":["import { Certificate, PrivateKey } from \"@fidm/x509\";\n\nimport { randomUUID } from \"crypto\";\nimport { setTimeout } from \"timers/promises\";\nimport { Event, type Transport } from \"../imports/common\";\n\nimport type { AddressInfo } from \"net\";\nimport {\n CipherContext,\n DtlsClient,\n DtlsServer,\n type DtlsSocket,\n HashAlgorithm,\n NamedCurveAlgorithm,\n SignatureAlgorithm,\n type SignatureHash,\n} from \"../imports/dtls\";\nimport type { IceConnection } from \"../imports/ice\";\nimport {\n type RtcpPacket,\n RtcpPacketConverter,\n type RtpHeader,\n RtpPacket,\n SrtcpSession,\n type SrtpProfile,\n SrtpSession,\n debug,\n isMedia,\n isRtcp,\n keyLength,\n saltLength,\n} from \"../imports/rtp\";\nimport {\n type RTCCertificateStats,\n type RTCIceCandidatePairStats,\n type RTCIceCandidateStats,\n type RTCStats,\n type RTCTransportStats,\n generateStatsId,\n getStatsTimestamp,\n} from \"../media/stats\";\nimport type { PeerConfig } from \"../peerConnection\";\nimport { fingerprint, isDtls } from \"../utils\";\nimport type { RTCIceTransport } from \"./ice\";\n\nconst log = debug(\"werift:packages/webrtc/src/transport/dtls.ts\");\n\nexport interface DtlsTransportStats {\n bytesSent: number;\n bytesReceived: number;\n packetsSent: number;\n packetsReceived: number;\n}\n\nexport class RTCDtlsTransport implements DtlsTransportStats {\n id = randomUUID().toString();\n state: DtlsState = \"new\";\n role: DtlsRole = \"auto\";\n srtpStarted = false;\n transportSequenceNumber = 0;\n\n // Statistics tracking\n public bytesSent = 0;\n public bytesReceived = 0;\n public packetsSent = 0;\n public packetsReceived = 0;\n\n dataReceiver: (buf: Buffer) => void = () => {};\n dtls?: DtlsSocket;\n srtp!: SrtpSession;\n srtcp!: SrtcpSession;\n\n readonly onStateChange = new Event<[DtlsState]>();\n readonly onRtcp = new Event<[RtcpPacket]>();\n readonly onRtp = new Event<[RtpPacket]>();\n\n static localCertificate?: RTCCertificate;\n static localCertificatePromise?: Promise<RTCCertificate>;\n private remoteParameters?: RTCDtlsParameters;\n\n constructor(\n readonly config: PeerConfig,\n readonly iceTransport: RTCIceTransport,\n public localCertificate?: RTCCertificate,\n private readonly srtpProfiles: SrtpProfile[] = [],\n ) {\n this.localCertificate ??= RTCDtlsTransport.localCertificate;\n }\n\n get localParameters() {\n return new RTCDtlsParameters(\n this.localCertificate ? this.localCertificate.getFingerprints() : [],\n this.role,\n );\n }\n\n static async SetupCertificate() {\n if (this.localCertificate) {\n return this.localCertificate;\n }\n\n if (this.localCertificatePromise) {\n return this.localCertificatePromise;\n }\n\n this.localCertificatePromise = (async () => {\n const { certPem, keyPem, signatureHash } =\n await CipherContext.createSelfSignedCertificateWithKey(\n {\n signature: SignatureAlgorithm.ecdsa_3,\n hash: HashAlgorithm.sha256_4,\n },\n NamedCurveAlgorithm.secp256r1_23,\n );\n this.localCertificate = new RTCCertificate(\n keyPem,\n certPem,\n signatureHash,\n );\n return this.localCertificate;\n })();\n\n return this.localCertificatePromise;\n }\n\n setRemoteParams(remoteParameters: RTCDtlsParameters) {\n this.remoteParameters = remoteParameters;\n }\n\n async start() {\n if (this.state !== \"new\") {\n throw new Error(\"state must be new\");\n }\n if (this.remoteParameters?.fingerprints.length === 0) {\n throw new Error(\"remote fingerprint not exist\");\n }\n\n if (this.role === \"auto\") {\n if (this.iceTransport.role === \"controlling\") {\n this.role = \"server\";\n } else {\n this.role = \"client\";\n }\n }\n\n this.setState(\"connecting\");\n\n await new Promise<void>(async (r, f) => {\n if (this.role === \"server\") {\n this.dtls = new DtlsServer({\n cert: this.localCertificate?.certPem,\n key: this.localCertificate?.privateKey,\n signatureHash: this.localCertificate?.signatureHash,\n transport: createIceTransport(this.iceTransport.connection),\n srtpProfiles: this.srtpProfiles,\n extendedMasterSecret: true,\n // certificateRequest: true,\n });\n } else {\n this.dtls = new DtlsClient({\n cert: this.localCertificate?.certPem,\n key: this.localCertificate?.privateKey,\n signatureHash: this.localCertificate?.signatureHash,\n transport: createIceTransport(this.iceTransport.connection),\n srtpProfiles: this.srtpProfiles,\n extendedMasterSecret: true,\n });\n }\n this.dtls.onData.subscribe((buf) => {\n if (\n this.config.debug.inboundPacketLoss &&\n this.config.debug.inboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n this.dataReceiver(buf);\n });\n this.dtls.onClose.subscribe(() => {\n this.setState(\"closed\");\n });\n this.dtls.onConnect.once(r);\n this.dtls.onError.once((error) => {\n this.setState(\"failed\");\n log(\"dtls failed\", error);\n f(error);\n });\n\n if (this.dtls instanceof DtlsClient) {\n await setTimeout(100);\n this.dtls.connect().catch((error) => {\n this.setState(\"failed\");\n log(\"dtls connect failed\", error);\n f(error);\n });\n }\n });\n\n if (this.srtpProfiles.length > 0) {\n this.startSrtp();\n }\n this.dtls!.onConnect.subscribe(() => {\n this.updateSrtpSession();\n this.setState(\"connected\");\n });\n this.setState(\"connected\");\n\n log(\"dtls connected\");\n }\n\n updateSrtpSession() {\n if (!this.dtls) throw new Error();\n\n const profile = this.dtls.srtp.srtpProfile;\n if (!profile) {\n throw new Error(\"need srtpProfile\");\n }\n log(\"selected SRTP Profile\", profile);\n\n const { localKey, localSalt, remoteKey, remoteSalt } =\n this.dtls.extractSessionKeys(keyLength(profile), saltLength(profile));\n\n const config = {\n keys: {\n localMasterKey: localKey,\n localMasterSalt: localSalt,\n remoteMasterKey: remoteKey,\n remoteMasterSalt: remoteSalt,\n },\n profile,\n };\n this.srtp = new SrtpSession(config);\n this.srtcp = new SrtcpSession(config);\n }\n\n startSrtp() {\n if (this.srtpStarted) return;\n this.srtpStarted = true;\n\n this.updateSrtpSession();\n\n this.iceTransport.connection.onData.subscribe((data) => {\n if (\n this.config.debug.inboundPacketLoss &&\n this.config.debug.inboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n\n if (!isMedia(data)) return;\n\n // Track received data statistics\n this.bytesReceived += data.length;\n this.packetsReceived++;\n\n if (isRtcp(data)) {\n const dec = this.srtcp.decrypt(data);\n const rtcpPackets = RtcpPacketConverter.deSerialize(dec);\n for (const rtcp of rtcpPackets) {\n try {\n this.onRtcp.execute(rtcp);\n } catch (error) {\n log(\"RTCP error\", error);\n }\n }\n } else {\n const dec = this.srtp.decrypt(data);\n const rtp = RtpPacket.deSerialize(dec);\n try {\n this.onRtp.execute(rtp);\n } catch (error) {\n log(\"RTP error\", error);\n }\n }\n });\n }\n\n readonly sendData = async (data: Buffer) => {\n if (\n this.config.debug.outboundPacketLoss &&\n this.config.debug.outboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n\n if (!this.dtls) {\n throw new Error(\"dtls not established\");\n }\n await this.dtls.send(data);\n };\n\n async sendRtp(payload: Buffer, header: RtpHeader): Promise<number> {\n try {\n const enc = this.srtp.encrypt(payload, header);\n\n if (\n this.config.debug.outboundPacketLoss &&\n this.config.debug.outboundPacketLoss / 100 < Math.random()\n ) {\n return enc.length;\n }\n\n // Track statistics\n this.bytesSent += enc.length;\n this.packetsSent++;\n\n await this.iceTransport.connection.send(enc).catch(() => {});\n return enc.length;\n } catch (error) {\n log(\"failed to send\", error);\n return 0;\n }\n }\n\n async sendRtcp(packets: RtcpPacket[]) {\n const payload = Buffer.concat(packets.map((packet) => packet.serialize()));\n const enc = this.srtcp.encrypt(payload);\n\n if (\n this.config.debug.outboundPacketLoss &&\n this.config.debug.outboundPacketLoss / 100 < Math.random()\n ) {\n return enc.length;\n }\n\n // Track statistics\n this.bytesSent += enc.length;\n this.packetsSent++;\n\n await this.iceTransport.connection.send(enc).catch(() => {});\n }\n\n private setState(state: DtlsState) {\n if (state != this.state) {\n this.state = state;\n this.onStateChange.execute(state);\n }\n }\n\n async stop() {\n this.setState(\"closed\");\n // todo impl send alert\n await this.iceTransport.stop();\n }\n\n async getStats(): Promise<RTCStats[]> {\n const timestamp = getStatsTimestamp();\n const stats: RTCStats[] = [];\n\n const transportId = generateStatsId(\"transport\", this.id);\n\n // Transport stats\n const transportStats: RTCTransportStats = {\n type: \"transport\",\n id: transportId,\n timestamp,\n bytesSent: this.bytesSent,\n bytesReceived: this.bytesReceived,\n packetsSent: this.packetsSent,\n packetsReceived: this.packetsReceived,\n dtlsState: this.state,\n iceState: this.iceTransport.state,\n selectedCandidatePairId: this.iceTransport.connection.nominated\n ? generateStatsId(\n \"candidate-pair\",\n this.iceTransport.connection.nominated.localCandidate.foundation,\n this.iceTransport.connection.nominated.remoteCandidate.foundation,\n )\n : undefined,\n localCertificateId: this.localCertificate\n ? generateStatsId(\"certificate\", \"local\")\n : undefined,\n remoteCertificateId: this.remoteParameters\n ? generateStatsId(\"certificate\", \"remote\")\n : undefined,\n dtlsRole: this.role === \"auto\" ? undefined : this.role,\n };\n stats.push(transportStats);\n\n // Certificate stats\n if (this.localCertificate) {\n const fingerprints = this.localCertificate.getFingerprints();\n if (fingerprints.length > 0) {\n const certStats: RTCCertificateStats = {\n type: \"certificate\",\n id: generateStatsId(\"certificate\", \"local\"),\n timestamp,\n fingerprint: fingerprints[0].value,\n fingerprintAlgorithm: fingerprints[0].algorithm,\n base64Certificate: Buffer.from(\n this.localCertificate.certPem,\n ).toString(\"base64\"),\n };\n stats.push(certStats);\n }\n }\n\n if (\n this.remoteParameters &&\n this.remoteParameters.fingerprints.length > 0\n ) {\n const certStats: RTCCertificateStats = {\n type: \"certificate\",\n id: generateStatsId(\"certificate\", \"remote\"),\n timestamp,\n fingerprint: this.remoteParameters.fingerprints[0].value,\n fingerprintAlgorithm: this.remoteParameters.fingerprints[0].algorithm,\n base64Certificate: \"\", // Remote certificate content not available\n };\n stats.push(certStats);\n }\n\n // Get ICE stats\n const iceStats = await this.iceTransport.getStats();\n stats.push(...iceStats);\n\n return stats;\n }\n}\n\nexport const DtlsStates = [\n \"new\",\n \"connecting\",\n \"connected\",\n \"closed\",\n \"failed\",\n] as const;\nexport type DtlsState = (typeof DtlsStates)[number];\n\nexport type DtlsRole = \"auto\" | \"server\" | \"client\";\n\nexport class RTCCertificate {\n publicKey: string;\n privateKey: string;\n\n constructor(\n privateKeyPem: string,\n public certPem: string,\n public signatureHash: SignatureHash,\n ) {\n const cert = Certificate.fromPEM(Buffer.from(certPem));\n this.publicKey = cert.publicKey.toPEM();\n this.privateKey = PrivateKey.fromPEM(Buffer.from(privateKeyPem)).toPEM();\n }\n\n getFingerprints(): RTCDtlsFingerprint[] {\n return [\n new RTCDtlsFingerprint(\n \"sha-256\",\n fingerprint(\n Certificate.fromPEM(Buffer.from(this.certPem)).raw,\n \"sha256\",\n ),\n ),\n ];\n }\n}\n\nexport type DtlsKeys = {\n certPem: string;\n keyPem: string;\n signatureHash: SignatureHash;\n};\n\nexport class RTCDtlsFingerprint {\n constructor(\n public algorithm: string,\n public value: string,\n ) {}\n}\n\nexport class RTCDtlsParameters {\n constructor(\n public fingerprints: RTCDtlsFingerprint[] = [],\n public role: \"auto\" | \"client\" | \"server\",\n ) {}\n}\n\nclass IceTransport implements Transport {\n closed: boolean = false;\n constructor(private ice: IceConnection) {\n ice.onData.subscribe((buf) => {\n if (isDtls(buf)) {\n if (this.onData) {\n this.onData(buf);\n }\n }\n });\n }\n onData: (buf: Buffer) => void = () => {};\n\n get address() {\n return {} as AddressInfo;\n }\n\n type: string = \"ice\";\n\n readonly send = (data: Buffer) => {\n return this.ice.send(data);\n };\n\n async close() {\n this.closed = true;\n this.ice.close();\n }\n}\n\nconst createIceTransport = (ice: IceConnection) => new IceTransport(ice);\n"]}
1
+ {"version":3,"file":"dtls.js","sourceRoot":"","sources":["../../../../src/transport/dtls.ts"],"names":[],"mappings":";;;AAAA,qCAAqD;AAErD,mCAAoC;AACpC,8CAA6C;AAC7C,8CAA0D;AAG1D,sCAA0D;AAC1D,0CASyB;AAEzB,wCAcwB;AACxB,0CAQwB;AAExB,oCAKkB;AAGlB,MAAM,GAAG,GAAG,IAAA,WAAK,EAAC,8CAA8C,CAAC,CAAC;AAElE,SAAS,iBAAiB,CAAC,OAG1B;IACC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACrD,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACrD,OAAO,UAAU,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAgB;IACxC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,OAAO,yBAAyB,CAAC;QACnC,KAAK,MAAM;YACT,OAAO,kBAAkB,CAAC;QAC5B;YACE,OAAO;IACX,CAAC;AACH,CAAC;AASD,MAAa,gBAAgB;IA4B3B,YACW,MAA+B,EAC/B,YAA6B,EAC/B,gBAAiC,EACvB,eAA8B,EAAE;QAHjD;;;;mBAAS,MAAM;WAAyB;QACxC;;;;mBAAS,YAAY;WAAiB;QACtC;;;;mBAAO,gBAAgB;WAAiB;QACxC;;;;mBAAiB,YAAY;WAAoB;QA/BnD;;;;mBAAK,IAAA,mBAAU,GAAE,CAAC,QAAQ,EAAE;WAAC;QAC7B;;;;mBAAmB,KAAK;WAAC;QACzB;;;;mBAAiB,MAAM;WAAC;QACxB;;;;mBAAc,KAAK;WAAC;QACpB;;;;mBAA0B,CAAC;WAAC;QAE5B,sBAAsB;QACf;;;;mBAAY,CAAC;WAAC;QACd;;;;mBAAgB,CAAC;WAAC;QAClB;;;;mBAAc,CAAC;WAAC;QAChB;;;;mBAAkB,CAAC;WAAC;QAE3B;;;;mBAAsC,GAAG,EAAE,GAAE,CAAC;WAAC;QAC/C;;;;;WAAkB;QAClB;;;;;WAAmB;QACnB;;;;;WAAqB;QAEZ;;;;mBAAgB,IAAI,cAAK,EAAe;WAAC;QACzC;;;;mBAAS,IAAI,cAAK,EAAgB;WAAC;QACnC;;;;mBAAQ,IAAI,cAAK,EAAe;WAAC;QACzB;;;;mBAAS,IAAI,oBAAc,EAAE;WAAC;QAC/C;;;;;WAA2B;QAInB;;;;;WAAqC;QAW7C;;;;mBAAmB,CACjB,IAAY,EACZ,QAAkC,EAClC,OAAsC,EACtC,EAAE;gBACF,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YACxD,CAAC;WAAC;QAEF;;;;mBAAsB,CAAC,IAAY,EAAE,QAAkC,EAAE,EAAE;gBACzE,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAClD,CAAC;WAAC;QAEF;;;;mBAAgB,CAAC,KAAuB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC;WAAC;QA4SrE;;;;mBAAW,KAAK,EAAE,IAAY,EAAE,EAAE;gBACzC,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB;oBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAC3D,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACf,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBAC1C,CAAC;gBACD,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;WAAC;QAvUA,IAAI,CAAC,gBAAgB,KAArB,IAAI,CAAC,gBAAgB,GAAK,gBAAgB,CAAC,gBAAgB,EAAC;IAC9D,CAAC;IAgBD,IAAI,eAAe;QACjB,OAAO,IAAI,iBAAiB,CAC1B,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,EACpE,IAAI,CAAC,IAAI,CACV,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,gBAAgB;QAC3B,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,gBAAgB,CAAC;QAC/B,CAAC;QAED,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,uBAAuB,CAAC;QACtC,CAAC;QAED,IAAI,CAAC,uBAAuB,GAAG,CAAC,KAAK,IAAI,EAAE;YACzC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,GACtC,MAAM,oBAAa,CAAC,kCAAkC,CACpD;gBACE,SAAS,EAAE,yBAAkB,CAAC,OAAO;gBACrC,IAAI,EAAE,oBAAa,CAAC,QAAQ;aAC7B,EACD,0BAAmB,CAAC,YAAY,CACjC,CAAC;YACJ,IAAI,CAAC,gBAAgB,GAAG,IAAI,cAAc,CACxC,MAAM,EACN,OAAO,EACP,aAAa,CACd,CAAC;YACF,OAAO,IAAI,CAAC,gBAAgB,CAAC;QAC/B,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,IAAI,CAAC,uBAAuB,CAAC;IACtC,CAAC;IAED,eAAe,CAAC,gBAAmC;QACjD,MAAM,YAAY,GAAG,uBAAuB,CAAC;YAC3C,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,IAAI,EAAE,CAAC;YAC9C,GAAG,gBAAgB,CAAC,YAAY;SACjC,CAAC,CAAC;QACH,MAAM,IAAI,GACR,gBAAgB,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,IAAI;YAC7D,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI;YAC5B,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,gBAAgB,GAAG,IAAI,iBAAiB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,IACE,CAAC,IAAI,CAAC,gBAAgB;YACtB,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAC/C,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBAC7C,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;YACvB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAE5B,MAAM,IAAI,OAAO,CAAO,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;YACrC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,iBAAU,CAAC;oBACzB,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO;oBACpC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU;oBACtC,aAAa,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa;oBACnD,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;oBAC3D,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,oBAAoB,EAAE,IAAI;oBAC1B,kBAAkB,EAAE,IAAI;iBACzB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,GAAG,IAAI,iBAAU,CAAC;oBACzB,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,OAAO;oBACpC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU;oBACtC,aAAa,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa;oBACnD,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;oBAC3D,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,oBAAoB,EAAE,IAAI;iBAC3B,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;gBACjC,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB;oBACpC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAC1D,CAAC;oBACD,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE;gBAC/B,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC5B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC/B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACxB,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;gBAC1B,CAAC,CAAC,KAAK,CAAC,CAAC;YACX,CAAC,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,YAAY,iBAAU,EAAE,CAAC;gBACpC,MAAM,IAAA,qBAAU,EAAC,GAAG,CAAC,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBAClC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACxB,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;oBAClC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACX,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxB,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YACnB,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAE3B,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACxB,CAAC;IAEO,kCAAkC;QACxC,IACE,CAAC,IAAI,CAAC,gBAAgB;YACtB,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAC/C,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC;QACvD,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,OAAO,CACtE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;YACvB,MAAM,mBAAmB,GAAG,IAAA,qCAA6B,EAAC,SAAS,CAAC,CAAC;YACrE,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,eAAe,GAAG,IAAA,iCAAyB,EAAC,KAAK,CAAC,CAAC;YACzD,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YAED,OAAO,CAAC,EAAE,mBAAmB,EAAE,eAAe,EAAE,CAAC,CAAC;QACpD,CAAC,CACF,CAAC;QACF,IAAI,qBAAqB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,kBAAkB,GAAG,mCAAmC,CAC5D,qBAAqB,CACtB,CAAC;QACF,MAAM,oBAAoB,GAAG,qBAAqB,CAAC,MAAM,CACvD,CAAC,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,mBAAmB,KAAK,kBAAkB,CACxE,CAAC;QAEF,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,MAAM,CACpD,CAAC,GAAG,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE;YAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAClC,GAAG,CAAC,GAAG,CACL,mBAAmB,EACnB,IAAA,iCAAyB,EACvB,IAAA,mBAAW,EAAC,iBAAiB,EAAE,mBAAmB,CAAC,CACpD,CACF,CAAC;YACJ,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,EACD,IAAI,GAAG,EAAkB,CAC1B,CAAC;QAEF,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,CACvC,CAAC,EAAE,mBAAmB,EAAE,eAAe,EAAE,EAAE,EAAE,CAC3C,kBAAkB,CAAC,GAAG,CAAC,mBAAmB,CAAC,KAAK,eAAe,CAClE,CAAC;QAEF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QACD,GAAG,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QAEtC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,GAClD,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAA,eAAS,EAAC,OAAO,CAAC,EAAE,IAAA,gBAAU,EAAC,OAAO,CAAC,CAAC,CAAC;QAExE,MAAM,MAAM,GAAG;YACb,IAAI,EAAE;gBACJ,cAAc,EAAE,QAAQ;gBACxB,eAAe,EAAE,SAAS;gBAC1B,eAAe,EAAE,SAAS;gBAC1B,gBAAgB,EAAE,UAAU;aAC7B;YACD,OAAO;SACR,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,IAAI,iBAAW,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,IAAI,kBAAY,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED,SAAS;QACP,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAExB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzB,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACrD,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB;gBACpC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAC1D,CAAC;gBACD,OAAO;YACT,CAAC;YAED,IAAI,CAAC,IAAA,aAAO,EAAC,IAAI,CAAC;gBAAE,OAAO;YAE3B,iCAAiC;YACjC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC;YAClC,IAAI,CAAC,eAAe,EAAE,CAAC;YAEvB,IAAI,IAAA,YAAM,EAAC,IAAI,CAAC,EAAE,CAAC;gBACjB,IAAI,GAAW,CAAC;gBAChB,IAAI,CAAC;oBACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACjC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,6BAAuB,EAAE,CAAC;wBAC7C,GAAG,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;wBAC5C,OAAO;oBACT,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,WAAW,CAAC;gBAChB,IAAI,CAAC;oBACH,WAAW,GAAG,yBAAmB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBACrD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;oBAC9C,OAAO;gBACT,CAAC;gBACD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;oBAC/B,IAAI,CAAC;wBACH,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;oBAC5B,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,GAAG,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAW,CAAC;gBAChB,IAAI,CAAC;oBACH,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,6BAAuB,EAAE,CAAC;wBAC7C,GAAG,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;wBAC3C,OAAO;oBACT,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,GAAG,CAAC;gBACR,IAAI,CAAC;oBACH,GAAG,GAAG,eAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBACnC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;oBAC7C,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAgBD,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,MAAiB;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAE/C,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAC3D,CAAC;gBACD,OAAO,GAAG,CAAC,MAAM,CAAC;YACpB,CAAC;YAED,mBAAmB;YACnB,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC;YAC7B,IAAI,CAAC,WAAW,EAAE,CAAC;YAEnB,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC7D,OAAO,GAAG,CAAC,MAAM,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;YAC7B,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAqB;QAClC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAExC,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB;YACrC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAC3D,CAAC;YACD,OAAO,GAAG,CAAC,MAAM,CAAC;QACpB,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAEO,QAAQ,CAAC,KAAgB,EAAE,SAAS,GAAG,IAAI;QACjD,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,uBAAuB;QACvB,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAA,yBAAiB,GAAE;QAC5C,MAAM,KAAK,GAAe,EAAE,CAAC;QAE7B,MAAM,WAAW,GAAG,IAAA,uBAAe,EAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAE1D,kBAAkB;QAClB,MAAM,cAAc,GAAsB;YACxC,IAAI,EAAE,WAAW;YACjB,EAAE,EAAE,WAAW;YACf,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,SAAS,EAAE,IAAI,CAAC,KAAK;YACrB,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK;YACjC,OAAO,EACL,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,SAAS;gBAClC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI;YAC5B,wBAAwB,EACtB,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,gBAAgB;YACpD,uBAAuB,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS;gBAC7D,CAAC,CAAC,IAAA,uBAAe,EACb,gBAAgB,EAChB,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAC1C;gBACH,CAAC,CAAC,SAAS;YACb,kBAAkB,EAAE,IAAI,CAAC,gBAAgB;gBACvC,CAAC,CAAC,IAAA,uBAAe,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC;gBAClD,CAAC,CAAC,SAAS;YACb,mBAAmB,EAAE,IAAI,CAAC,IAAI,EAAE,iBAAiB;gBAC/C,CAAC,CAAC,IAAA,uBAAe,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC;gBACnD,CAAC,CAAC,SAAS;YACb,QAAQ,EAAE,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACtD,UAAU,EAAE,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC;YACtD,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI;YAC1C,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC;YACzD,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,WAAW;SAC3C,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE3B,oBAAoB;QACpB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC;YAC7D,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,SAAS,GAAwB;oBACrC,IAAI,EAAE,aAAa;oBACnB,EAAE,EAAE,IAAA,uBAAe,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC;oBACpD,SAAS;oBACT,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK;oBAClC,oBAAoB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;oBAC/C,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAC5B,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAC9B,CAAC,QAAQ,CAAC,QAAQ,CAAC;iBACrB,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,IACE,IAAI,CAAC,gBAAgB;YACrB,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAC7C,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAC5B,CAAC;YACD,MAAM,SAAS,GAAwB;gBACrC,IAAI,EAAE,aAAa;gBACnB,EAAE,EAAE,IAAA,uBAAe,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC;gBACrD,SAAS;gBACT,WAAW,EAAE,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK;gBACxD,oBAAoB,EAAE,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;gBACrE,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAClE,QAAQ,CACT;aACF,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QAED,gBAAgB;QAChB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC1E,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAExB,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAzfD,4CAyfC;AAEY,QAAA,UAAU,GAAG;IACxB,KAAK;IACL,YAAY;IACZ,WAAW;IACX,QAAQ;IACR,QAAQ;CACA,CAAC;AAKX,MAAa,cAAc;IAIzB,YACE,aAAqB,EACd,OAAe,EACf,aAA4B;QADnC;;;;mBAAO,OAAO;WAAQ;QACtB;;;;mBAAO,aAAa;WAAe;QANrC;;;;;WAAkB;QAClB;;;;;WAAmB;QAOjB,MAAM,IAAI,GAAG,kBAAW,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,iBAAU,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3E,CAAC;IAED,eAAe;QACb,OAAO;YACL,IAAI,kBAAkB,CACpB,SAAS,EACT,IAAA,mBAAW,EACT,kBAAW,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAClD,QAAQ,CACT,CACF;SACF,CAAC;IACJ,CAAC;CACF;AAzBD,wCAyBC;AAQD,MAAa,kBAAkB;IAC7B,YACS,SAAiB,EACjB,KAAa;QADpB;;;;mBAAO,SAAS;WAAQ;QACxB;;;;mBAAO,KAAK;WAAQ;IACnB,CAAC;CACL;AALD,gDAKC;AAED,MAAa,iBAAiB;IAC5B,YACS,eAAqC,EAAE,EACvC,IAAkC;QADzC;;;;mBAAO,YAAY;WAA2B;QAC9C;;;;mBAAO,IAAI;WAA8B;IACxC,CAAC;CACL;AALD,8CAKC;AAED,MAAM,uBAAuB,GAAG,CAAC,YAAkC,EAAE,EAAE;IACrE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;QAClD,MAAM,GAAG,GAAG,GACV,IAAA,qCAA6B,EAAC,SAAS,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,EAC1E,IAAI,IAAA,iCAAyB,EAAC,KAAK,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,8BAA8B,GAAG;IACrC,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;CACE,CAAC;AAEX,MAAM,mCAAmC,GAAG,CAC1C,YAA+C,EAC/C,EAAE;IACF,OAAO,CACL,8BAA8B,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAChD,YAAY,CAAC,IAAI,CACf,CAAC,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,mBAAmB,KAAK,SAAS,CAC/D,CACF,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,mBAAmB,CACzC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,YAAY;IAEhB,YAAoB,GAAkB;QAA1B;;;;mBAAQ,GAAG;WAAe;QADtC;;;;mBAAkB,KAAK;WAAC;QAUxB;;;;mBAAgC,GAAG,EAAE,GAAE,CAAC;WAAC;QAMzC;;;;mBAAe,KAAK;WAAC;QAEZ;;;;mBAAO,CAAC,IAAY,EAAE,EAAE;gBAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;WAAC;QAlBA,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3B,IAAI,IAAA,cAAM,EAAC,GAAG,CAAC,EAAE,CAAC;gBAChB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAChB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAGD,IAAI,OAAO;QACT,OAAO,EAAiB,CAAC;IAC3B,CAAC;IAQD,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;CACF;AAED,MAAM,kBAAkB,GAAG,CAAC,GAAkB,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC","sourcesContent":["import { Certificate, PrivateKey } from \"@fidm/x509\";\n\nimport { randomUUID } from \"crypto\";\nimport { setTimeout } from \"timers/promises\";\nimport { Event, type Transport } from \"../imports/common\";\n\nimport type { AddressInfo } from \"net\";\nimport { EventTarget as DomEventTarget } from \"../helper\";\nimport {\n CipherContext,\n DtlsClient,\n DtlsServer,\n type DtlsSocket,\n HashAlgorithm,\n NamedCurveAlgorithm,\n SignatureAlgorithm,\n type SignatureHash,\n} from \"../imports/dtls\";\nimport type { IceConnection } from \"../imports/ice\";\nimport {\n type RtcpPacket,\n RtcpPacketConverter,\n type RtpHeader,\n RtpPacket,\n SrtcpSession,\n SrtpAuthenticationError,\n type SrtpProfile,\n SrtpSession,\n debug,\n isMedia,\n isRtcp,\n keyLength,\n saltLength,\n} from \"../imports/rtp\";\nimport {\n type RTCCertificateStats,\n type RTCIceCandidatePairStats,\n type RTCIceCandidateStats,\n type RTCStats,\n type RTCTransportStats,\n generateStatsId,\n getStatsTimestamp,\n} from \"../media/stats\";\nimport type { DebugConfig } from \"../peerConnection\";\nimport {\n fingerprint,\n isDtls,\n normalizeFingerprintAlgorithm,\n normalizeFingerprintValue,\n} from \"../utils\";\nimport type { RTCIceTransport } from \"./ice\";\n\nconst log = debug(\"werift:packages/webrtc/src/transport/dtls.ts\");\n\nfunction formatDtlsVersion(version?: {\n major: number;\n minor: number;\n}) {\n if (!version) {\n return;\n }\n\n if (version.major === 0xfe && version.minor === 0xfd) {\n return \"DTLS 1.2\";\n }\n if (version.major === 0xfe && version.minor === 0xff) {\n return \"DTLS 1.0\";\n }\n}\n\nfunction formatSrtpCipher(profile?: number) {\n switch (profile) {\n case 0x0001:\n return \"AES_CM_128_HMAC_SHA1_80\";\n case 0x0007:\n return \"AEAD_AES_128_GCM\";\n default:\n return;\n }\n}\n\nexport interface DtlsTransportStats {\n bytesSent: number;\n bytesReceived: number;\n packetsSent: number;\n packetsReceived: number;\n}\n\nexport class RTCDtlsTransport implements DtlsTransportStats {\n id = randomUUID().toString();\n state: DtlsState = \"new\";\n role: DtlsRole = \"auto\";\n srtpStarted = false;\n transportSequenceNumber = 0;\n\n // Statistics tracking\n public bytesSent = 0;\n public bytesReceived = 0;\n public packetsSent = 0;\n public packetsReceived = 0;\n\n dataReceiver: (buf: Buffer) => void = () => {};\n dtls?: DtlsSocket;\n srtp!: SrtpSession;\n srtcp!: SrtcpSession;\n\n readonly onStateChange = new Event<[DtlsState]>();\n readonly onRtcp = new Event<[RtcpPacket]>();\n readonly onRtp = new Event<[RtpPacket]>();\n private readonly events = new DomEventTarget();\n onstatechange?: () => void;\n\n static localCertificate?: RTCCertificate;\n static localCertificatePromise?: Promise<RTCCertificate>;\n private remoteParameters?: RTCDtlsParameters;\n\n constructor(\n readonly config: { debug?: DebugConfig },\n readonly iceTransport: RTCIceTransport,\n public localCertificate?: RTCCertificate,\n private readonly srtpProfiles: SrtpProfile[] = [],\n ) {\n this.localCertificate ??= RTCDtlsTransport.localCertificate;\n }\n\n addEventListener = (\n type: string,\n listener: (...args: any[]) => void,\n options?: boolean | { once?: boolean },\n ) => {\n this.events.addEventListener(type, listener, options);\n };\n\n removeEventListener = (type: string, listener: (...args: any[]) => void) => {\n this.events.removeEventListener(type, listener);\n };\n\n dispatchEvent = (event: globalThis.Event) => this.events.dispatchEvent(event);\n\n get localParameters() {\n return new RTCDtlsParameters(\n this.localCertificate ? this.localCertificate.getFingerprints() : [],\n this.role,\n );\n }\n\n static async SetupCertificate() {\n if (this.localCertificate) {\n return this.localCertificate;\n }\n\n if (this.localCertificatePromise) {\n return this.localCertificatePromise;\n }\n\n this.localCertificatePromise = (async () => {\n const { certPem, keyPem, signatureHash } =\n await CipherContext.createSelfSignedCertificateWithKey(\n {\n signature: SignatureAlgorithm.ecdsa_3,\n hash: HashAlgorithm.sha256_4,\n },\n NamedCurveAlgorithm.secp256r1_23,\n );\n this.localCertificate = new RTCCertificate(\n keyPem,\n certPem,\n signatureHash,\n );\n return this.localCertificate;\n })();\n\n return this.localCertificatePromise;\n }\n\n setRemoteParams(remoteParameters: RTCDtlsParameters) {\n const fingerprints = deduplicateFingerprints([\n ...(this.remoteParameters?.fingerprints ?? []),\n ...remoteParameters.fingerprints,\n ]);\n const role =\n remoteParameters.role === \"auto\" && this.remoteParameters?.role\n ? this.remoteParameters.role\n : remoteParameters.role;\n this.remoteParameters = new RTCDtlsParameters(fingerprints, role);\n }\n\n async start() {\n if (this.state !== \"new\") {\n throw new Error(\"state must be new\");\n }\n if (\n !this.remoteParameters ||\n this.remoteParameters.fingerprints.length === 0\n ) {\n throw new Error(\"remote fingerprint not exist\");\n }\n\n if (this.role === \"auto\") {\n if (this.iceTransport.role === \"controlling\") {\n this.role = \"server\";\n } else {\n this.role = \"client\";\n }\n }\n\n this.setState(\"connecting\");\n\n await new Promise<void>(async (r, f) => {\n if (this.role === \"server\") {\n this.dtls = new DtlsServer({\n cert: this.localCertificate?.certPem,\n key: this.localCertificate?.privateKey,\n signatureHash: this.localCertificate?.signatureHash,\n transport: createIceTransport(this.iceTransport.connection),\n srtpProfiles: this.srtpProfiles,\n extendedMasterSecret: true,\n certificateRequest: true,\n });\n } else {\n this.dtls = new DtlsClient({\n cert: this.localCertificate?.certPem,\n key: this.localCertificate?.privateKey,\n signatureHash: this.localCertificate?.signatureHash,\n transport: createIceTransport(this.iceTransport.connection),\n srtpProfiles: this.srtpProfiles,\n extendedMasterSecret: true,\n });\n }\n this.dtls.onData.subscribe((buf) => {\n if (\n this.config.debug?.inboundPacketLoss &&\n this.config.debug?.inboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n this.dataReceiver(buf);\n });\n this.dtls.onClose.subscribe(() => {\n if (this.state !== \"failed\") {\n this.setState(\"closed\");\n }\n });\n this.dtls.onConnect.once(r);\n this.dtls.onError.once((error) => {\n this.setState(\"failed\");\n log(\"dtls failed\", error);\n f(error);\n });\n\n if (this.dtls instanceof DtlsClient) {\n await setTimeout(100);\n this.dtls.connect().catch((error) => {\n this.setState(\"failed\");\n log(\"dtls connect failed\", error);\n f(error);\n });\n }\n });\n\n try {\n this.verifyRemoteCertificateFingerprint();\n } catch (error) {\n this.setState(\"failed\");\n this.dtls?.close();\n throw error;\n }\n\n if (this.srtpProfiles.length > 0) {\n this.startSrtp();\n }\n this.setState(\"connected\");\n\n log(\"dtls connected\");\n }\n\n private verifyRemoteCertificateFingerprint() {\n if (\n !this.remoteParameters ||\n this.remoteParameters.fingerprints.length === 0\n ) {\n throw new Error(\"remote fingerprint not exist\");\n }\n\n const remoteCertificate = this.dtls?.remoteCertificate;\n if (!remoteCertificate) {\n throw new Error(\"remote certificate not available\");\n }\n\n const supportedFingerprints = this.remoteParameters.fingerprints.flatMap(\n ({ algorithm, value }) => {\n const normalizedAlgorithm = normalizeFingerprintAlgorithm(algorithm);\n if (!normalizedAlgorithm) {\n return [];\n }\n\n const normalizedValue = normalizeFingerprintValue(value);\n if (!normalizedValue) {\n throw new Error(\"remote fingerprint value is empty\");\n }\n\n return [{ normalizedAlgorithm, normalizedValue }];\n },\n );\n if (supportedFingerprints.length === 0) {\n throw new Error(\"no supported remote fingerprint algorithms\");\n }\n\n const preferredAlgorithm = selectPreferredFingerprintAlgorithm(\n supportedFingerprints,\n );\n const expectedFingerprints = supportedFingerprints.filter(\n ({ normalizedAlgorithm }) => normalizedAlgorithm === preferredAlgorithm,\n );\n\n const actualFingerprints = expectedFingerprints.reduce(\n (acc, { normalizedAlgorithm }) => {\n if (!acc.has(normalizedAlgorithm)) {\n acc.set(\n normalizedAlgorithm,\n normalizeFingerprintValue(\n fingerprint(remoteCertificate, normalizedAlgorithm),\n ),\n );\n }\n return acc;\n },\n new Map<string, string>(),\n );\n\n const matched = expectedFingerprints.some(\n ({ normalizedAlgorithm, normalizedValue }) =>\n actualFingerprints.get(normalizedAlgorithm) === normalizedValue,\n );\n\n if (!matched) {\n throw new Error(\"remote certificate fingerprint mismatch\");\n }\n }\n\n updateSrtpSession() {\n if (!this.dtls) throw new Error();\n\n const profile = this.dtls.srtp.srtpProfile;\n if (!profile) {\n throw new Error(\"need srtpProfile\");\n }\n log(\"selected SRTP Profile\", profile);\n\n const { localKey, localSalt, remoteKey, remoteSalt } =\n this.dtls.extractSessionKeys(keyLength(profile), saltLength(profile));\n\n const config = {\n keys: {\n localMasterKey: localKey,\n localMasterSalt: localSalt,\n remoteMasterKey: remoteKey,\n remoteMasterSalt: remoteSalt,\n },\n profile,\n };\n this.srtp = new SrtpSession(config);\n this.srtcp = new SrtcpSession(config);\n }\n\n startSrtp() {\n if (this.srtpStarted) return;\n this.srtpStarted = true;\n\n this.updateSrtpSession();\n\n this.iceTransport.connection.onData.subscribe((data) => {\n if (\n this.config.debug?.inboundPacketLoss &&\n this.config.debug?.inboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n\n if (!isMedia(data)) return;\n\n // Track received data statistics\n this.bytesReceived += data.length;\n this.packetsReceived++;\n\n if (isRtcp(data)) {\n let dec: Buffer;\n try {\n dec = this.srtcp.decrypt(data);\n } catch (error) {\n if (error instanceof SrtpAuthenticationError) {\n log(\"dropping invalid SRTCP packet\", error);\n return;\n }\n throw error;\n }\n let rtcpPackets;\n try {\n rtcpPackets = RtcpPacketConverter.deSerialize(dec);\n } catch (error) {\n log(\"dropping malformed SRTCP packet\", error);\n return;\n }\n for (const rtcp of rtcpPackets) {\n try {\n this.onRtcp.execute(rtcp);\n } catch (error) {\n log(\"RTCP error\", error);\n }\n }\n } else {\n let dec: Buffer;\n try {\n dec = this.srtp.decrypt(data);\n } catch (error) {\n if (error instanceof SrtpAuthenticationError) {\n log(\"dropping invalid SRTP packet\", error);\n return;\n }\n throw error;\n }\n let rtp;\n try {\n rtp = RtpPacket.deSerialize(dec);\n } catch (error) {\n log(\"dropping malformed SRTP packet\", error);\n return;\n }\n try {\n this.onRtp.execute(rtp);\n } catch (error) {\n log(\"RTP error\", error);\n }\n }\n });\n }\n\n readonly sendData = async (data: Buffer) => {\n if (\n this.config.debug?.outboundPacketLoss &&\n this.config.debug?.outboundPacketLoss / 100 < Math.random()\n ) {\n return;\n }\n\n if (!this.dtls) {\n throw new Error(\"dtls not established\");\n }\n await this.dtls.send(data);\n };\n\n async sendRtp(payload: Buffer, header: RtpHeader): Promise<number> {\n try {\n const enc = this.srtp.encrypt(payload, header);\n\n if (\n this.config.debug?.outboundPacketLoss &&\n this.config.debug?.outboundPacketLoss / 100 < Math.random()\n ) {\n return enc.length;\n }\n\n // Track statistics\n this.bytesSent += enc.length;\n this.packetsSent++;\n\n await this.iceTransport.connection.send(enc).catch(() => {});\n return enc.length;\n } catch (error) {\n log(\"failed to send\", error);\n return 0;\n }\n }\n\n async sendRtcp(packets: RtcpPacket[]) {\n const payload = Buffer.concat(packets.map((packet) => packet.serialize()));\n const enc = this.srtcp.encrypt(payload);\n\n if (\n this.config.debug?.outboundPacketLoss &&\n this.config.debug?.outboundPacketLoss / 100 < Math.random()\n ) {\n return enc.length;\n }\n\n // Track statistics\n this.bytesSent += enc.length;\n this.packetsSent++;\n\n await this.iceTransport.connection.send(enc).catch(() => {});\n }\n\n private setState(state: DtlsState, emitEvent = true) {\n if (state != this.state) {\n this.state = state;\n this.onStateChange.execute(state);\n if (emitEvent) {\n this.onstatechange?.();\n this.events.emit(\"statechange\");\n }\n }\n }\n\n async stop() {\n this.setState(\"closed\", false);\n // todo impl send alert\n await this.iceTransport.stop();\n }\n\n async getStats(timestamp = getStatsTimestamp()): Promise<RTCStats[]> {\n const stats: RTCStats[] = [];\n\n const transportId = generateStatsId(\"transport\", this.id);\n\n // Transport stats\n const transportStats: RTCTransportStats = {\n type: \"transport\",\n id: transportId,\n timestamp,\n bytesSent: this.bytesSent,\n bytesReceived: this.bytesReceived,\n packetsSent: this.packetsSent,\n packetsReceived: this.packetsReceived,\n dtlsState: this.state,\n iceState: this.iceTransport.state,\n iceRole:\n this.iceTransport.role === \"unknown\"\n ? undefined\n : this.iceTransport.role,\n iceLocalUsernameFragment:\n this.iceTransport.localParameters.usernameFragment,\n selectedCandidatePairId: this.iceTransport.connection.nominated\n ? generateStatsId(\n \"candidate-pair\",\n this.iceTransport.connection.nominated.id,\n )\n : undefined,\n localCertificateId: this.localCertificate\n ? generateStatsId(\"certificate\", this.id, \"local\")\n : undefined,\n remoteCertificateId: this.dtls?.remoteCertificate\n ? generateStatsId(\"certificate\", this.id, \"remote\")\n : undefined,\n dtlsRole: this.role === \"auto\" ? undefined : this.role,\n tlsVersion: formatDtlsVersion(this.dtls?.dtls.version),\n dtlsCipher: this.dtls?.cipher.cipher?.name,\n srtpCipher: formatSrtpCipher(this.dtls?.srtp.srtpProfile),\n iceRestarts: this.iceTransport.iceRestarts,\n };\n stats.push(transportStats);\n\n // Certificate stats\n if (this.localCertificate) {\n const fingerprints = this.localCertificate.getFingerprints();\n if (fingerprints.length > 0) {\n const certStats: RTCCertificateStats = {\n type: \"certificate\",\n id: generateStatsId(\"certificate\", this.id, \"local\"),\n timestamp,\n fingerprint: fingerprints[0].value,\n fingerprintAlgorithm: fingerprints[0].algorithm,\n base64Certificate: Buffer.from(\n this.localCertificate.certPem,\n ).toString(\"base64\"),\n };\n stats.push(certStats);\n }\n }\n\n if (\n this.remoteParameters &&\n this.remoteParameters.fingerprints.length > 0 &&\n this.dtls?.remoteCertificate\n ) {\n const certStats: RTCCertificateStats = {\n type: \"certificate\",\n id: generateStatsId(\"certificate\", this.id, \"remote\"),\n timestamp,\n fingerprint: this.remoteParameters.fingerprints[0].value,\n fingerprintAlgorithm: this.remoteParameters.fingerprints[0].algorithm,\n base64Certificate: Buffer.from(this.dtls.remoteCertificate).toString(\n \"base64\",\n ),\n };\n stats.push(certStats);\n }\n\n // Get ICE stats\n const iceStats = await this.iceTransport.getStats(timestamp, transportId);\n stats.push(...iceStats);\n\n return stats;\n }\n}\n\nexport const DtlsStates = [\n \"new\",\n \"connecting\",\n \"connected\",\n \"closed\",\n \"failed\",\n] as const;\nexport type DtlsState = (typeof DtlsStates)[number];\n\nexport type DtlsRole = \"auto\" | \"server\" | \"client\";\n\nexport class RTCCertificate {\n publicKey: string;\n privateKey: string;\n\n constructor(\n privateKeyPem: string,\n public certPem: string,\n public signatureHash: SignatureHash,\n ) {\n const cert = Certificate.fromPEM(Buffer.from(certPem));\n this.publicKey = cert.publicKey.toPEM();\n this.privateKey = PrivateKey.fromPEM(Buffer.from(privateKeyPem)).toPEM();\n }\n\n getFingerprints(): RTCDtlsFingerprint[] {\n return [\n new RTCDtlsFingerprint(\n \"sha-256\",\n fingerprint(\n Certificate.fromPEM(Buffer.from(this.certPem)).raw,\n \"sha256\",\n ),\n ),\n ];\n }\n}\n\nexport type DtlsKeys = {\n certPem: string;\n keyPem: string;\n signatureHash: SignatureHash;\n};\n\nexport class RTCDtlsFingerprint {\n constructor(\n public algorithm: string,\n public value: string,\n ) {}\n}\n\nexport class RTCDtlsParameters {\n constructor(\n public fingerprints: RTCDtlsFingerprint[] = [],\n public role: \"auto\" | \"client\" | \"server\",\n ) {}\n}\n\nconst deduplicateFingerprints = (fingerprints: RTCDtlsFingerprint[]) => {\n const seen = new Set<string>();\n return fingerprints.filter(({ algorithm, value }) => {\n const key = `${\n normalizeFingerprintAlgorithm(algorithm) ?? algorithm.trim().toLowerCase()\n }:${normalizeFingerprintValue(value)}`;\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n};\n\nconst preferredFingerprintAlgorithms = [\n \"sha512\",\n \"sha384\",\n \"sha256\",\n \"sha224\",\n \"sha1\",\n] as const;\n\nconst selectPreferredFingerprintAlgorithm = (\n fingerprints: { normalizedAlgorithm: string }[],\n) => {\n return (\n preferredFingerprintAlgorithms.find((algorithm) =>\n fingerprints.some(\n ({ normalizedAlgorithm }) => normalizedAlgorithm === algorithm,\n ),\n ) ?? fingerprints[0].normalizedAlgorithm\n );\n};\n\nclass IceTransport implements Transport {\n closed: boolean = false;\n constructor(private ice: IceConnection) {\n ice.onData.subscribe((buf) => {\n if (isDtls(buf)) {\n if (this.onData) {\n this.onData(buf);\n }\n }\n });\n }\n onData: (buf: Buffer) => void = () => {};\n\n get address() {\n return {} as AddressInfo;\n }\n\n type: string = \"ice\";\n\n readonly send = (data: Buffer) => {\n return this.ice.send(data);\n };\n\n async close() {\n this.closed = true;\n this.ice.close();\n }\n}\n\nconst createIceTransport = (ice: IceConnection) => new IceTransport(ice);\n"]}
@@ -28,16 +28,34 @@ export declare class RTCIceTransport {
28
28
  readonly id: string;
29
29
  connection: IceConnection;
30
30
  state: RTCIceConnectionState;
31
+ readonly component = "rtp";
32
+ iceRestarts: number;
31
33
  private waitStart?;
32
34
  private renominating;
33
- readonly onStateChange: Event<["disconnected" | "closed" | "completed" | "new" | "connected" | "failed" | "checking"]>;
35
+ private readonly events;
36
+ onstatechange?: () => void;
37
+ ongatheringstatechange?: () => void;
38
+ readonly onStateChange: Event<["closed" | "disconnected" | "completed" | "new" | "connected" | "failed" | "checking"]>;
34
39
  readonly onIceCandidate: Event<[IceCandidate | undefined]>;
35
40
  readonly onNegotiationNeeded: Event<[]>;
36
41
  constructor(iceGather: RTCIceGatherer);
37
- get role(): "controlling" | "controlled";
42
+ addEventListener: (type: string, listener: (...args: any[]) => void, options?: boolean | {
43
+ once?: boolean;
44
+ }) => void;
45
+ removeEventListener: (type: string, listener: (...args: any[]) => void) => void;
46
+ dispatchEvent: (event: globalThis.Event) => boolean;
47
+ get role(): "unknown" | "controlling" | "controlled";
38
48
  get gatheringState(): "complete" | "new" | "gathering";
39
49
  get localCandidates(): IceCandidate[];
40
50
  get localParameters(): RTCIceParameters;
51
+ getRemoteCandidates(): RTCIceCandidate[];
52
+ getLocalCandidates(): RTCIceCandidate[];
53
+ getSelectedCandidatePair(): {
54
+ local: RTCIceCandidate;
55
+ remote: RTCIceCandidate;
56
+ } | null;
57
+ getLocalParameters(): RTCIceParameters;
58
+ getRemoteParameters(): RTCIceParameters | null;
41
59
  private setState;
42
60
  gather(): Promise<void>;
43
61
  addRemoteCandidate: (candidate?: IceCandidate) => Promise<void> | undefined;
@@ -45,7 +63,7 @@ export declare class RTCIceTransport {
45
63
  restart(): void;
46
64
  start(): Promise<void>;
47
65
  stop(): Promise<void>;
48
- getStats(): Promise<RTCStats[]>;
66
+ getStats(timestamp?: number, transportId?: string): Promise<RTCStats[]>;
49
67
  }
50
68
  export declare const IceTransportStates: readonly ["new", "checking", "connected", "completed", "disconnected", "failed", "closed"];
51
69
  export type RTCIceConnectionState = (typeof IceTransportStates)[number];