diff --git a/packages/transport-webrtc/package.json b/packages/transport-webrtc/package.json index ab53a2b663..46302127ae 100644 --- a/packages/transport-webrtc/package.json +++ b/packages/transport-webrtc/package.json @@ -51,6 +51,7 @@ "@libp2p/peer-id": "^3.0.2", "@multiformats/mafmt": "^12.1.2", "@multiformats/multiaddr": "^12.1.5", + "@multiformats/multiaddr-matcher": "^1.0.1", "abortable-iterator": "^5.0.1", "detect-browser": "^5.3.0", "it-length-prefixed": "^9.0.1", diff --git a/packages/transport-webrtc/src/private-to-private/transport.ts b/packages/transport-webrtc/src/private-to-private/transport.ts index 1dd1804140..9ab8de1f1e 100644 --- a/packages/transport-webrtc/src/private-to-private/transport.ts +++ b/packages/transport-webrtc/src/private-to-private/transport.ts @@ -2,7 +2,8 @@ import { CodeError } from '@libp2p/interface/errors' import { type CreateListenerOptions, type DialOptions, symbol, type Transport, type Listener, type Upgrader } from '@libp2p/interface/transport' import { logger } from '@libp2p/logger' import { peerIdFromString } from '@libp2p/peer-id' -import { multiaddr, type Multiaddr, protocols } from '@multiformats/multiaddr' +import { multiaddr, type Multiaddr } from '@multiformats/multiaddr' +import { WebRTC } from '@multiformats/multiaddr-matcher' import { codes } from '../error.js' import { WebRTCMultiaddrConnection } from '../maconn.js' import { cleanup } from '../webrtc/index.js' @@ -21,7 +22,6 @@ const log = logger('libp2p:webrtc:peer') const WEBRTC_TRANSPORT = '/webrtc' const CIRCUIT_RELAY_TRANSPORT = '/p2p-circuit' const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1' -const WEBRTC_CODE = protocols('webrtc').code export interface WebRTCTransportInit { rtcConfiguration?: RTCConfiguration @@ -91,10 +91,7 @@ export class WebRTCTransport implements Transport, Startable { readonly [symbol] = true filter (multiaddrs: Multiaddr[]): Multiaddr[] { - return multiaddrs.filter((ma) => { - const codes = ma.protoCodes() - return codes.includes(WEBRTC_CODE) - }) + return multiaddrs.filter(WebRTC.exactMatch) } /* diff --git a/packages/transport-webrtc/src/private-to-public/transport.ts b/packages/transport-webrtc/src/private-to-public/transport.ts index b0c37a7306..23bb5d1994 100644 --- a/packages/transport-webrtc/src/private-to-public/transport.ts +++ b/packages/transport-webrtc/src/private-to-public/transport.ts @@ -3,6 +3,7 @@ import { type CreateListenerOptions, symbol, type Transport, type Listener } fro import { logger } from '@libp2p/logger' import * as p from '@libp2p/peer-id' import { protocols } from '@multiformats/multiaddr' +import { WebRTCDirect } from '@multiformats/multiaddr-matcher' import * as multihashes from 'multihashes' import { concat } from 'uint8arrays/concat' import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' @@ -95,7 +96,7 @@ export class WebRTCDirectTransport implements Transport { * Takes a list of `Multiaddr`s and returns only valid addresses for the transport */ filter (multiaddrs: Multiaddr[]): Multiaddr[] { - return multiaddrs.filter(validMa) + return multiaddrs.filter(WebRTCDirect.exactMatch) } /** @@ -275,12 +276,3 @@ export class WebRTCDirectTransport implements Transport { return concat([prefix, local, remote]) } } - -/** - * Determine if a given multiaddr contains a WebRTC Code (280), - * a Certhash Code (466) and a PeerId - */ -function validMa (ma: Multiaddr): boolean { - const codes = ma.protoCodes() - return codes.includes(WEBRTC_CODE) && codes.includes(CERTHASH_CODE) && ma.getPeerId() != null && !codes.includes(protocols('p2p-circuit').code) -} diff --git a/packages/transport-webrtc/test/peer.browser.spec.ts b/packages/transport-webrtc/test/peer.browser.spec.ts index 8d490ff967..623a8a8542 100644 --- a/packages/transport-webrtc/test/peer.browser.spec.ts +++ b/packages/transport-webrtc/test/peer.browser.spec.ts @@ -106,7 +106,7 @@ describe('webrtc filter', () => { }, {}) const valid = [ - multiaddr('/ip4/127.0.0.1/tcp/1234/ws/p2p-circuit/webrtc') + multiaddr('/ip4/127.0.0.1/tcp/1234/ws/p2p/12D3KooWFqpHsdZaL4NW6eVE3yjhoSDNv7HJehPZqj17kjKntAh2/p2p-circuit/webrtc/p2p/12D3KooWF2P1k8SVRL1cV1Z9aNM8EVRwbrMESyRf58ceQkaht4AF') ] expect(transport.filter(valid)).length(1) diff --git a/packages/transport-webrtc/test/transport.browser.spec.ts b/packages/transport-webrtc/test/transport.browser.spec.ts index ea7b56d545..8ba736a0d0 100644 --- a/packages/transport-webrtc/test/transport.browser.spec.ts +++ b/packages/transport-webrtc/test/transport.browser.spec.ts @@ -3,10 +3,10 @@ import { type CreateListenerOptions, symbol } from '@libp2p/interface/transport' import { mockMetrics, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' -import { multiaddr, type Multiaddr } from '@multiformats/multiaddr' -import { expect, assert } from 'aegir/chai' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' import { UnimplementedError } from '../src/error.js' -import * as underTest from '../src/private-to-public/transport.js' +import { WebRTCDirectTransport, type WebRTCDirectTransportComponents } from '../src/private-to-public/transport.js' import { expectError } from './util.js' import type { Metrics } from '@libp2p/interface/metrics' @@ -15,9 +15,9 @@ function ignoredDialOption (): CreateListenerOptions { return { upgrader } } -describe('WebRTC Transport', () => { +describe('WebRTCDirect Transport', () => { let metrics: Metrics - let components: underTest.WebRTCDirectTransportComponents + let components: WebRTCDirectTransportComponents before(async () => { metrics = mockMetrics()() @@ -28,13 +28,13 @@ describe('WebRTC Transport', () => { }) it('can construct', () => { - const t = new underTest.WebRTCDirectTransport(components) + const t = new WebRTCDirectTransport(components) expect(t.constructor.name).to.equal('WebRTCDirectTransport') }) it('can dial', async () => { const ma = multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd') - const transport = new underTest.WebRTCDirectTransport(components) + const transport = new WebRTCDirectTransport(components) const options = ignoredDialOption() // don't await as this isn't an e2e test @@ -42,7 +42,7 @@ describe('WebRTC Transport', () => { }) it('createListner throws', () => { - const t = new underTest.WebRTCDirectTransport(components) + const t = new WebRTCDirectTransport(components) try { t.createListener(ignoredDialOption()) expect('Should have thrown').to.equal('but did not') @@ -52,38 +52,38 @@ describe('WebRTC Transport', () => { }) it('toString property getter', () => { - const t = new underTest.WebRTCDirectTransport(components) + const t = new WebRTCDirectTransport(components) const s = t[Symbol.toStringTag] expect(s).to.equal('@libp2p/webrtc-direct') }) it('symbol property getter', () => { - const t = new underTest.WebRTCDirectTransport(components) + const t = new WebRTCDirectTransport(components) const s = t[symbol] expect(s).to.equal(true) }) it('transport filter filters out invalid multiaddrs', async () => { - const mas: Multiaddr[] = [ - '/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ', - '/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd', - '/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd', - '/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd' - ].map((s) => multiaddr(s)) - const t = new underTest.WebRTCDirectTransport(components) - const result = t.filter(mas) - const expected = + const valid = [ multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd') + ] + const invalid = [ + multiaddr('/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ'), + multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'), + multiaddr('/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd') + ] - assert.isNotNull(result) - expect(result.constructor.name).to.equal('Array') - expect(result).to.have.length(1) - expect(result[0].equals(expected)).to.be.true() + const t = new WebRTCDirectTransport(components) + + expect(t.filter([ + ...valid, + ...invalid + ])).to.deep.equal(valid) }) it('throws WebRTC transport error when dialing a multiaddr without a PeerId', async () => { const ma = multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ') - const transport = new underTest.WebRTCDirectTransport(components) + const transport = new WebRTCDirectTransport(components) try { await transport.dial(ma, ignoredDialOption()) diff --git a/packages/transport-webtransport/package.json b/packages/transport-webtransport/package.json index 9bf972107b..0477e70a10 100644 --- a/packages/transport-webtransport/package.json +++ b/packages/transport-webtransport/package.json @@ -72,6 +72,7 @@ "uint8arrays": "^4.0.6" }, "devDependencies": { + "@libp2p/peer-id-factory": "^3.0.3", "aegir": "^40.0.8", "libp2p": "^0.46.11", "p-defer": "^4.0.0" diff --git a/packages/transport-webtransport/src/index.ts b/packages/transport-webtransport/src/index.ts index 1654cbba64..d37e5a6564 100644 --- a/packages/transport-webtransport/src/index.ts +++ b/packages/transport-webtransport/src/index.ts @@ -2,6 +2,7 @@ import { noise } from '@chainsafe/libp2p-noise' import { type Transport, symbol, type CreateListenerOptions, type DialOptions, type Listener } from '@libp2p/interface/transport' import { logger } from '@libp2p/logger' import { type Multiaddr, type AbortOptions } from '@multiformats/multiaddr' +import { WebTransport as WebTransportMatcher } from '@multiformats/multiaddr-matcher' import { webtransportBiDiStreamToStream } from './stream.js' import { inertDuplex } from './utils/inert-duplex.js' import { isSubset } from './utils/is-subset.js' @@ -329,7 +330,7 @@ class WebTransportTransport implements Transport { * Takes a list of `Multiaddr`s and returns only valid webtransport addresses. */ filter (multiaddrs: Multiaddr[]): Multiaddr[] { - return multiaddrs.filter(ma => ma.protoNames().includes('webtransport')) + return multiaddrs.filter(WebTransportMatcher.exactMatch) } } diff --git a/packages/transport-webtransport/test/browser.ts b/packages/transport-webtransport/test/browser.ts index edafa83b76..3771545df4 100644 --- a/packages/transport-webtransport/test/browser.ts +++ b/packages/transport-webtransport/test/browser.ts @@ -89,7 +89,7 @@ describe('libp2p-webtransport', () => { const ma = multiaddr(maStrNoCerthash + '/p2p/' + maStrP2p) await expect(node.dial(ma)).to.eventually.be.rejected() - .with.property('code', 'ERR_INVALID_MULTIADDR') + .with.property('code', 'ERR_NO_VALID_ADDRESSES') }) it('fails to connect due to an aborted signal', async () => { diff --git a/packages/transport-webtransport/test/transport.spec.ts b/packages/transport-webtransport/test/transport.spec.ts new file mode 100644 index 0000000000..3a5c8c921b --- /dev/null +++ b/packages/transport-webtransport/test/transport.spec.ts @@ -0,0 +1,34 @@ +/* eslint-disable no-console */ +/* eslint-env mocha */ + +import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import { webTransport, type WebTransportComponents } from '../src/index.js' + +describe('WebTransport Transport', () => { + let components: WebTransportComponents + + beforeEach(async () => { + components = { + peerId: await createEd25519PeerId() + } + }) + + it('transport filter filters out invalid multiaddrs', async () => { + const valid = [ + multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd') + ] + const invalid = [ + multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd/p2p-circuit/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'), + multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd') + ] + + const t = webTransport()(components) + + expect(t.filter([ + ...valid, + ...invalid + ])).to.deep.equal(valid) + }) +})