Skip to content

Commit 5f92b50

Browse files
authoredAug 13, 2024··
fix: make local peer id optional (#440)
`libp2p@2.x.x` will remove the `localPeer` argument from the `secureInbound` and `secureOutbound` methods of the `ConnectionEncrypter` interface. Unfortunately the `js-libp2p` monorepo has a dependency on this module so the change cannot be released until this module is compatible... with the unreleased change. This PR tests the first argument to `secureInbound` and `secureOutbound` to ensure that it is actually a `PeerId`. If not it shuffles all the arguments along by one place. This PR can be reverted and the first argument removed once `libp2p@2.x.x` is released.
1 parent 0a349b6 commit 5f92b50

File tree

5 files changed

+101
-20
lines changed

5 files changed

+101
-20
lines changed
 

‎src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Noise } from './noise.js'
22
import type { NoiseInit } from './noise.js'
33
import type { NoiseExtensions } from './proto/payload.js'
4-
import type { ComponentLogger, ConnectionEncrypter, Metrics } from '@libp2p/interface'
4+
import type { ComponentLogger, ConnectionEncrypter, Metrics, PeerId } from '@libp2p/interface'
55
export type { ICryptoInterface } from './crypto.js'
66
export { pureJsCrypto } from './crypto/js.js'
77

88
export interface NoiseComponents {
9+
peerId: PeerId
910
logger: ComponentLogger
1011
metrics?: Metrics
1112
}

‎src/noise.ts

+37-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { unmarshalPrivateKey } from '@libp2p/crypto/keys'
2-
import { type MultiaddrConnection, type SecuredConnection, type PeerId, CodeError, type PrivateKey, serviceCapabilities } from '@libp2p/interface'
2+
import { type MultiaddrConnection, type SecuredConnection, type PeerId, CodeError, type PrivateKey, serviceCapabilities, isPeerId } from '@libp2p/interface'
33
import { peerIdFromKeys } from '@libp2p/peer-id'
44
import { decode } from 'it-length-prefixed'
55
import { lpStream, type LengthPrefixedStream } from 'it-length-prefixed-stream'
@@ -72,7 +72,11 @@ export class Noise implements INoiseConnection {
7272
* @param connection - streaming iterable duplex that will be encrypted
7373
* @param remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer.
7474
*/
75-
public async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localPeer: PeerId, connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>> {
75+
public async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>>
76+
public async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localPeer: PeerId, connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>>
77+
public async secureOutbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (...args: any[]): Promise<SecuredConnection<Stream, NoiseExtensions>> {
78+
const { localPeer, connection, remotePeer } = this.parseArgs<Stream>(args)
79+
7680
const wrappedConnection = lpStream(
7781
connection,
7882
{
@@ -113,7 +117,11 @@ export class Noise implements INoiseConnection {
113117
* @param connection - streaming iterable duplex that will be encrypted.
114118
* @param remotePeer - optional PeerId of the initiating peer, if known. This may only exist during transport upgrades.
115119
*/
116-
public async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localPeer: PeerId, connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>> {
120+
public async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>>
121+
public async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (localPeer: PeerId, connection: Stream, remotePeer?: PeerId): Promise<SecuredConnection<Stream, NoiseExtensions>>
122+
public async secureInbound <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (...args: any[]): Promise<SecuredConnection<Stream, NoiseExtensions>> {
123+
const { localPeer, connection, remotePeer } = this.parseArgs<Stream>(args)
124+
117125
const wrappedConnection = lpStream(
118126
connection,
119127
{
@@ -226,4 +234,30 @@ export class Noise implements INoiseConnection {
226234

227235
return user
228236
}
237+
238+
/**
239+
* Detect call signature in `libp2p@1.x.x` or `libp2p@2.x.x` style.
240+
*
241+
* TODO: remove this after `libp2p@2.x.x` is released and only support the
242+
* newer style
243+
*/
244+
private parseArgs <Stream extends Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>> = MultiaddrConnection> (args: any[]): { localPeer: PeerId, connection: Stream, remotePeer?: PeerId } {
245+
// if the first argument is a peer id, we're using the libp2p@1.x.x style
246+
if (isPeerId(args[0])) {
247+
return {
248+
localPeer: args[0],
249+
connection: args[1],
250+
remotePeer: args[2]
251+
}
252+
} else {
253+
// handle upcoming changes in libp2p@2.x.x where the first argument is the
254+
// connection and the second is optionally the remote peer
255+
// @see https://github.com/libp2p/js-libp2p/pull/2304
256+
return {
257+
localPeer: this.components.peerId,
258+
connection: args[0],
259+
remotePeer: args[1]
260+
}
261+
}
262+
}
229263
}

‎test/compliance.spec.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import tests from '@libp2p/interface-compliance-tests/connection-encryption'
22
import { defaultLogger } from '@libp2p/logger'
3+
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
34
import { Noise } from '../src/noise.js'
5+
import type { PeerId } from '@libp2p/interface'
46

57
describe('spec compliance tests', function () {
68
tests({
7-
async setup () {
8-
return new Noise({ logger: defaultLogger() })
9+
async setup (opts: { peerId?: PeerId }) {
10+
return new Noise({
11+
peerId: opts?.peerId ?? await createEd25519PeerId(),
12+
logger: defaultLogger()
13+
})
914
},
1015
async teardown () {}
1116
})

‎test/index.spec.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { defaultLogger } from '@libp2p/logger'
2+
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
23
import { expect } from 'aegir/chai'
34
import { lpStream } from 'it-length-prefixed-stream'
45
import { duplexPair } from 'it-pair/duplex'
@@ -18,8 +19,11 @@ function createCounterSpy (): ReturnType<typeof sinon.spy> {
1819
}
1920

2021
describe('Index', () => {
21-
it('should expose class with tag and required functions', () => {
22-
const noiseInstance = noise()({ logger: defaultLogger() })
22+
it('should expose class with tag and required functions', async () => {
23+
const noiseInstance = noise()({
24+
peerId: await createEd25519PeerId(),
25+
logger: defaultLogger()
26+
})
2327
expect(noiseInstance.protocol).to.equal('/noise')
2428
expect(typeof (noiseInstance.secureInbound)).to.equal('function')
2529
expect(typeof (noiseInstance.secureOutbound)).to.equal('function')
@@ -35,8 +39,15 @@ describe('Index', () => {
3539
return counter
3640
}
3741
}
38-
const noiseInit = new Noise({ logger: defaultLogger(), metrics: metrics as any as Metrics })
39-
const noiseResp = new Noise({ logger: defaultLogger() })
42+
const noiseInit = new Noise({
43+
peerId: await createEd25519PeerId(),
44+
logger: defaultLogger(),
45+
metrics: metrics as any as Metrics
46+
})
47+
const noiseResp = new Noise({
48+
peerId: await createEd25519PeerId(),
49+
logger: defaultLogger()
50+
})
4051

4152
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
4253
const [outbound, inbound] = await Promise.all([

‎test/noise.spec.ts

+40-10
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,14 @@ describe('Noise', () => {
2828

2929
it('should communicate through encrypted streams without noise pipes', async () => {
3030
try {
31-
const noiseInit = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined, extensions: undefined })
32-
const noiseResp = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined, extensions: undefined })
31+
const noiseInit = new Noise({
32+
peerId: localPeer,
33+
logger: defaultLogger()
34+
}, { staticNoiseKey: undefined, extensions: undefined })
35+
const noiseResp = new Noise({
36+
peerId: remotePeer,
37+
logger: defaultLogger()
38+
}, { staticNoiseKey: undefined, extensions: undefined })
3339

3440
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
3541
const [outbound, inbound] = await Promise.all([
@@ -51,8 +57,14 @@ describe('Noise', () => {
5157
it('should test large payloads', async function () {
5258
this.timeout(10000)
5359
try {
54-
const noiseInit = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined })
55-
const noiseResp = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined })
60+
const noiseInit = new Noise({
61+
peerId: localPeer,
62+
logger: defaultLogger()
63+
}, { staticNoiseKey: undefined })
64+
const noiseResp = new Noise({
65+
peerId: remotePeer,
66+
logger: defaultLogger()
67+
}, { staticNoiseKey: undefined })
5668

5769
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
5870
const [outbound, inbound] = await Promise.all([
@@ -76,9 +88,15 @@ describe('Noise', () => {
7688
it('should working without remote peer provided in incoming connection', async () => {
7789
try {
7890
const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair()
79-
const noiseInit = new Noise({ logger: defaultLogger() }, { staticNoiseKey: staticKeysInitiator.privateKey })
91+
const noiseInit = new Noise({
92+
peerId: localPeer,
93+
logger: defaultLogger()
94+
}, { staticNoiseKey: staticKeysInitiator.privateKey })
8095
const staticKeysResponder = pureJsCrypto.generateX25519KeyPair()
81-
const noiseResp = new Noise({ logger: defaultLogger() }, { staticNoiseKey: staticKeysResponder.privateKey })
96+
const noiseResp = new Noise({
97+
peerId: remotePeer,
98+
logger: defaultLogger()
99+
}, { staticNoiseKey: staticKeysResponder.privateKey })
82100

83101
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
84102
const [outbound, inbound] = await Promise.all([
@@ -109,10 +127,16 @@ describe('Noise', () => {
109127
try {
110128
const certhashInit = Buffer.from('certhash data from init')
111129
const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair()
112-
const noiseInit = new Noise({ logger: defaultLogger() }, { staticNoiseKey: staticKeysInitiator.privateKey, extensions: { webtransportCerthashes: [certhashInit] } })
130+
const noiseInit = new Noise({
131+
peerId: localPeer,
132+
logger: defaultLogger()
133+
}, { staticNoiseKey: staticKeysInitiator.privateKey, extensions: { webtransportCerthashes: [certhashInit] } })
113134
const staticKeysResponder = pureJsCrypto.generateX25519KeyPair()
114135
const certhashResp = Buffer.from('certhash data from respon')
115-
const noiseResp = new Noise({ logger: defaultLogger() }, { staticNoiseKey: staticKeysResponder.privateKey, extensions: { webtransportCerthashes: [certhashResp] } })
136+
const noiseResp = new Noise({
137+
peerId: remotePeer,
138+
logger: defaultLogger()
139+
}, { staticNoiseKey: staticKeysResponder.privateKey, extensions: { webtransportCerthashes: [certhashResp] } })
116140

117141
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
118142
const [outbound, inbound] = await Promise.all([
@@ -130,8 +154,14 @@ describe('Noise', () => {
130154

131155
it('should accept a prologue', async () => {
132156
try {
133-
const noiseInit = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') })
134-
const noiseResp = new Noise({ logger: defaultLogger() }, { staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') })
157+
const noiseInit = new Noise({
158+
peerId: localPeer,
159+
logger: defaultLogger()
160+
}, { staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') })
161+
const noiseResp = new Noise({
162+
peerId: remotePeer,
163+
logger: defaultLogger()
164+
}, { staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') })
135165

136166
const [inboundConnection, outboundConnection] = duplexPair<Uint8Array | Uint8ArrayList>()
137167
const [outbound, inbound] = await Promise.all([

0 commit comments

Comments
 (0)
Please sign in to comment.