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.
- package/lib/dtls/src/context/transport.d.ts +2 -2
- package/lib/dtls/src/context/transport.js +2 -2
- package/lib/dtls/src/context/transport.js.map +1 -1
- package/lib/dtls/src/socket.d.ts +3 -2
- package/lib/dtls/src/socket.js +2 -2
- package/lib/dtls/src/socket.js.map +1 -1
- package/lib/ice/src/ice.d.ts +20 -0
- package/lib/ice/src/ice.js +259 -57
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +22 -1
- package/lib/ice/src/iceBase.js +30 -1
- package/lib/ice/src/iceBase.js.map +1 -1
- package/lib/ice/src/stun/protocol.d.ts +2 -2
- package/lib/ice/src/stun/protocol.js +17 -3
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/tcpProtocol.d.ts +2 -2
- package/lib/ice/src/stun/tcpProtocol.js +13 -3
- package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.d.ts +41 -4
- package/lib/ice/src/stun/transaction.js +193 -24
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +3 -3
- package/lib/ice/src/turn/protocol.js +31 -6
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +27 -1
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/ice-server/src/stun/message.js +8 -0
- package/lib/ice-server/src/stun/message.js.map +1 -1
- package/lib/index.mjs +435 -104
- package/lib/webrtc/src/peerConnection.d.ts +2 -2
- package/lib/webrtc/src/secureTransportManager.d.ts +1 -1
- package/lib/webrtc/src/secureTransportManager.js +12 -0
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.d.ts +1 -1
- 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
|
}
|
|
@@ -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;
|
|
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"]}
|
package/lib/dtls/src/socket.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Event
|
|
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;
|
package/lib/dtls/src/socket.js
CHANGED
|
@@ -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"]}
|
package/lib/ice/src/ice.d.ts
CHANGED
|
@@ -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) => {
|
package/lib/ice/src/ice.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.
|
|
254
|
-
|
|
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
|
-
|
|
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
|
|
328
|
+
if (this.queryConsentHandle === handle) {
|
|
329
|
+
this.queryConsentHandle = undefined;
|
|
330
|
+
}
|
|
262
331
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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 (
|
|
269
|
-
|
|
270
|
-
|
|
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
|
|
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:
|
|
359
|
+
nominate: this.shouldNominateConsentRequest(nominated),
|
|
277
360
|
localUsername,
|
|
278
361
|
remoteUsername,
|
|
279
362
|
iceControlling,
|
|
280
363
|
localCandidate: nominated.localCandidate,
|
|
281
364
|
});
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
292
|
-
|
|
409
|
+
this.consentFresh = true;
|
|
410
|
+
refreshConsentExpiry();
|
|
411
|
+
if (state === "disconnected") {
|
|
293
412
|
this.setState("connected");
|
|
294
413
|
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
322
|
-
if (
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
542
|
-
this.
|
|
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.
|
|
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
|
-
|
|
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
|