From 1d52ee03c3816200b0e3065792c53e3627ddf46a Mon Sep 17 00:00:00 2001 From: mertushka Date: Mon, 29 Jun 2026 16:57:24 +0300 Subject: [PATCH] fix: align certificate types and close gathering state --- docs/divergences.md | 3 +++ index.d.ts | 4 +--- lib/index.js | 1 + test/basic.test.js | 16 ++++++++++++++++ test/types.ts | 2 ++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/divergences.md b/docs/divergences.md index fe06883..fea0c98 100644 --- a/docs/divergences.md +++ b/docs/divergences.md @@ -78,6 +78,9 @@ rejects `setConfiguration()` calls that change the certificate set, and passes the first configured certificate into libdatachannel's `rtc::Configuration` so the generated DTLS fingerprint appears in local SDP. +Certificate generation supports object-form ECDSA P-256 and RSA SHA-256 +algorithms. String-form WebCrypto `AlgorithmIdentifier` values are rejected. + libdatachannel accepts one certificate/key pair for a peer connection. The W3C configuration dictionary allows a sequence of certificates, and WPT has a case that expects all configured certificate fingerprints to appear in SDP. The diff --git a/index.d.ts b/index.d.ts index b0a33e4..c971a0d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -280,9 +280,7 @@ export class RTCSctpTransport extends EventTarget { } export class RTCPeerConnection extends EventTarget { - static generateCertificate( - algorithm: string | RTCCertificateKeygenAlgorithm, - ): Promise; + static generateCertificate(algorithm: RTCCertificateKeygenAlgorithm): Promise; constructor(configuration?: RTCConfiguration); readonly localDescription: RTCSessionDescription | null; readonly currentLocalDescription: RTCSessionDescription | null; diff --git a/lib/index.js b/lib/index.js index 79a711e..2c7df04 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3369,6 +3369,7 @@ class RTCPeerConnection extends SimpleEventTarget { }); this._connectionState = "closed"; this._iceConnectionState = "closed"; + this._iceGatheringState = "new"; this._deferredIceEvents = []; this._preparedLocalDescription = null; this._nonstandardPreparedLocalDescriptionType = null; diff --git a/test/basic.test.js b/test/basic.test.js index bf1a988..a848f97 100644 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -615,6 +615,22 @@ test("generateCertificate returns a native-backed RTCCertificate", async (t) => pc.close(); }); +test("generateCertificate rejects string-form algorithms", async () => { + await assert.rejects( + RTCPeerConnection.generateCertificate("ECDSA"), + (error) => error.name === "NotSupportedError", + ); +}); + +test("close resets iceGatheringState to new", () => { + const pc = new RTCPeerConnection(); + + pc._iceGatheringState = "complete"; + pc.close(); + + assert.equal(pc.iceGatheringState, "new"); +}); + test("createDataChannel rejects duplicate negotiated ids until the channel closes", async (t) => { const pc = new RTCPeerConnection(); t.after(() => closeAllAndWait(pc)); diff --git a/test/types.ts b/test/types.ts index 85f50cc..717b32a 100644 --- a/test/types.ts +++ b/test/types.ts @@ -54,6 +54,8 @@ const certificatePromise: Promise = RTCPeerConnection.generateCe namedCurve: "P-256", expires: 60000, }); +// @ts-expect-error string-form certificate algorithms are not supported. +RTCPeerConnection.generateCertificate("ECDSA"); const pc = new RTCPeerConnection(); pc.setConfiguration({ iceServers: [{ urls: "stun:stun.example.org" }], iceCandidatePoolSize: 0 }); const configuration = pc.getConfiguration();