diff --git a/packages/connection-encrypter-tls/src/tls.ts b/packages/connection-encrypter-tls/src/tls.ts index 37a00b0a0e..c7af583e4e 100644 --- a/packages/connection-encrypter-tls/src/tls.ts +++ b/packages/connection-encrypter-tls/src/tls.ts @@ -90,6 +90,12 @@ export class TLS implements ConnectionEncrypter { async _encrypt > = MultiaddrConnection> (conn: Stream, isServer: boolean, options?: SecureConnectionOptions): Promise> { let streamMuxer: StreamMuxerFactory | undefined + let streamMuxers: string[] = [] + + if (options?.skipStreamMuxerNegotiation !== true) { + streamMuxers = [...this.components.upgrader.getStreamMuxers().keys()] + } + const opts: TLSSocketOptions = { ...await generateCertificate(this.components.privateKey), isServer, @@ -101,7 +107,7 @@ export class TLS implements ConnectionEncrypter { // early negotiation of muxer via ALPN protocols ALPNProtocols: [ - ...this.components.upgrader.getStreamMuxers().keys(), + ...streamMuxers, 'libp2p' ], ALPNCallback: ({ protocols }) => { @@ -158,17 +164,9 @@ export class TLS implements ConnectionEncrypter { .then(remotePeer => { this.log('remote certificate ok, remote peer %p', remotePeer) - if (!isServer && typeof socket.alpnProtocol === 'string') { - streamMuxer = this.components.upgrader.getStreamMuxers().get(socket.alpnProtocol) - - if (streamMuxer == null) { - this.log.error('selected muxer that did not exist') - } - } - // 'libp2p' is a special protocol - if it's sent the remote does not // support early muxer negotiation - if (!isServer && typeof socket.alpnProtocol === 'string' && socket.alpnProtocol !== 'libp2p') { + if (!isServer && typeof socket.alpnProtocol === 'string' && socket.alpnProtocol !== 'libp2p' && options?.skipStreamMuxerNegotiation !== true) { this.log.trace('got early muxer', socket.alpnProtocol) streamMuxer = this.components.upgrader.getStreamMuxers().get(socket.alpnProtocol) diff --git a/packages/connection-encrypter-tls/test/index.spec.ts b/packages/connection-encrypter-tls/test/index.spec.ts index 76a53c9811..6f7a051305 100644 --- a/packages/connection-encrypter-tls/test/index.spec.ts +++ b/packages/connection-encrypter-tls/test/index.spec.ts @@ -113,4 +113,26 @@ describe('tls', () => { expect(result).to.have.nested.property('[0].streamMuxer.protocol', '/test/muxer') expect(result).to.have.nested.property('[1].streamMuxer.protocol', '/test/muxer') }) + + it('should not select an early muxer when it is skipped', async () => { + const [inbound, outbound] = duplexPair() + + const result = await Promise.all([ + encrypter.secureInbound(stubInterface({ + ...inbound + }), { + remotePeer: localPeer, + skipStreamMuxerNegotiation: true + }), + encrypter.secureOutbound(stubInterface({ + ...outbound + }), { + remotePeer: localPeer, + skipStreamMuxerNegotiation: true + }) + ]) + + expect(result).to.have.nested.property('[0].streamMuxer', undefined) + expect(result).to.have.nested.property('[1].streamMuxer', undefined) + }) }) diff --git a/packages/interface/src/connection-encrypter.ts b/packages/interface/src/connection-encrypter.ts index 596cbdb92a..05607b5c20 100644 --- a/packages/interface/src/connection-encrypter.ts +++ b/packages/interface/src/connection-encrypter.ts @@ -11,6 +11,14 @@ import type { Uint8ArrayList } from 'uint8arraylist' */ export interface SecureConnectionOptions extends AbortOptions { remotePeer?: PeerId + + /** + * Some encryption protocols allow negotiating application protocols as part + * of the initial handshake. The negotiated stream muxer protocol will be + * included as part of the from the `secureOutbound`/`secureInbound` methods + * unless `false` is passed here. + */ + skipStreamMuxerNegotiation?: boolean } /**