werift 0.24.1 → 0.24.2

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 (35) hide show
  1. package/lib/dtls/src/context/transport.d.ts +2 -2
  2. package/lib/dtls/src/context/transport.js +2 -2
  3. package/lib/dtls/src/context/transport.js.map +1 -1
  4. package/lib/dtls/src/socket.d.ts +3 -2
  5. package/lib/dtls/src/socket.js +2 -2
  6. package/lib/dtls/src/socket.js.map +1 -1
  7. package/lib/ice/src/ice.d.ts +20 -0
  8. package/lib/ice/src/ice.js +259 -57
  9. package/lib/ice/src/ice.js.map +1 -1
  10. package/lib/ice/src/iceBase.d.ts +22 -1
  11. package/lib/ice/src/iceBase.js +30 -1
  12. package/lib/ice/src/iceBase.js.map +1 -1
  13. package/lib/ice/src/stun/protocol.d.ts +2 -2
  14. package/lib/ice/src/stun/protocol.js +17 -3
  15. package/lib/ice/src/stun/protocol.js.map +1 -1
  16. package/lib/ice/src/stun/tcpProtocol.d.ts +2 -2
  17. package/lib/ice/src/stun/tcpProtocol.js +13 -3
  18. package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
  19. package/lib/ice/src/stun/transaction.d.ts +41 -4
  20. package/lib/ice/src/stun/transaction.js +193 -24
  21. package/lib/ice/src/stun/transaction.js.map +1 -1
  22. package/lib/ice/src/turn/protocol.d.ts +3 -3
  23. package/lib/ice/src/turn/protocol.js +31 -6
  24. package/lib/ice/src/turn/protocol.js.map +1 -1
  25. package/lib/ice/src/types/model.d.ts +27 -1
  26. package/lib/ice/src/types/model.js.map +1 -1
  27. package/lib/ice-server/src/stun/message.js +8 -0
  28. package/lib/ice-server/src/stun/message.js.map +1 -1
  29. package/lib/index.mjs +435 -104
  30. package/lib/webrtc/src/peerConnection.d.ts +2 -2
  31. package/lib/webrtc/src/secureTransportManager.d.ts +1 -1
  32. package/lib/webrtc/src/secureTransportManager.js +12 -0
  33. package/lib/webrtc/src/secureTransportManager.js.map +1 -1
  34. package/lib/webrtc/src/transport/dtls.d.ts +1 -1
  35. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import type { Transport } from "../imports/common";
1
+ import type { Address, Transport } from "../imports/common";
2
2
  export declare class TransportContext {
3
3
  socket: Transport;
4
4
  constructor(socket: Transport);
5
- readonly send: (buf: Buffer) => Promise<void>;
5
+ readonly send: (buf: Buffer, addr?: Address) => Promise<void>;
6
6
  }
@@ -13,8 +13,8 @@ class TransportContext {
13
13
  enumerable: true,
14
14
  configurable: true,
15
15
  writable: true,
16
- value: (buf) => {
17
- return this.socket.send(buf);
16
+ value: (buf, addr) => {
17
+ return this.socket.send(buf, addr);
18
18
  }
19
19
  });
20
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../../dtls/src/context/transport.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAC3B,YAAmB,MAAiB;QAAxB;;;;mBAAO,MAAM;WAAW;QAE3B;;;;mBAAO,CAAC,GAAW,EAAE,EAAE;gBAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;WAAC;IAJqC,CAAC;CAKzC;AAND,4CAMC","sourcesContent":["import type { Transport } from \"../imports/common\";\n\nexport class TransportContext {\n constructor(public socket: Transport) {}\n\n readonly send = (buf: Buffer) => {\n return this.socket.send(buf);\n };\n}\n"]}
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../../dtls/src/context/transport.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAC3B,YAAmB,MAAiB;QAAxB;;;;mBAAO,MAAM;WAAW;QAE3B;;;;mBAAO,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE;gBAC9C,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACrC,CAAC;WAAC;IAJqC,CAAC;CAKzC;AAND,4CAMC","sourcesContent":["import type { Address, Transport } from \"../imports/common\";\n\nexport class TransportContext {\n constructor(public socket: Transport) {}\n\n readonly send = (buf: Buffer, addr?: Address) => {\n return this.socket.send(buf, addr);\n };\n}\n"]}
@@ -1,4 +1,5 @@
1
- import { Event, type Transport } from "./imports/common";
1
+ import { Event } from "./imports/common";
2
+ import type { Address, Transport } from "./imports/common";
2
3
  import { type SignatureHash } from "./cipher/const";
3
4
  import { type SessionTypes } from "./cipher/suites/abstract";
4
5
  import { CipherContext } from "./context/cipher";
@@ -30,7 +31,7 @@ export declare class DtlsSocket {
30
31
  protected waitForReady: (condition: () => boolean) => Promise<void>;
31
32
  handleFragmentHandshake(messages: FragmentedHandshake[]): FragmentedHandshake[];
32
33
  /**send application data */
33
- send: (buf: Buffer) => Promise<void>;
34
+ send: (buf: Buffer, addr?: Address) => Promise<void>;
34
35
  close(): void;
35
36
  extractSessionKeys(keyLength: number, saltLength: number): {
36
37
  localKey: any;
@@ -176,9 +176,9 @@ class DtlsSocket {
176
176
  enumerable: true,
177
177
  configurable: true,
178
178
  writable: true,
179
- value: async (buf) => {
179
+ value: async (buf, addr) => {
180
180
  const pkt = (0, builder_1.createPlaintext)(this.dtls)([{ type: const_2.ContentType.applicationData, fragment: buf }], ++this.dtls.recordSequenceNumber)[0];
181
- await this.transport.send(this.cipher.encryptPacket(pkt).serialize());
181
+ await this.transport.send(this.cipher.encryptPacket(pkt).serialize(), addr);
182
182
  }
183
183
  });
184
184
  this.dtls = new dtls_1.DtlsContext(this.options, this.sessionType);
@@ -1 +1 @@
1
- {"version":3,"file":"socket.js","sourceRoot":"","sources":["../../../../dtls/src/socket.ts"],"names":[],"mappings":"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","sourcesContent":["import { decode, types } from \"@shinyoshiaki/binary-data\";\n\nimport { setTimeout } from \"timers/promises\";\nimport { Event, type Transport, debug } from \"./imports/common\";\n\nimport {\n NamedCurveAlgorithmList,\n type SignatureHash,\n signatures,\n} from \"./cipher/const\";\nimport { exportKeyingMaterial } from \"./cipher/prf\";\nimport { SessionType, type SessionTypes } from \"./cipher/suites/abstract\";\nimport { CipherContext } from \"./context/cipher\";\nimport { DtlsContext } from \"./context/dtls\";\nimport { SrtpContext } from \"./context/srtp\";\nimport { TransportContext } from \"./context/transport\";\nimport { EllipticCurves } from \"./handshake/extensions/ellipticCurves\";\nimport { ExtendedMasterSecret } from \"./handshake/extensions/extendedMasterSecret\";\nimport { RenegotiationIndication } from \"./handshake/extensions/renegotiationIndication\";\nimport { Signature } from \"./handshake/extensions/signature\";\nimport { UseSRTP } from \"./handshake/extensions/useSrtp\";\nimport type { SrtpProfile } from \"./imports/rtp\";\nimport { createPlaintext } from \"./record/builder\";\nimport { ContentType } from \"./record/const\";\nimport { FragmentedHandshake } from \"./record/message/fragment\";\nimport { parsePacket, parsePlainText } from \"./record/receive\";\nimport type { Extension } from \"./typings/domain\";\n\nconst log = debug(\"werift-dtls : packages/dtls/src/socket.ts : log\");\nconst err = debug(\"werift-dtls : packages/dtls/src/socket.ts : err\");\n\nexport class DtlsSocket {\n readonly onConnect = new Event();\n readonly onData = new Event<[Buffer]>();\n readonly onError = new Event<[Error]>();\n readonly onClose = new Event();\n readonly transport: TransportContext;\n cipher: CipherContext;\n dtls: DtlsContext;\n srtp: SrtpContext = new SrtpContext();\n\n connected = false;\n extensions: Extension[] = [];\n onHandleHandshakes!: (assembled: FragmentedHandshake[]) => Promise<void>;\n\n private bufferFragmentedHandshakes: FragmentedHandshake[] = [];\n\n constructor(\n public options: Options,\n public sessionType: SessionTypes,\n ) {\n this.dtls = new DtlsContext(this.options, this.sessionType);\n this.cipher = new CipherContext(\n this.sessionType,\n this.options.cert,\n this.options.key,\n this.options.signatureHash,\n );\n this.transport = new TransportContext(this.options.transport);\n this.setupExtensions();\n this.transport.socket.onData = this.udpOnMessage;\n }\n\n renegotiation() {\n log(\"renegotiation\", this.sessionType);\n this.connected = false;\n this.cipher = new CipherContext(\n this.sessionType,\n this.options.cert,\n this.options.key,\n this.options.signatureHash,\n );\n this.dtls = new DtlsContext(this.options, this.sessionType);\n this.srtp = new SrtpContext();\n this.extensions = [];\n this.bufferFragmentedHandshakes = [];\n }\n\n private udpOnMessage = (data: Buffer) => {\n const packets = parsePacket(data);\n\n for (const packet of packets) {\n try {\n const messages = parsePlainText(this.dtls, this.cipher)(packet);\n for (const message of messages) {\n switch (message.type) {\n case ContentType.handshake:\n {\n const handshake = message.data as FragmentedHandshake;\n const handshakes = this.handleFragmentHandshake([handshake]);\n const assembled = Object.values(\n handshakes.reduce(\n (acc: { [type: string]: FragmentedHandshake[] }, cur) => {\n if (!acc[cur.msg_type]) acc[cur.msg_type] = [];\n acc[cur.msg_type].push(cur);\n return acc;\n },\n {},\n ),\n )\n .map((v) => FragmentedHandshake.assemble(v))\n .sort((a, b) => a.msg_type - b.msg_type);\n\n this.onHandleHandshakes(assembled).catch((error) => {\n err(this.dtls.sessionId, \"onHandleHandshakes error\", error);\n this.onError.execute(error);\n });\n }\n break;\n case ContentType.applicationData:\n {\n this.onData.execute(message.data as Buffer);\n }\n break;\n case ContentType.alert:\n this.onClose.execute();\n break;\n }\n }\n } catch (error) {\n err(this.dtls.sessionId, \"catch udpOnMessage error\", error);\n }\n }\n };\n\n private setupExtensions() {\n log(this.dtls.sessionId, \"support srtpProfiles\", this.options.srtpProfiles);\n if (this.options.srtpProfiles && this.options.srtpProfiles.length > 0) {\n const useSrtp = UseSRTP.create(\n this.options.srtpProfiles,\n Buffer.from([0x00]),\n );\n this.extensions.push(useSrtp.extension);\n }\n\n {\n const curve = EllipticCurves.createEmpty();\n curve.data = NamedCurveAlgorithmList;\n this.extensions.push(curve.extension);\n }\n\n {\n const signature = Signature.createEmpty();\n // libwebrtc/OpenSSL require 4=1 , 4=3 signatureHash\n signature.data = signatures;\n this.extensions.push(signature.extension);\n }\n if (this.options.extendedMasterSecret) {\n this.extensions.push({\n type: ExtendedMasterSecret.type,\n data: Buffer.alloc(0),\n });\n }\n\n {\n const renegotiationIndication = RenegotiationIndication.createEmpty();\n this.extensions.push(renegotiationIndication.extension);\n }\n }\n\n protected waitForReady = (condition: () => boolean) =>\n new Promise<void>(async (r, f) => {\n for (let i = 0; i < 10; i++) {\n if (condition()) {\n r();\n break;\n } else {\n await setTimeout(100 * i);\n }\n }\n f(\"waitForReady timeout\");\n });\n\n handleFragmentHandshake(messages: FragmentedHandshake[]) {\n let handshakes = messages.filter((v) => {\n // find fragmented\n if (v.fragment_length !== v.length) {\n this.bufferFragmentedHandshakes.push(v);\n return false;\n }\n return true;\n });\n\n if (this.bufferFragmentedHandshakes.length > 1) {\n const [last] = this.bufferFragmentedHandshakes.slice(-1);\n if (last.fragment_offset + last.fragment_length === last.length) {\n handshakes = [...this.bufferFragmentedHandshakes, ...handshakes];\n this.bufferFragmentedHandshakes = [];\n }\n }\n return handshakes; // return un fragmented handshakes\n }\n\n /**send application data */\n send = async (buf: Buffer) => {\n const pkt = createPlaintext(this.dtls)(\n [{ type: ContentType.applicationData, fragment: buf }],\n ++this.dtls.recordSequenceNumber,\n )[0];\n await this.transport.send(this.cipher.encryptPacket(pkt).serialize());\n };\n\n close() {\n this.transport.socket.close();\n }\n\n extractSessionKeys(keyLength: number, saltLength: number) {\n const keyingMaterial = this.exportKeyingMaterial(\n \"EXTRACTOR-dtls_srtp\",\n keyLength * 2 + saltLength * 2,\n );\n\n const { clientKey, serverKey, clientSalt, serverSalt } = decode(\n keyingMaterial,\n {\n clientKey: types.buffer(keyLength),\n serverKey: types.buffer(keyLength),\n clientSalt: types.buffer(saltLength),\n serverSalt: types.buffer(saltLength),\n },\n );\n\n if (this.sessionType === SessionType.CLIENT) {\n return {\n localKey: clientKey,\n localSalt: clientSalt,\n remoteKey: serverKey,\n remoteSalt: serverSalt,\n };\n } else {\n return {\n localKey: serverKey,\n localSalt: serverSalt,\n remoteKey: clientKey,\n remoteSalt: clientSalt,\n };\n }\n }\n\n exportKeyingMaterial(label: string, length: number) {\n return exportKeyingMaterial(\n label,\n length,\n this.cipher.masterSecret,\n this.cipher.localRandom.serialize(),\n this.cipher.remoteRandom.serialize(),\n this.sessionType === SessionType.CLIENT,\n );\n }\n\n get remoteCertificate() {\n return this.cipher.remoteCertificate;\n }\n}\n\nexport interface Options {\n transport: Transport;\n srtpProfiles?: SrtpProfile[];\n cert?: string;\n key?: string;\n signatureHash?: SignatureHash;\n certificateRequest?: boolean;\n extendedMasterSecret?: boolean;\n}\n"]}
1
+ {"version":3,"file":"socket.js","sourceRoot":"","sources":["../../../../dtls/src/socket.ts"],"names":[],"mappings":"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","sourcesContent":["import { decode, types } from \"@shinyoshiaki/binary-data\";\n\nimport { setTimeout } from \"timers/promises\";\nimport { Event, debug } from \"./imports/common\";\nimport type { Address, Transport } from \"./imports/common\";\n\nimport {\n NamedCurveAlgorithmList,\n type SignatureHash,\n signatures,\n} from \"./cipher/const\";\nimport { exportKeyingMaterial } from \"./cipher/prf\";\nimport { SessionType, type SessionTypes } from \"./cipher/suites/abstract\";\nimport { CipherContext } from \"./context/cipher\";\nimport { DtlsContext } from \"./context/dtls\";\nimport { SrtpContext } from \"./context/srtp\";\nimport { TransportContext } from \"./context/transport\";\nimport { EllipticCurves } from \"./handshake/extensions/ellipticCurves\";\nimport { ExtendedMasterSecret } from \"./handshake/extensions/extendedMasterSecret\";\nimport { RenegotiationIndication } from \"./handshake/extensions/renegotiationIndication\";\nimport { Signature } from \"./handshake/extensions/signature\";\nimport { UseSRTP } from \"./handshake/extensions/useSrtp\";\nimport type { SrtpProfile } from \"./imports/rtp\";\nimport { createPlaintext } from \"./record/builder\";\nimport { ContentType } from \"./record/const\";\nimport { FragmentedHandshake } from \"./record/message/fragment\";\nimport { parsePacket, parsePlainText } from \"./record/receive\";\nimport type { Extension } from \"./typings/domain\";\n\nconst log = debug(\"werift-dtls : packages/dtls/src/socket.ts : log\");\nconst err = debug(\"werift-dtls : packages/dtls/src/socket.ts : err\");\n\nexport class DtlsSocket {\n readonly onConnect = new Event();\n readonly onData = new Event<[Buffer]>();\n readonly onError = new Event<[Error]>();\n readonly onClose = new Event();\n readonly transport: TransportContext;\n cipher: CipherContext;\n dtls: DtlsContext;\n srtp: SrtpContext = new SrtpContext();\n\n connected = false;\n extensions: Extension[] = [];\n onHandleHandshakes!: (assembled: FragmentedHandshake[]) => Promise<void>;\n\n private bufferFragmentedHandshakes: FragmentedHandshake[] = [];\n\n constructor(\n public options: Options,\n public sessionType: SessionTypes,\n ) {\n this.dtls = new DtlsContext(this.options, this.sessionType);\n this.cipher = new CipherContext(\n this.sessionType,\n this.options.cert,\n this.options.key,\n this.options.signatureHash,\n );\n this.transport = new TransportContext(this.options.transport);\n this.setupExtensions();\n this.transport.socket.onData = this.udpOnMessage;\n }\n\n renegotiation() {\n log(\"renegotiation\", this.sessionType);\n this.connected = false;\n this.cipher = new CipherContext(\n this.sessionType,\n this.options.cert,\n this.options.key,\n this.options.signatureHash,\n );\n this.dtls = new DtlsContext(this.options, this.sessionType);\n this.srtp = new SrtpContext();\n this.extensions = [];\n this.bufferFragmentedHandshakes = [];\n }\n\n private udpOnMessage = (data: Buffer) => {\n const packets = parsePacket(data);\n\n for (const packet of packets) {\n try {\n const messages = parsePlainText(this.dtls, this.cipher)(packet);\n for (const message of messages) {\n switch (message.type) {\n case ContentType.handshake:\n {\n const handshake = message.data as FragmentedHandshake;\n const handshakes = this.handleFragmentHandshake([handshake]);\n const assembled = Object.values(\n handshakes.reduce(\n (acc: { [type: string]: FragmentedHandshake[] }, cur) => {\n if (!acc[cur.msg_type]) acc[cur.msg_type] = [];\n acc[cur.msg_type].push(cur);\n return acc;\n },\n {},\n ),\n )\n .map((v) => FragmentedHandshake.assemble(v))\n .sort((a, b) => a.msg_type - b.msg_type);\n\n this.onHandleHandshakes(assembled).catch((error) => {\n err(this.dtls.sessionId, \"onHandleHandshakes error\", error);\n this.onError.execute(error);\n });\n }\n break;\n case ContentType.applicationData:\n {\n this.onData.execute(message.data as Buffer);\n }\n break;\n case ContentType.alert:\n this.onClose.execute();\n break;\n }\n }\n } catch (error) {\n err(this.dtls.sessionId, \"catch udpOnMessage error\", error);\n }\n }\n };\n\n private setupExtensions() {\n log(this.dtls.sessionId, \"support srtpProfiles\", this.options.srtpProfiles);\n if (this.options.srtpProfiles && this.options.srtpProfiles.length > 0) {\n const useSrtp = UseSRTP.create(\n this.options.srtpProfiles,\n Buffer.from([0x00]),\n );\n this.extensions.push(useSrtp.extension);\n }\n\n {\n const curve = EllipticCurves.createEmpty();\n curve.data = NamedCurveAlgorithmList;\n this.extensions.push(curve.extension);\n }\n\n {\n const signature = Signature.createEmpty();\n // libwebrtc/OpenSSL require 4=1 , 4=3 signatureHash\n signature.data = signatures;\n this.extensions.push(signature.extension);\n }\n if (this.options.extendedMasterSecret) {\n this.extensions.push({\n type: ExtendedMasterSecret.type,\n data: Buffer.alloc(0),\n });\n }\n\n {\n const renegotiationIndication = RenegotiationIndication.createEmpty();\n this.extensions.push(renegotiationIndication.extension);\n }\n }\n\n protected waitForReady = (condition: () => boolean) =>\n new Promise<void>(async (r, f) => {\n for (let i = 0; i < 10; i++) {\n if (condition()) {\n r();\n break;\n } else {\n await setTimeout(100 * i);\n }\n }\n f(\"waitForReady timeout\");\n });\n\n handleFragmentHandshake(messages: FragmentedHandshake[]) {\n let handshakes = messages.filter((v) => {\n // find fragmented\n if (v.fragment_length !== v.length) {\n this.bufferFragmentedHandshakes.push(v);\n return false;\n }\n return true;\n });\n\n if (this.bufferFragmentedHandshakes.length > 1) {\n const [last] = this.bufferFragmentedHandshakes.slice(-1);\n if (last.fragment_offset + last.fragment_length === last.length) {\n handshakes = [...this.bufferFragmentedHandshakes, ...handshakes];\n this.bufferFragmentedHandshakes = [];\n }\n }\n return handshakes; // return un fragmented handshakes\n }\n\n /**send application data */\n send = async (buf: Buffer, addr?: Address) => {\n const pkt = createPlaintext(this.dtls)(\n [{ type: ContentType.applicationData, fragment: buf }],\n ++this.dtls.recordSequenceNumber,\n )[0];\n await this.transport.send(this.cipher.encryptPacket(pkt).serialize(), addr);\n };\n\n close() {\n this.transport.socket.close();\n }\n\n extractSessionKeys(keyLength: number, saltLength: number) {\n const keyingMaterial = this.exportKeyingMaterial(\n \"EXTRACTOR-dtls_srtp\",\n keyLength * 2 + saltLength * 2,\n );\n\n const { clientKey, serverKey, clientSalt, serverSalt } = decode(\n keyingMaterial,\n {\n clientKey: types.buffer(keyLength),\n serverKey: types.buffer(keyLength),\n clientSalt: types.buffer(saltLength),\n serverSalt: types.buffer(saltLength),\n },\n );\n\n if (this.sessionType === SessionType.CLIENT) {\n return {\n localKey: clientKey,\n localSalt: clientSalt,\n remoteKey: serverKey,\n remoteSalt: serverSalt,\n };\n } else {\n return {\n localKey: serverKey,\n localSalt: serverSalt,\n remoteKey: clientKey,\n remoteSalt: clientSalt,\n };\n }\n }\n\n exportKeyingMaterial(label: string, length: number) {\n return exportKeyingMaterial(\n label,\n length,\n this.cipher.masterSecret,\n this.cipher.localRandom.serialize(),\n this.cipher.remoteRandom.serialize(),\n this.sessionType === SessionType.CLIENT,\n );\n }\n\n get remoteCertificate() {\n return this.cipher.remoteCertificate;\n }\n}\n\nexport interface Options {\n transport: Transport;\n srtpProfiles?: SrtpProfile[];\n cert?: string;\n key?: string;\n signatureHash?: SignatureHash;\n certificateRequest?: boolean;\n extendedMasterSecret?: boolean;\n}\n"]}
@@ -35,6 +35,12 @@ export declare class Connection implements IceConnection {
35
35
  private localCandidatesStart;
36
36
  private protocols;
37
37
  private queryConsentHandle?;
38
+ /** RFC 7675 consent-to-send: application data may use the selected pair. */
39
+ private consentFresh;
40
+ /** Invalidates in-flight consent callbacks on restart / close / replace / expire. */
41
+ private consentSessionId;
42
+ private consentExpiryTimer?;
43
+ private consentRequestAbort?;
38
44
  readonly onData: Event<[Buffer<ArrayBufferLike>]>;
39
45
  readonly stateChanged: Event<[IceState]>;
40
46
  readonly onIceCandidate: Event<[Candidate]>;
@@ -56,6 +62,19 @@ export declare class Connection implements IceConnection {
56
62
  connect(): Promise<void>;
57
63
  private unfreezeInitial;
58
64
  private schedulingChecks;
65
+ /**
66
+ * Stop consent request cadence, expiry timer, and outstanding transactions.
67
+ * Does not change ICE state by itself.
68
+ */
69
+ private stopConsentLifecycle;
70
+ /**
71
+ * ICE-lite interop only (not required by RFC 7675): mirror libwebrtc
72
+ * semi-aggressive nomination — attach USE-CANDIDATE when we are controlling,
73
+ * the remote is ICE-lite, and the target is the current selected pair.
74
+ */
75
+ private shouldNominateConsentRequest;
76
+ private canSendApplicationData;
77
+ private abortableDelay;
59
78
  private queryConsent;
60
79
  close(): Promise<void>;
61
80
  private setState;
@@ -67,6 +86,7 @@ export declare class Connection implements IceConnection {
67
86
  get candidatePairs(): CandidatePair[];
68
87
  private sortCheckList;
69
88
  private findPair;
89
+ private applyIceControlling;
70
90
  private switchRole;
71
91
  private checkComplete;
72
92
  checkStart: (pair: CandidatePair) => {
@@ -220,6 +220,32 @@ class Connection {
220
220
  writable: true,
221
221
  value: void 0
222
222
  });
223
+ /** RFC 7675 consent-to-send: application data may use the selected pair. */
224
+ Object.defineProperty(this, "consentFresh", {
225
+ enumerable: true,
226
+ configurable: true,
227
+ writable: true,
228
+ value: false
229
+ });
230
+ /** Invalidates in-flight consent callbacks on restart / close / replace / expire. */
231
+ Object.defineProperty(this, "consentSessionId", {
232
+ enumerable: true,
233
+ configurable: true,
234
+ writable: true,
235
+ value: 0
236
+ });
237
+ Object.defineProperty(this, "consentExpiryTimer", {
238
+ enumerable: true,
239
+ configurable: true,
240
+ writable: true,
241
+ value: void 0
242
+ });
243
+ Object.defineProperty(this, "consentRequestAbort", {
244
+ enumerable: true,
245
+ configurable: true,
246
+ writable: true,
247
+ value: void 0
248
+ });
223
249
  Object.defineProperty(this, "onData", {
224
250
  enumerable: true,
225
251
  configurable: true,
@@ -238,7 +264,7 @@ class Connection {
238
264
  writable: true,
239
265
  value: new common_1.Event()
240
266
  });
241
- // 4.1.1.4 ? 生存確認 life check
267
+ // RFC 7675 consent freshness
242
268
  Object.defineProperty(this, "queryConsent", {
243
269
  enumerable: true,
244
270
  configurable: true,
@@ -247,70 +273,164 @@ class Connection {
247
273
  if (this.iceLite) {
248
274
  return;
249
275
  }
250
- if (this.queryConsentHandle) {
251
- this.queryConsentHandle.resolve();
252
- }
253
- this.queryConsentHandle = (0, helper_1.cancelable)(async (_, __, onCancel) => {
254
- let failures = 0;
276
+ // Invalidate any previous consent session before starting a new one.
277
+ this.stopConsentLifecycle();
278
+ const sessionId = this.consentSessionId;
279
+ this.consentFresh = true;
280
+ const handle = (0, helper_1.cancelable)(async (_, __, onCancel) => {
255
281
  let canceled = false;
256
282
  const cancelEvent = new AbortController();
283
+ const clearConsentExpiry = () => {
284
+ if (this.consentExpiryTimer === undefined) {
285
+ return;
286
+ }
287
+ clearTimeout(this.consentExpiryTimer);
288
+ this.consentExpiryTimer = undefined;
289
+ };
290
+ const refreshConsentExpiry = () => {
291
+ // Only the active session may refresh the shared expiry timer.
292
+ if (canceled || sessionId !== this.consentSessionId) {
293
+ return;
294
+ }
295
+ clearConsentExpiry();
296
+ this.consentExpiryTimer = setTimeout(() => {
297
+ this.consentExpiryTimer = undefined;
298
+ if (canceled || sessionId !== this.consentSessionId) {
299
+ return;
300
+ }
301
+ if (this.state === "closed" || this.state === "failed") {
302
+ return;
303
+ }
304
+ log("Consent to send expired");
305
+ // Expire independently of request cadence / failure count (RFC 7675).
306
+ this.consentFresh = false;
307
+ this.consentSessionId++;
308
+ this.consentRequestAbort?.abort();
309
+ this.consentRequestAbort = undefined;
310
+ if (this.queryConsentHandle === handle) {
311
+ this.queryConsentHandle = undefined;
312
+ }
313
+ canceled = true;
314
+ cancelEvent.abort();
315
+ // Transport stays available for ICE restart; explicit close() uses "closed".
316
+ this.setState("failed");
317
+ }, iceBase_1.CONSENT_TIMEOUT * 1000);
318
+ };
257
319
  onCancel.once(() => {
258
320
  canceled = true;
259
- failures += iceBase_1.CONSENT_FAILURES;
321
+ // Avoid clearing a replacement session's timer/handle.
322
+ if (sessionId === this.consentSessionId) {
323
+ clearConsentExpiry();
324
+ this.consentRequestAbort?.abort();
325
+ this.consentRequestAbort = undefined;
326
+ }
260
327
  cancelEvent.abort();
261
- this.queryConsentHandle = undefined;
328
+ if (this.queryConsentHandle === handle) {
329
+ this.queryConsentHandle = undefined;
330
+ }
262
331
  });
263
- const { localUsername, remoteUsername, iceControlling } = this;
264
- // """
265
- // Periodically check consent (RFC 7675).
266
- // """
332
+ // Initial ICE check success is the first valid consent response.
333
+ refreshConsentExpiry();
334
+ const randomizedConsentInterval = () => iceBase_1.CONSENT_INTERVAL * (0.8 + 0.4 * Math.random()) * 1000;
335
+ // Cadence is measured between request *starts*, not response completions.
336
+ let nextConsentAt = Date.now() + randomizedConsentInterval();
337
+ const isTerminalState = () => this.state === "closed" || this.state === "failed";
267
338
  try {
268
- while (this.state !== "closed" && !canceled) {
269
- // # randomize between 0.8 and 1.2 times CONSENT_INTERVAL
270
- await timers.setTimeout(iceBase_1.CONSENT_INTERVAL * (0.8 + 0.4 * Math.random()) * 1000, undefined, { signal: cancelEvent.signal });
339
+ while (!isTerminalState() &&
340
+ !canceled &&
341
+ sessionId === this.consentSessionId) {
342
+ await this.abortableDelay(Math.max(0, nextConsentAt - Date.now()), cancelEvent.signal);
343
+ if (canceled ||
344
+ isTerminalState() ||
345
+ sessionId !== this.consentSessionId) {
346
+ break;
347
+ }
348
+ // Fix next start time before awaiting any response (independent timers).
349
+ nextConsentAt = Date.now() + randomizedConsentInterval();
271
350
  const nominated = this.nominated;
272
- if (!nominated || canceled) {
351
+ if (!nominated) {
273
352
  break;
274
353
  }
354
+ const pairId = nominated.id;
355
+ const generation = this.generation;
356
+ const remotePassword = this.remotePassword;
357
+ const { localUsername, remoteUsername, iceControlling } = this;
275
358
  const request = this.buildRequest({
276
- nominate: false,
359
+ nominate: this.shouldNominateConsentRequest(nominated),
277
360
  localUsername,
278
361
  remoteUsername,
279
362
  iceControlling,
280
363
  localCandidate: nominated.localCandidate,
281
364
  });
282
- try {
283
- nominated.consentRequestsSent++;
284
- nominated.requestsSent++;
285
- await nominated.protocol.request(request, nominated.remoteAddr, Buffer.from(this.remotePassword, "utf8"), 0, (attempt) => {
365
+ this.consentRequestAbort?.abort();
366
+ const requestAbort = new AbortController();
367
+ this.consentRequestAbort = requestAbort;
368
+ nominated.consentRequestsSent++;
369
+ nominated.requestsSent++;
370
+ // RTT-aware wait (floor 500ms); independent of retransmissions: 0.
371
+ const responseTimeout = (0, iceBase_1.consentResponseTimeoutMs)(nominated.rtt);
372
+ const requestStartedAt = performance.now();
373
+ // Do not await here: response wait must not stretch the 4–6s cadence.
374
+ nominated.protocol
375
+ .request(request, nominated.remoteAddr, Buffer.from(remotePassword, "utf8"), {
376
+ retransmissions: 0,
377
+ responseTimeout,
378
+ signal: requestAbort.signal,
379
+ onRequestSent: (attempt) => {
286
380
  if (attempt > 0) {
287
381
  nominated.retransmissionsSent++;
288
382
  }
289
- });
383
+ },
384
+ })
385
+ .then(() => {
386
+ // Accept only responses for the current pair / generation / session.
387
+ // Address / MESSAGE-INTEGRITY / response class are enforced in Transaction + protocol.
388
+ if (sessionId !== this.consentSessionId || canceled) {
389
+ return;
390
+ }
391
+ const state = this.state;
392
+ if (state === "closed" || state === "failed") {
393
+ return;
394
+ }
395
+ if (this.nominated?.id !== pairId) {
396
+ return;
397
+ }
398
+ if (this.generation !== generation) {
399
+ return;
400
+ }
401
+ if (this.remotePassword !== remotePassword) {
402
+ return;
403
+ }
404
+ const rtt = (performance.now() - requestStartedAt) / 1000; // seconds
405
+ nominated.rtt = rtt;
406
+ nominated.totalRoundTripTime += rtt;
407
+ nominated.roundTripTimeMeasurements++;
290
408
  nominated.responsesReceived++;
291
- failures = 0;
292
- if (this.state === "disconnected") {
409
+ this.consentFresh = true;
410
+ refreshConsentExpiry();
411
+ if (state === "disconnected") {
293
412
  this.setState("connected");
294
413
  }
295
- }
296
- catch (error) {
297
- if (nominated.id === this.nominated?.id) {
298
- log("no stun response");
299
- failures++;
300
- this.setState("disconnected");
301
- break;
414
+ })
415
+ .catch((error) => {
416
+ // Individual request loss is expected; keep monitoring (RFC 7675).
417
+ if (sessionId === this.consentSessionId &&
418
+ this.nominated?.id === pairId) {
419
+ log("no stun response", error);
302
420
  }
303
- }
304
- if (failures >= iceBase_1.CONSENT_FAILURES) {
305
- log("Consent to send expired");
306
- this.queryConsentHandle = undefined;
307
- this.setState("closed");
308
- break;
309
- }
421
+ });
422
+ }
423
+ }
424
+ catch (error) {
425
+ // Abort during delay is normal on cancel / expire.
426
+ }
427
+ finally {
428
+ if (sessionId === this.consentSessionId) {
429
+ clearConsentExpiry();
310
430
  }
311
431
  }
312
- catch (error) { }
313
432
  });
433
+ this.queryConsentHandle = handle;
314
434
  }
315
435
  });
316
436
  Object.defineProperty(this, "send", {
@@ -318,17 +438,15 @@ class Connection {
318
438
  configurable: true,
319
439
  writable: true,
320
440
  value: async (data) => {
321
- const activePair = this.nominated;
322
- if (activePair) {
323
- await activePair.protocol.sendData(data, activePair.remoteAddr);
324
- // Update statistics
325
- activePair.packetsSent++;
326
- activePair.bytesSent += data.length;
327
- }
328
- else {
329
- // log("Cannot send data, ice not connected");
441
+ // RFC 7675: after consent expiry, do not send application data on the 5-tuple.
442
+ if (!this.canSendApplicationData()) {
330
443
  return;
331
444
  }
445
+ const activePair = this.nominated;
446
+ await activePair.protocol.sendData(data, activePair.remoteAddr);
447
+ // Update statistics
448
+ activePair.packetsSent++;
449
+ activePair.bytesSent += data.length;
332
450
  }
333
451
  });
334
452
  // 3. Terminology : Check
@@ -492,13 +610,13 @@ class Connection {
492
610
  if (this.iceLite) {
493
611
  value = false;
494
612
  }
495
- if (this.generation > 0 || this.nominated) {
613
+ // While a pair is selected, keep the negotiated role. ICE restart clears
614
+ // `nominated`, so offer/answer role and RFC 8445 role-conflict repair can
615
+ // reassign controlling/controlled for the new generation.
616
+ if (this.nominated) {
496
617
  return;
497
618
  }
498
- this._iceControlling = value;
499
- for (const pair of this.checkList) {
500
- pair.iceControlling = value;
501
- }
619
+ this.applyIceControlling(value);
502
620
  }
503
621
  get iceLite() {
504
622
  return this.options.iceLite;
@@ -538,13 +656,15 @@ class Connection {
538
656
  protocol.localCandidate.ufrag = this.localUsername;
539
657
  }
540
658
  }
541
- this.queryConsentHandle?.resolve?.();
542
- this.queryConsentHandle = undefined;
659
+ // Tear down consent timers/transactions; new credentials require a new session.
660
+ this.stopConsentLifecycle();
543
661
  }
544
662
  resetNominatedPair() {
545
663
  log("resetNominatedPair");
546
664
  this.nominated = undefined;
547
665
  this.nominating = false;
666
+ // Drop old pair's consent timers/transactions; restarted when a new pair is nominated.
667
+ this.stopConsentLifecycle();
548
668
  }
549
669
  setRemoteParams({ iceLite, usernameFragment, password, }) {
550
670
  log("setRemoteParams", { iceLite, usernameFragment, password });
@@ -556,6 +676,15 @@ class Connection {
556
676
  async gatherCandidates() {
557
677
  if (!this.localCandidatesStart) {
558
678
  this.localCandidatesStart = true;
679
+ // ICE restart keeps transport protocols; re-advertise their host candidates
680
+ // with the new generation / ufrag before gathering additional addresses.
681
+ for (const protocol of this.protocols) {
682
+ if (protocol.localCandidate) {
683
+ protocol.localCandidate.generation = this.generation;
684
+ protocol.localCandidate.ufrag = this.localUsername;
685
+ this.appendLocalCandidate(protocol.localCandidate);
686
+ }
687
+ }
559
688
  let address = (0, utils_1.getHostAddresses)(this.options.useIpv4, this.options.useIpv6, {
560
689
  useLinkLocalAddress: this.options.useLinkLocalAddress,
561
690
  });
@@ -917,13 +1046,69 @@ class Connection {
917
1046
  }
918
1047
  return false;
919
1048
  }
1049
+ /**
1050
+ * Stop consent request cadence, expiry timer, and outstanding transactions.
1051
+ * Does not change ICE state by itself.
1052
+ */
1053
+ stopConsentLifecycle() {
1054
+ this.consentSessionId++;
1055
+ this.consentFresh = false;
1056
+ if (this.consentExpiryTimer !== undefined) {
1057
+ clearTimeout(this.consentExpiryTimer);
1058
+ this.consentExpiryTimer = undefined;
1059
+ }
1060
+ this.consentRequestAbort?.abort();
1061
+ this.consentRequestAbort = undefined;
1062
+ const handle = this.queryConsentHandle;
1063
+ this.queryConsentHandle = undefined;
1064
+ // Resolve after clearing the field so a stale onCancel cannot wipe a replacement.
1065
+ handle?.resolve?.();
1066
+ }
1067
+ /**
1068
+ * ICE-lite interop only (not required by RFC 7675): mirror libwebrtc
1069
+ * semi-aggressive nomination — attach USE-CANDIDATE when we are controlling,
1070
+ * the remote is ICE-lite, and the target is the current selected pair.
1071
+ */
1072
+ shouldNominateConsentRequest(pair) {
1073
+ return (this.iceControlling && this.remoteIsLite && this.nominated?.id === pair.id);
1074
+ }
1075
+ canSendApplicationData() {
1076
+ if (!this.nominated) {
1077
+ return false;
1078
+ }
1079
+ if (this.state === "closed" || this.state === "failed") {
1080
+ return false;
1081
+ }
1082
+ // Local ICE-lite does not run consent checks; full agents need fresh consent.
1083
+ if (this.iceLite) {
1084
+ return true;
1085
+ }
1086
+ return this.consentFresh;
1087
+ }
1088
+ abortableDelay(ms, signal) {
1089
+ return new Promise((resolve, reject) => {
1090
+ if (signal.aborted) {
1091
+ reject(new DOMException("The operation was aborted", "AbortError"));
1092
+ return;
1093
+ }
1094
+ const timer = setTimeout(() => {
1095
+ signal.removeEventListener("abort", onAbort);
1096
+ resolve();
1097
+ }, ms);
1098
+ const onAbort = () => {
1099
+ clearTimeout(timer);
1100
+ reject(new DOMException("The operation was aborted", "AbortError"));
1101
+ };
1102
+ signal.addEventListener("abort", onAbort, { once: true });
1103
+ });
1104
+ }
920
1105
  async close() {
921
1106
  // """
922
1107
  // Close the connection.
923
1108
  // """
924
1109
  this.setState("closed");
925
1110
  // # stop consent freshness tests
926
- this.queryConsentHandle?.resolve?.();
1111
+ this.stopConsentLifecycle();
927
1112
  // # stop check list
928
1113
  if (this.checkList && !this.checkListDone) {
929
1114
  this.checkListState.put(new Promise((r) => {
@@ -1012,9 +1197,20 @@ class Connection {
1012
1197
  const pair = this.checkList.find((pair) => pair.protocol === protocol && pair.remoteCandidate === remoteCandidate);
1013
1198
  return pair;
1014
1199
  }
1200
+ applyIceControlling(iceControlling) {
1201
+ this._iceControlling = iceControlling;
1202
+ for (const pair of this.checkList) {
1203
+ pair.iceControlling = iceControlling;
1204
+ }
1205
+ }
1015
1206
  switchRole(iceControlling) {
1016
1207
  log("switch role", iceControlling);
1017
- this.iceControlling = iceControlling;
1208
+ // Role conflicts must be repaired even after a prior generation or while
1209
+ // connectivity checks are in flight (RFC 8445 §7.2.5.1 / §7.3.1.1).
1210
+ if (this.iceLite) {
1211
+ iceControlling = false;
1212
+ }
1213
+ this.applyIceControlling(iceControlling);
1018
1214
  this.sortCheckList();
1019
1215
  }
1020
1216
  checkComplete(pair) {
@@ -1035,6 +1231,12 @@ class Connection {
1035
1231
  this.nominated = pair;
1036
1232
  this.nominating = false;
1037
1233
  this.pruneTcpConnections(pair);
1234
+ // After resetNominatedPair / renomination while already connected,
1235
+ // restart consent freshness on the new selected pair.
1236
+ if (!this.iceLite &&
1237
+ (this.state === "connected" || this.state === "completed")) {
1238
+ this.queryConsent();
1239
+ }
1038
1240
  // 8.1.2. Updating States
1039
1241
  // The agent MUST remove all Waiting and Frozen pairs in the check
1040
1242
  // list and triggered check queue for the same component as the