diff --git a/examples/browser-to-browser/package.json b/examples/browser-to-browser/package.json index ecee66d..8dbabf1 100644 --- a/examples/browser-to-browser/package.json +++ b/examples/browser-to-browser/package.json @@ -9,7 +9,7 @@ "relay": "node relay.js", "test:firefox": "npm run build && playwright test --browser=firefox tests", "test:chrome": "npm run build && playwright test tests", - "test": "npm run test:firefox && npm run test:chrome" + "test": "npm run build && playwright test tests && playwright test --browser firefox tests" }, "dependencies": { "@chainsafe/libp2p-noise": "^11.0.0", diff --git a/examples/browser-to-browser/tests/test.js b/examples/browser-to-browser/tests/test.spec.js similarity index 100% rename from examples/browser-to-browser/tests/test.js rename to examples/browser-to-browser/tests/test.spec.js diff --git a/examples/browser-to-server/package.json b/examples/browser-to-server/package.json index 1dfc40f..68c708b 100644 --- a/examples/browser-to-server/package.json +++ b/examples/browser-to-server/package.json @@ -7,7 +7,9 @@ "start": "vite", "build": "vite build", "go-libp2p-server": "cd ../go-libp2p-server && go run ./main.go", - "test": "npm run build && playwright test tests" + "test:chrome": "npm run build && playwright test tests", + "test:firefox": "npm run build && playwright test --browser firefox tests", + "test": "npm run build && playwright test tests && playwright test --browser firefox tests" }, "dependencies": { "@chainsafe/libp2p-noise": "^11.0.0", diff --git a/examples/browser-to-server/tests/test.js b/examples/browser-to-server/tests/test.spec.js similarity index 99% rename from examples/browser-to-server/tests/test.js rename to examples/browser-to-server/tests/test.spec.js index 8f304e7..6f6e5e9 100644 --- a/examples/browser-to-server/tests/test.js +++ b/examples/browser-to-server/tests/test.spec.js @@ -90,12 +90,9 @@ play.describe('bundle ipfs with parceljs:', () => { // Received message '${message}' const connections = await page.textContent(output) - expect(connections).toContain(`Dialing '${serverAddr}'`) expect(connections).toContain(`Peer connected '${serverAddr}'`) - - expect(connections).toContain(`Sending message '${message}'`) expect(connections).toContain(`Received message '${message}'`) }) diff --git a/src/sdp.ts b/src/sdp.ts index 8c3b6c6..1f3ac5a 100644 --- a/src/sdp.ts +++ b/src/sdp.ts @@ -15,6 +15,37 @@ const log = logger('libp2p:webrtc:sdp') // @ts-expect-error - Not easy to combine these types. export const mbdecoder: any = Object.values(bases).map(b => b.decoder).reduce((d, b) => d.or(b)) +export function getLocalFingerprint (pc: RTCPeerConnection): string | undefined { + // try to fetch fingerprint from local certificate + const localCert = pc.getConfiguration().certificates?.at(0) + if (localCert == null || localCert.getFingerprints == null) { + log.trace('fetching fingerprint from local SDP') + const localDescription = pc.localDescription + if (localDescription == null) { + return undefined + } + return getFingerprintFromSdp(localDescription.sdp) + } + + log.trace('fetching fingerprint from local certificate') + + if (localCert.getFingerprints().length === 0) { + return undefined + } + + const fingerprint = localCert.getFingerprints()[0].value + if (fingerprint == null) { + throw invalidFingerprint('', 'no fingerprint on local certificate') + } + + return fingerprint +} + +const fingerprintRegex = /^a=fingerprint:(?:\w+-[0-9]+)\s(?(:?[0-9a-fA-F]{2})+)$/m +export function getFingerprintFromSdp (sdp: string): string | undefined { + const searchResult = sdp.match(fingerprintRegex) + return searchResult?.groups?.fingerprint +} /** * Get base2 | identity decoders */ diff --git a/src/stream.ts b/src/stream.ts index 2f61de9..4124704 100644 --- a/src/stream.ts +++ b/src/stream.ts @@ -213,6 +213,7 @@ export class WebRTCStream implements Stream { constructor (opts: StreamInitOpts) { this.channel = opts.channel + this.channel.binaryType = 'arraybuffer' this.id = this.channel.label this.stat = opts.stat diff --git a/src/transport.ts b/src/transport.ts index 38f6382..d143c7b 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -118,6 +118,7 @@ export class WebRTCDirectTransport implements Transport { namedCurve: 'P-256', hash: sdp.toSupportedHashFunction(remoteCerthash.name) } as any) + const peerConnection = new RTCPeerConnection({ certificates: [certificate] }) // create data channel for running the noise handshake. Once the data channel is opened, @@ -181,12 +182,24 @@ export class WebRTCDirectTransport implements Transport { source: { [Symbol.asyncIterator]: async function * () { for await (const list of wrappedChannel.source) { - yield list.subarray() + for (const buf of list) { + yield buf + } } } } } + // Creating the connection before completion of the noise + // handshake ensures that the stream opening callback is set up + const maConn = new WebRTCMultiaddrConnection({ + peerConnection, + remoteAddr: ma, + timeline: { + open: Date.now() + } + }) + const eventListeningName = isFirefox ? 'iceconnectionstatechange' : 'connectionstatechange' peerConnection.addEventListener(eventListeningName, () => { @@ -206,16 +219,6 @@ export class WebRTCDirectTransport implements Transport { } }, { signal }) - // Creating the connection before completion of the noise - // handshake ensures that the stream opening callback is set up - const maConn = new WebRTCMultiaddrConnection({ - peerConnection, - remoteAddr: ma, - timeline: { - open: Date.now() - } - }) - const muxerFactory = new DataChannelMuxerFactory(peerConnection) // For outbound connections, the remote is expected to start the noise handshake. @@ -234,19 +237,12 @@ export class WebRTCDirectTransport implements Transport { throw invalidArgument('no local certificate') } - const localCert = pc.getConfiguration().certificates?.at(0) - - if (localCert === undefined || localCert.getFingerprints().length === 0) { - throw invalidArgument('no fingerprint on local certificate') - } - - const localFingerprint = localCert.getFingerprints()[0] - - if (localFingerprint.value === undefined) { - throw invalidArgument('no fingerprint on local certificate') + const localFingerprint = sdp.getLocalFingerprint(pc) + if (localFingerprint == null) { + throw invalidArgument('no local fingerprint found') } - const localFpString = localFingerprint.value.replace(/:/g, '') + const localFpString = localFingerprint.trim().toLowerCase().replaceAll(':', '') const localFpArray = uint8arrayFromString(localFpString, 'hex') const local = multihashes.encode(localFpArray, hashCode) const remote: Uint8Array = sdp.mbdecoder.decode(sdp.certhash(ma)) diff --git a/test/sdp.spec.ts b/test/sdp.spec.ts index 8472f0d..dcc5c24 100644 --- a/test/sdp.spec.ts +++ b/test/sdp.spec.ts @@ -53,6 +53,11 @@ describe('SDP', () => { ]) }) + it('extracts a fingerprint from sdp', () => { + const fingerprint = underTest.getFingerprintFromSdp(sampleSdp) + expect(fingerprint).to.eq('72:68:47:CD:48:B0:5E:C5:60:4D:15:9C:BF:40:1D:6F:00:A1:23:EC:90:17:0E:2C:D1:B3:8F:D2:9D:37:E5:B1') + }) + it('munges the ufrag and pwd in a SDP', () => { const result = underTest.munge({ type: 'answer', sdp: sampleSdp }, 'someotheruserfragmentstring') const expected = `v=0