From a3226cdd672a25a967571ada53be7d811c932d61 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Tue, 13 Aug 2024 16:03:20 +0100 Subject: [PATCH] fix!: remove private key field from peer id The only time you'll ever see a private key on a peer id is for the id of the currently running node. At runtime a service can obtain the unmarhsalled private key by adding a `privateKey: PrivateKey` field to it's components map so there's no need to have the field on every `PeerId`. BREAKING CHANGE: the `.privateKey` field of the `PeerId` interface has been removed --- interop/package.json | 2 +- .../package.json | 1 + .../src/index.ts | 30 +- .../src/pb/proto.proto | 2 +- .../src/pb/proto.ts | 4 +- .../test/compliance.spec.ts | 4 +- .../test/index.spec.ts | 36 +- .../connection-encrypter-tls/src/index.ts | 4 +- .../src/pb/index.proto | 2 +- .../connection-encrypter-tls/src/pb/index.ts | 4 +- packages/connection-encrypter-tls/src/tls.ts | 8 +- .../connection-encrypter-tls/src/utils.ts | 43 +-- .../test/compliance.spec.ts | 4 +- .../test/index.spec.ts | 34 +- packages/crypto/src/keys/ed25519-class.ts | 2 + packages/crypto/src/keys/index.ts | 24 +- packages/crypto/src/keys/rsa-class.ts | 2 + packages/crypto/src/keys/secp256k1-class.ts | 2 + packages/crypto/test/keys/ed25519.spec.ts | 28 +- packages/crypto/test/keys/rsa.spec.ts | 7 +- packages/crypto/test/keys/secp256k1.spec.ts | 5 +- packages/integration-tests/package.json | 6 +- .../integration-tests/test/bootstrap.spec.ts | 4 +- packages/integration-tests/test/dht.node.ts | 40 +- packages/integration-tests/test/interop.ts | 10 +- packages/integration-tests/test/mdns.node.ts | 27 +- .../interface-compliance-tests/package.json | 5 +- .../src/connection-encryption/index.ts | 22 +- .../src/mocks/connection-manager.ts | 4 +- .../interface-compliance-tests/src/peers.ts | 25 -- .../src/pubsub/index.ts | 3 +- packages/interface/src/index.ts | 5 +- packages/interface/src/keys/index.ts | 18 +- packages/interface/src/peer-id/index.ts | 54 ++- packages/interface/src/record/index.ts | 4 +- packages/kad-dht/src/index.ts | 3 +- packages/kad-dht/test/kad-dht.spec.ts | 13 +- packages/kad-dht/test/libp2p-routing.spec.ts | 11 +- packages/kad-dht/test/routing-table.spec.ts | 4 +- packages/kad-dht/test/utils/create-peer-id.ts | 21 +- .../kad-dht/test/utils/sort-closest-peers.ts | 4 +- packages/kad-dht/test/utils/test-dht.ts | 10 +- packages/keychain/package.json | 3 - packages/keychain/src/index.ts | 89 ++--- packages/keychain/src/keychain.ts | 355 +++++------------- packages/keychain/src/util.ts | 16 - packages/keychain/test/keychain.spec.ts | 304 ++++----------- packages/keychain/test/peerid.spec.ts | 76 ---- packages/libp2p/src/config.ts | 9 +- packages/libp2p/src/index.ts | 50 ++- packages/libp2p/src/libp2p.ts | 28 +- .../libp2p/test/addresses/addresses.node.ts | 44 ++- .../test/connection-manager/direct.node.ts | 60 +-- .../test/connection-manager/direct.spec.ts | 15 +- .../test/connection-manager/index.node.ts | 42 +-- .../test/connection-manager/index.spec.ts | 30 +- .../test/connection-manager/resolver.spec.ts | 16 +- .../libp2p/test/connection/compliance.spec.ts | 3 +- .../test/core/consume-peer-record.spec.ts | 11 +- packages/libp2p/test/core/encryption.spec.ts | 9 - packages/libp2p/test/core/listening.node.ts | 16 +- packages/libp2p/test/core/status.node.ts | 7 +- .../libp2p/test/fixtures/creators/peer.ts | 11 +- .../libp2p/test/fixtures/get-component.ts | 3 + .../peer-discovery/peer-discovery.spec.ts | 9 +- .../libp2p/test/registrar/protocols.spec.ts | 6 +- .../test/transports/transport-manager.spec.ts | 10 +- .../libp2p/test/upgrading/upgrader.spec.ts | 41 +- packages/peer-id-factory/package.json | 6 +- packages/peer-id-factory/src/index.ts | 25 +- packages/peer-id-factory/test/index.spec.ts | 55 +-- packages/peer-id/src/index.ts | 11 +- packages/peer-record/README.md | 8 +- packages/peer-record/src/envelope/index.ts | 40 +- packages/peer-record/src/index.ts | 10 +- packages/peer-record/test/envelope.spec.ts | 20 +- packages/peer-record/test/peer-record.spec.ts | 18 +- packages/peer-store/package.json | 3 +- packages/peer-store/src/index.ts | 8 +- packages/peer-store/test/index.spec.ts | 19 +- packages/pnet/package.json | 2 +- packages/protocol-identify/package.json | 3 +- .../protocol-identify/src/identify-push.ts | 2 +- packages/protocol-identify/src/identify.ts | 5 +- packages/protocol-identify/src/index.ts | 3 +- packages/protocol-identify/src/utils.ts | 8 +- .../protocol-identify/test/fixtures/index.ts | 3 +- packages/protocol-identify/test/index.spec.ts | 21 +- packages/protocol-identify/test/push.spec.ts | 9 +- packages/pubsub-floodsub/package.json | 1 + .../pubsub-floodsub/test/floodsub.spec.ts | 9 +- packages/pubsub/package.json | 2 +- packages/pubsub/src/index.ts | 9 +- packages/pubsub/src/sign.ts | 18 +- packages/pubsub/test/emit-self.spec.ts | 11 +- packages/pubsub/test/instance.spec.ts | 7 +- packages/pubsub/test/lifecycle.spec.ts | 17 +- packages/pubsub/test/message.spec.ts | 8 +- packages/pubsub/test/pubsub.spec.ts | 54 ++- packages/pubsub/test/sign.spec.ts | 42 +-- packages/pubsub/test/topic-validators.spec.ts | 8 +- packages/pubsub/test/utils/index.ts | 7 - .../transport-circuit-relay-v2/package.json | 1 + .../src/server/index.ts | 7 +- .../test/hop.spec.ts | 11 +- 105 files changed, 846 insertions(+), 1449 deletions(-) delete mode 100644 packages/interface-compliance-tests/src/peers.ts delete mode 100644 packages/keychain/src/util.ts delete mode 100644 packages/keychain/test/peerid.spec.ts create mode 100644 packages/libp2p/test/fixtures/get-component.ts diff --git a/interop/package.json b/interop/package.json index 70ac6a3f10..299ba4742a 100644 --- a/interop/package.json +++ b/interop/package.json @@ -21,7 +21,7 @@ "@chainsafe/libp2p-noise": "^15.0.0", "@chainsafe/libp2p-yamux": "^6.0.2", "@libp2p/circuit-relay-v2": "^1.0.24", - "@libp2p/interface": "^1.4.0", + "@libp2p/interface": "^1.7.0", "@libp2p/identify": "^2.0.2", "@libp2p/mplex": "^10.0.24", "@libp2p/ping": "^1.0.19", diff --git a/packages/connection-encrypter-plaintext/package.json b/packages/connection-encrypter-plaintext/package.json index ad61e9fb18..3f8d5a7734 100644 --- a/packages/connection-encrypter-plaintext/package.json +++ b/packages/connection-encrypter-plaintext/package.json @@ -61,6 +61,7 @@ "uint8arrays": "^5.1.0" }, "devDependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface-compliance-tests": "^5.4.12", "@libp2p/logger": "^4.0.20", "@libp2p/peer-id-factory": "^4.2.4", diff --git a/packages/connection-encrypter-plaintext/src/index.ts b/packages/connection-encrypter-plaintext/src/index.ts index 30bf267386..57ae3b279f 100644 --- a/packages/connection-encrypter-plaintext/src/index.ts +++ b/packages/connection-encrypter-plaintext/src/index.ts @@ -24,14 +24,14 @@ import { UnexpectedPeerError, InvalidCryptoExchangeError, serviceCapabilities } import { peerIdFromBytes, peerIdFromKeys } from '@libp2p/peer-id' import { pbStream } from 'it-protobuf-stream' import { Exchange, KeyType } from './pb/proto.js' -import type { ComponentLogger, Logger, MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId } from '@libp2p/interface' +import type { ComponentLogger, Logger, MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId, PrivateKey } from '@libp2p/interface' import type { Duplex } from 'it-stream-types' import type { Uint8ArrayList } from 'uint8arraylist' const PROTOCOL = '/plaintext/2.0.0' export interface PlaintextComponents { - peerId: PeerId + privateKey: PrivateKey logger: ComponentLogger } @@ -45,12 +45,12 @@ export interface PlaintextInit { class Plaintext implements ConnectionEncrypter { public protocol: string = PROTOCOL - private readonly peerId: PeerId + private readonly privateKey: PrivateKey private readonly log: Logger private readonly timeout: number constructor (components: PlaintextComponents, init: PlaintextInit = {}) { - this.peerId = components.peerId + this.privateKey = components.privateKey this.log = components.logger.forComponent('libp2p:plaintext') this.timeout = init.timeout ?? 1000 } @@ -62,28 +62,20 @@ class Plaintext implements ConnectionEncrypter { ] async secureInbound > = MultiaddrConnection> (conn: Stream, remoteId?: PeerId): Promise> { - return this._encrypt(this.peerId, conn, remoteId) + return this._encrypt(this.privateKey, conn, remoteId) } async secureOutbound > = MultiaddrConnection> (conn: Stream, remoteId?: PeerId): Promise> { - return this._encrypt(this.peerId, conn, remoteId) + return this._encrypt(this.privateKey, conn, remoteId) } /** * Encrypt connection */ - async _encrypt > = MultiaddrConnection> (localId: PeerId, conn: Stream, remoteId?: PeerId): Promise> { + async _encrypt > = MultiaddrConnection> (privateKey: PrivateKey, conn: Stream, remoteId?: PeerId): Promise> { const signal = AbortSignal.timeout(this.timeout) const pb = pbStream(conn).pb(Exchange) - let type = KeyType.RSA - - if (localId.type === 'Ed25519') { - type = KeyType.Ed25519 - } else if (localId.type === 'secp256k1') { - type = KeyType.Secp256k1 - } - this.log('write pubkey exchange to peer %p', remoteId) const [ @@ -91,10 +83,10 @@ class Plaintext implements ConnectionEncrypter { ] = await Promise.all([ // Encode the public key and write it to the remote peer pb.write({ - id: localId.toBytes(), + id: await privateKey.public.hash(), pubkey: { - Type: type, - Data: localId.publicKey ?? new Uint8Array(0) + Type: KeyType[privateKey.type], + Data: privateKey.public.marshal() } }, { signal @@ -126,7 +118,7 @@ class Plaintext implements ConnectionEncrypter { } } catch (err: any) { this.log.error(err) - throw new InvalidCryptoExchangeError('Remote did not provide its public key') + throw new InvalidCryptoExchangeError('Invalid public key - ' + err.message) } if (remoteId != null && !peerId.equals(remoteId)) { diff --git a/packages/connection-encrypter-plaintext/src/pb/proto.proto b/packages/connection-encrypter-plaintext/src/pb/proto.proto index 9d174a898c..7cbe1b2925 100644 --- a/packages/connection-encrypter-plaintext/src/pb/proto.proto +++ b/packages/connection-encrypter-plaintext/src/pb/proto.proto @@ -8,7 +8,7 @@ message Exchange { enum KeyType { RSA = 0; Ed25519 = 1; - Secp256k1 = 2; + secp256k1 = 2; ECDSA = 3; } diff --git a/packages/connection-encrypter-plaintext/src/pb/proto.ts b/packages/connection-encrypter-plaintext/src/pb/proto.ts index 3a85c10b42..5f53d2cf19 100644 --- a/packages/connection-encrypter-plaintext/src/pb/proto.ts +++ b/packages/connection-encrypter-plaintext/src/pb/proto.ts @@ -81,14 +81,14 @@ export namespace Exchange { export enum KeyType { RSA = 'RSA', Ed25519 = 'Ed25519', - Secp256k1 = 'Secp256k1', + secp256k1 = 'secp256k1', ECDSA = 'ECDSA' } enum __KeyTypeValues { RSA = 0, Ed25519 = 1, - Secp256k1 = 2, + secp256k1 = 2, ECDSA = 3 } diff --git a/packages/connection-encrypter-plaintext/test/compliance.spec.ts b/packages/connection-encrypter-plaintext/test/compliance.spec.ts index c1024441fe..30570115a3 100644 --- a/packages/connection-encrypter-plaintext/test/compliance.spec.ts +++ b/packages/connection-encrypter-plaintext/test/compliance.spec.ts @@ -1,15 +1,15 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/keys' import suite from '@libp2p/interface-compliance-tests/connection-encryption' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '../src/index.js' describe('plaintext compliance', () => { suite({ async setup (opts) { return plaintext()({ - peerId: opts?.peerId ?? await createEd25519PeerId(), + privateKey: opts?.privateKey ?? await generateKeyPair('Ed25519'), logger: defaultLogger() }) }, diff --git a/packages/connection-encrypter-plaintext/test/index.spec.ts b/packages/connection-encrypter-plaintext/test/index.spec.ts index c2a72f2dbb..f079b5e1ed 100644 --- a/packages/connection-encrypter-plaintext/test/index.spec.ts +++ b/packages/connection-encrypter-plaintext/test/index.spec.ts @@ -1,9 +1,9 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/keys' import { mockMultiaddrConnPair } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' -import { peerIdFromBytes } from '@libp2p/peer-id' -import { createEd25519PeerId, createRSAPeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import sinon from 'sinon' @@ -11,25 +11,23 @@ import { plaintext } from '../src/index.js' import type { ConnectionEncrypter, PeerId } from '@libp2p/interface' describe('plaintext', () => { - let localPeer: PeerId let remotePeer: PeerId let wrongPeer: PeerId let encrypter: ConnectionEncrypter let encrypterRemote: ConnectionEncrypter beforeEach(async () => { - [localPeer, remotePeer, wrongPeer] = await Promise.all([ - createEd25519PeerId(), + [remotePeer, wrongPeer] = await Promise.all([ createEd25519PeerId(), createEd25519PeerId() ]) encrypter = plaintext()({ - peerId: localPeer, + privateKey: await generateKeyPair('Ed25519'), logger: defaultLogger() }) encrypterRemote = plaintext()({ - peerId: remotePeer, + privateKey: await generateKeyPair('Ed25519'), logger: defaultLogger() }) }) @@ -55,28 +53,4 @@ describe('plaintext', () => { expect(err).to.have.property('name', 'UnexpectedPeerError') }) }) - - it('should fail if the peer does not provide its public key', async () => { - const peer = await createRSAPeerId() - remotePeer = peerIdFromBytes(peer.toBytes()) - - encrypter = plaintext()({ - peerId: remotePeer, - logger: defaultLogger() - }) - - const { inbound, outbound } = mockMultiaddrConnPair({ - remotePeer, - addrs: [ - multiaddr('/ip4/127.0.0.1/tcp/1234'), - multiaddr('/ip4/127.0.0.1/tcp/1235') - ] - }) - - await expect(Promise.all([ - encrypter.secureInbound(inbound), - encrypterRemote.secureOutbound(outbound, localPeer) - ])) - .to.eventually.be.rejected.with.property('name', 'InvalidCryptoExchangeError') - }) }) diff --git a/packages/connection-encrypter-tls/src/index.ts b/packages/connection-encrypter-tls/src/index.ts index 36d843d8c0..1463a89741 100644 --- a/packages/connection-encrypter-tls/src/index.ts +++ b/packages/connection-encrypter-tls/src/index.ts @@ -19,12 +19,12 @@ */ import { TLS } from './tls.js' -import type { ComponentLogger, ConnectionEncrypter, PeerId } from '@libp2p/interface' +import type { ComponentLogger, ConnectionEncrypter, PrivateKey } from '@libp2p/interface' export const PROTOCOL = '/tls/1.0.0' export interface TLSComponents { - peerId: PeerId + privateKey: PrivateKey logger: ComponentLogger } diff --git a/packages/connection-encrypter-tls/src/pb/index.proto b/packages/connection-encrypter-tls/src/pb/index.proto index 87b56ba8de..0068549c3c 100644 --- a/packages/connection-encrypter-tls/src/pb/index.proto +++ b/packages/connection-encrypter-tls/src/pb/index.proto @@ -3,7 +3,7 @@ syntax = "proto3"; enum KeyType { RSA = 0; Ed25519 = 1; - Secp256k1 = 2; + secp256k1 = 2; ECDSA = 3; } diff --git a/packages/connection-encrypter-tls/src/pb/index.ts b/packages/connection-encrypter-tls/src/pb/index.ts index f9da51abfb..a00050275e 100644 --- a/packages/connection-encrypter-tls/src/pb/index.ts +++ b/packages/connection-encrypter-tls/src/pb/index.ts @@ -10,14 +10,14 @@ import type { Uint8ArrayList } from 'uint8arraylist' export enum KeyType { RSA = 'RSA', Ed25519 = 'Ed25519', - Secp256k1 = 'Secp256k1', + secp256k1 = 'secp256k1', ECDSA = 'ECDSA' } enum __KeyTypeValues { RSA = 0, Ed25519 = 1, - Secp256k1 = 2, + secp256k1 = 2, ECDSA = 3 } diff --git a/packages/connection-encrypter-tls/src/tls.ts b/packages/connection-encrypter-tls/src/tls.ts index d64b19033f..e41b611326 100644 --- a/packages/connection-encrypter-tls/src/tls.ts +++ b/packages/connection-encrypter-tls/src/tls.ts @@ -24,19 +24,19 @@ import { HandshakeTimeoutError } from './errors.js' import { generateCertificate, verifyPeerCertificate, itToStream, streamToIt } from './utils.js' import { PROTOCOL } from './index.js' import type { TLSComponents, TLSInit } from './index.js' -import type { MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId, Logger } from '@libp2p/interface' +import type { MultiaddrConnection, ConnectionEncrypter, SecuredConnection, PeerId, Logger, PrivateKey } from '@libp2p/interface' import type { Duplex } from 'it-stream-types' import type { Uint8ArrayList } from 'uint8arraylist' export class TLS implements ConnectionEncrypter { public protocol: string = PROTOCOL private readonly log: Logger - private readonly peerId: PeerId + private readonly privateKey: PrivateKey private readonly timeout: number constructor (components: TLSComponents, init: TLSInit = {}) { this.log = components.logger.forComponent('libp2p:tls') - this.peerId = components.peerId + this.privateKey = components.privateKey this.timeout = init.timeout ?? 1000 } @@ -59,7 +59,7 @@ export class TLS implements ConnectionEncrypter { */ async _encrypt > = MultiaddrConnection> (conn: Stream, isServer: boolean, remoteId?: PeerId): Promise> { const opts: TLSSocketOptions = { - ...await generateCertificate(this.peerId), + ...await generateCertificate(this.privateKey), isServer, // require TLS 1.3 or later minVersion: 'TLSv1.3', diff --git a/packages/connection-encrypter-tls/src/utils.ts b/packages/connection-encrypter-tls/src/utils.ts index ffeb058a40..9d10ece471 100644 --- a/packages/connection-encrypter-tls/src/utils.ts +++ b/packages/connection-encrypter-tls/src/utils.ts @@ -1,6 +1,6 @@ import { Duplex as DuplexStream } from 'node:stream' -import { Ed25519PublicKey, Secp256k1PublicKey, marshalPublicKey, supportedKeys, unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys' -import { InvalidCryptoExchangeError, InvalidParametersError, UnexpectedPeerError } from '@libp2p/interface' +import { Ed25519PublicKey, Secp256k1PublicKey, marshalPublicKey, supportedKeys } from '@libp2p/crypto/keys' +import { InvalidCryptoExchangeError, UnexpectedPeerError } from '@libp2p/interface' import { peerIdFromKeys } from '@libp2p/peer-id' import { AsnConvert } from '@peculiar/asn1-schema' import * as asn1X509 from '@peculiar/asn1-x509' @@ -13,7 +13,7 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { InvalidCertificateError } from './errors.js' import { KeyType, PublicKey } from './pb/index.js' -import type { PeerId, PublicKey as Libp2pPublicKey, Logger } from '@libp2p/interface' +import type { PeerId, PublicKey as Libp2pPublicKey, Logger, PrivateKey } from '@libp2p/interface' import type { Duplex } from 'it-stream-types' import type { Uint8ArrayList } from 'uint8arraylist' @@ -74,7 +74,7 @@ export async function verifyPeerCertificate (rawCertificate: Uint8Array, expecte if (remotePublicKey.type === KeyType.Ed25519) { remoteLibp2pPublicKey = new Ed25519PublicKey(remotePublicKeyData) - } else if (remotePublicKey.type === KeyType.Secp256k1) { + } else if (remotePublicKey.type === KeyType.secp256k1) { remoteLibp2pPublicKey = new Secp256k1PublicKey(remotePublicKeyData) } else if (remotePublicKey.type === KeyType.RSA) { remoteLibp2pPublicKey = supportedKeys.rsa.unmarshalRsaPublicKey(remotePublicKeyData) @@ -104,35 +104,7 @@ export async function verifyPeerCertificate (rawCertificate: Uint8Array, expecte return remotePeerId } -export async function generateCertificate (peerId: PeerId): Promise<{ cert: string, key: string }> { - if (peerId.privateKey == null) { - throw new InvalidParametersError('Private key was missing from PeerId') - } - - if (peerId.publicKey == null) { - throw new InvalidParametersError('Public key missing from PeerId') - } - - const publicKey = unmarshalPublicKey(peerId.publicKey) - let keyType: KeyType - let keyData: Uint8Array - - if (peerId.type === 'Ed25519') { - // Ed25519: Only the 32 bytes of the public key - keyType = KeyType.Ed25519 - keyData = publicKey.marshal() - } else if (peerId.type === 'secp256k1') { - // Secp256k1: Only the compressed form of the public key. 33 bytes. - keyType = KeyType.Secp256k1 - keyData = publicKey.marshal() - } else if (peerId.type === 'RSA') { - // The rest of the keys are encoded as a SubjectPublicKeyInfo structure in PKIX, ASN.1 DER form. - keyType = KeyType.RSA - keyData = publicKey.marshal() - } else { - throw new InvalidParametersError('PeerId had unknown or unsupported type') - } - +export async function generateCertificate (privateKey: PrivateKey): Promise<{ cert: string, key: string }> { const now = Date.now() const alg = { @@ -144,7 +116,6 @@ export async function generateCertificate (peerId: PeerId): Promise<{ cert: stri const keys = await crypto.subtle.generateKey(alg, true, ['sign']) const certPublicKeySpki = await crypto.subtle.exportKey('spki', keys.publicKey) const dataToSign = encodeSignatureData(certPublicKeySpki) - const privateKey = await unmarshalPrivateKey(peerId.privateKey) const sig = await privateKey.sign(dataToSign) const notAfter = new Date(now + CERT_VALIDITY_PERIOD_TO) // workaround for https://github.com/PeculiarVentures/x509/issues/73 @@ -163,8 +134,8 @@ export async function generateCertificate (peerId: PeerId): Promise<{ cert: stri // publicKey new asn1js.OctetString({ valueHex: PublicKey.encode({ - type: keyType, - data: keyData + type: KeyType[privateKey.type], + data: privateKey.public.marshal() }) }), // signature diff --git a/packages/connection-encrypter-tls/test/compliance.spec.ts b/packages/connection-encrypter-tls/test/compliance.spec.ts index d926cda042..ed31f94411 100644 --- a/packages/connection-encrypter-tls/test/compliance.spec.ts +++ b/packages/connection-encrypter-tls/test/compliance.spec.ts @@ -1,15 +1,15 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/keys' import suite from '@libp2p/interface-compliance-tests/connection-encryption' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { tls } from '../src/index.js' describe('tls compliance', () => { suite({ async setup (opts) { return tls()({ - peerId: opts?.peerId ?? await createEd25519PeerId(), + privateKey: opts?.privateKey ?? await generateKeyPair('Ed25519'), logger: defaultLogger() }) }, diff --git a/packages/connection-encrypter-tls/test/index.spec.ts b/packages/connection-encrypter-tls/test/index.spec.ts index 135d3a3f03..9d5483d500 100644 --- a/packages/connection-encrypter-tls/test/index.spec.ts +++ b/packages/connection-encrypter-tls/test/index.spec.ts @@ -1,9 +1,9 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/keys' import { mockMultiaddrConnPair } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' -import { peerIdFromBytes } from '@libp2p/peer-id' -import { createEd25519PeerId, createRSAPeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import sinon from 'sinon' @@ -11,20 +11,18 @@ import { tls } from '../src/index.js' import type { ConnectionEncrypter, PeerId } from '@libp2p/interface' describe('tls', () => { - let localPeer: PeerId let remotePeer: PeerId let wrongPeer: PeerId let encrypter: ConnectionEncrypter beforeEach(async () => { - [localPeer, remotePeer, wrongPeer] = await Promise.all([ - createEd25519PeerId(), + [remotePeer, wrongPeer] = await Promise.all([ createEd25519PeerId(), createEd25519PeerId() ]) encrypter = tls()({ - peerId: await createEd25519PeerId(), + privateKey: await generateKeyPair('Ed25519'), logger: defaultLogger() }) }) @@ -50,28 +48,4 @@ describe('tls', () => { expect(err).to.have.property('name', 'UnexpectedPeerError') }) }) - - it('should fail if the peer does not provide its public key', async () => { - const peer = await createRSAPeerId() - remotePeer = peerIdFromBytes(peer.toBytes()) - - encrypter = tls()({ - peerId: remotePeer, - logger: defaultLogger() - }) - - const { inbound, outbound } = mockMultiaddrConnPair({ - remotePeer, - addrs: [ - multiaddr('/ip4/127.0.0.1/tcp/1234'), - multiaddr('/ip4/127.0.0.1/tcp/1235') - ] - }) - - await expect(Promise.all([ - encrypter.secureInbound(inbound), - encrypter.secureOutbound(outbound, localPeer) - ])) - .to.eventually.be.rejected.with.property('name', 'InvalidParametersError') - }) }) diff --git a/packages/crypto/src/keys/ed25519-class.ts b/packages/crypto/src/keys/ed25519-class.ts index 9f12dfe5d9..aad99aaddb 100644 --- a/packages/crypto/src/keys/ed25519-class.ts +++ b/packages/crypto/src/keys/ed25519-class.ts @@ -12,6 +12,7 @@ import type { Multibase } from 'multiformats' import type { Uint8ArrayList } from 'uint8arraylist' export class Ed25519PublicKey implements PublicKey<'Ed25519'> { + public readonly type = 'Ed25519' private readonly _key: Uint8Array constructor (key: Uint8Array) { @@ -49,6 +50,7 @@ export class Ed25519PublicKey implements PublicKey<'Ed25519'> { } export class Ed25519PrivateKey implements PrivateKey<'Ed25519'> { + public readonly type = 'Ed25519' private readonly _key: Uint8Array private readonly _publicKey: Uint8Array diff --git a/packages/crypto/src/keys/index.ts b/packages/crypto/src/keys/index.ts index 7464127cd0..3aeab5506c 100644 --- a/packages/crypto/src/keys/index.ts +++ b/packages/crypto/src/keys/index.ts @@ -19,13 +19,13 @@ import * as keysPBM from './keys.js' import * as RSA from './rsa-class.js' import { importFromPem } from './rsa-utils.js' import * as Secp256k1 from './secp256k1-class.js' -import type { PrivateKey, PublicKey, KeyType as KeyTypes } from '@libp2p/interface' +import type { PrivateKey, PublicKey, KeyType } from '@libp2p/interface' export { keyStretcher } export { generateEphemeralKeyPair } export { keysPBM } -export type { KeyTypes } +export type { KeyType } export { RsaPrivateKey, RsaPublicKey, MAX_RSA_KEY_SIZE } from './rsa-class.js' export { Ed25519PrivateKey, Ed25519PublicKey } from './ed25519-class.js' @@ -56,17 +56,23 @@ function typeToKey (type: string): typeof RSA | typeof Ed25519 | typeof Secp256k /** * Generates a keypair of the given type and bitsize */ -export async function generateKeyPair (type: T, bits?: number): Promise> { +export async function generateKeyPair (type: 'Ed25519'): Promise> +export async function generateKeyPair (type: 'secp256k1'): Promise> +export async function generateKeyPair (type: 'RSA', bits?: number): Promise> +export async function generateKeyPair (type: KeyType, bits?: number): Promise> { return typeToKey(type).generateKeyPair(bits ?? 2048) } /** - * Generates a keypair of the given type and bitsize. + * Generates a keypair of the given type from the passed seed. Currently only + * supports Ed25519 keys. * * Seed is a 32 byte uint8array */ -export async function generateKeyPairFromSeed (type: T, seed: Uint8Array, bits?: number): Promise> { - if (type.toLowerCase() !== 'ed25519') { +export async function generateKeyPairFromSeed (type: 'Ed25519', seed: Uint8Array): Promise> +export async function generateKeyPairFromSeed (type: T, seed: Uint8Array, bits?: number): Promise +export async function generateKeyPairFromSeed (type: string, seed: Uint8Array): Promise> { + if (type !== 'Ed25519') { throw new InvalidParametersError('Seed key derivation is unimplemented for RSA or secp256k1') } @@ -76,7 +82,7 @@ export async function generateKeyPairFromSeed (type: T, see /** * Converts a protobuf serialized public key into its representative object */ -export function unmarshalPublicKey (buf: Uint8Array): PublicKey { +export function unmarshalPublicKey (buf: Uint8Array): PublicKey { const decoded = keysPBM.PublicKey.decode(buf) const data = decoded.Data ?? new Uint8Array() @@ -104,7 +110,7 @@ export function marshalPublicKey (key: { bytes: Uint8Array }, type?: string): Ui /** * Converts a protobuf serialized private key into its representative object */ -export async function unmarshalPrivateKey (buf: Uint8Array): Promise> { +export async function unmarshalPrivateKey (buf: Uint8Array): Promise> { const decoded = keysPBM.PrivateKey.decode(buf) const data = decoded.Data ?? new Uint8Array() @@ -134,7 +140,7 @@ export function marshalPrivateKey (key: { bytes: Uint8Array }, type?: string): U * * Supported formats are 'pem' (RSA only) and 'libp2p-key'. */ -export async function importKey (encryptedKey: string, password: string): Promise> { +export async function importKey (encryptedKey: string, password: string): Promise> { try { const key = await importer(encryptedKey, password) return await unmarshalPrivateKey(key) diff --git a/packages/crypto/src/keys/rsa-class.ts b/packages/crypto/src/keys/rsa-class.ts index 18ce91a896..4558c9780b 100644 --- a/packages/crypto/src/keys/rsa-class.ts +++ b/packages/crypto/src/keys/rsa-class.ts @@ -13,6 +13,7 @@ import type { Uint8ArrayList } from 'uint8arraylist' export const MAX_RSA_KEY_SIZE = 8192 export class RsaPublicKey implements PublicKey<'RSA'> { + public readonly type = 'RSA' private readonly _key: JsonWebKey constructor (key: JsonWebKey) { @@ -50,6 +51,7 @@ export class RsaPublicKey implements PublicKey<'RSA'> { } export class RsaPrivateKey implements PrivateKey<'RSA'> { + public readonly type = 'RSA' private readonly _key: JsonWebKey private readonly _publicKey: JsonWebKey diff --git a/packages/crypto/src/keys/secp256k1-class.ts b/packages/crypto/src/keys/secp256k1-class.ts index 2a6d8b994b..3d2b49b443 100644 --- a/packages/crypto/src/keys/secp256k1-class.ts +++ b/packages/crypto/src/keys/secp256k1-class.ts @@ -11,6 +11,7 @@ import type { Multibase } from 'multiformats' import type { Uint8ArrayList } from 'uint8arraylist' export class Secp256k1PublicKey implements PublicKey<'secp256k1'> { + public readonly type = 'secp256k1' private readonly _key: Uint8Array constructor (key: Uint8Array) { @@ -52,6 +53,7 @@ export class Secp256k1PublicKey implements PublicKey<'secp256k1'> { } export class Secp256k1PrivateKey implements PrivateKey<'secp256k1'> { + public readonly type = 'secp256k1' private readonly _key: Uint8Array private readonly _publicKey: Uint8Array diff --git a/packages/crypto/test/keys/ed25519.spec.ts b/packages/crypto/test/keys/ed25519.spec.ts index 49650c20cf..22c4768e52 100644 --- a/packages/crypto/test/keys/ed25519.spec.ts +++ b/packages/crypto/test/keys/ed25519.spec.ts @@ -6,6 +6,7 @@ import * as crypto from '../../src/index.js' import { Ed25519PrivateKey } from '../../src/keys/ed25519-class.js' import fixtures from '../fixtures/go-key-ed25519.js' import { testGarbage } from '../helpers/test-garbage-error-handling.js' +import type { PrivateKey } from '@libp2p/interface' const ed25519 = crypto.keys.supportedKeys.ed25519 @@ -13,11 +14,12 @@ const ed25519 = crypto.keys.supportedKeys.ed25519 describe('ed25519', function () { this.timeout(20 * 1000) - let key: Ed25519PrivateKey + let key: PrivateKey<'Ed25519'> + before(async () => { - const generated = await crypto.keys.generateKeyPair('Ed25519', 512) + const generated = await crypto.keys.generateKeyPair('Ed25519') - if (!(generated instanceof Ed25519PrivateKey)) { + if (generated.type !== 'Ed25519') { throw new Error('Key was incorrect type') } @@ -32,7 +34,7 @@ describe('ed25519', function () { it('generates a valid key from seed', async () => { const seed = crypto.randomBytes(32) - const seededkey = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512) + const seededkey = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed) expect(seededkey).to.be.an.instanceof(ed25519.Ed25519PrivateKey) const digest = await seededkey.hash() expect(digest).to.have.length(34) @@ -40,24 +42,24 @@ describe('ed25519', function () { it('generates the same key from the same seed', async () => { const seed = crypto.randomBytes(32) - const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512) - const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512) + const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed) + const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed) expect(seededkey1.equals(seededkey2)).to.eql(true) expect(seededkey1.public.equals(seededkey2.public)).to.eql(true) }) it('generates different keys for different seeds', async () => { const seed1 = crypto.randomBytes(32) - const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed1, 512) + const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed1) const seed2 = crypto.randomBytes(32) - const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed2, 512) + const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed2) expect(seededkey1.equals(seededkey2)).to.eql(false) expect(seededkey1.public.equals(seededkey2.public)).to.eql(false) }) it('signs', async () => { const text = crypto.randomBytes(512) - const sig = key.sign(text) + const sig = await key.sign(text) const res = key.public.verify(text, sig) expect(res).to.be.eql(true) }) @@ -67,7 +69,7 @@ describe('ed25519', function () { crypto.randomBytes(512), crypto.randomBytes(512) ) - const sig = key.sign(text) + const sig = await key.sign(text) expect(key.sign(text.subarray())) .to.deep.equal(sig, 'list did not have same signature as a single buffer') @@ -163,7 +165,7 @@ describe('ed25519', function () { }) it('not equals other key', async () => { - const key2 = await crypto.keys.generateKeyPair('Ed25519', 512) + const key2 = await crypto.keys.generateKeyPair('Ed25519') if (!(key2 instanceof Ed25519PrivateKey)) { throw new Error('Key was incorrect type') @@ -178,7 +180,7 @@ describe('ed25519', function () { it('sign and verify', async () => { const data = uint8ArrayFromString('hello world') - const sig = key.sign(data) + const sig = await key.sign(data) const valid = key.public.verify(data, sig) expect(valid).to.eql(true) }) @@ -194,7 +196,7 @@ describe('ed25519', function () { it('fails to verify for different data', async () => { const data = uint8ArrayFromString('hello world') - const sig = key.sign(data) + const sig = await key.sign(data) const valid = key.public.verify(uint8ArrayFromString('hello'), sig) expect(valid).to.be.eql(false) }) diff --git a/packages/crypto/test/keys/rsa.spec.ts b/packages/crypto/test/keys/rsa.spec.ts index 619de10287..0b8ecf1b1e 100644 --- a/packages/crypto/test/keys/rsa.spec.ts +++ b/packages/crypto/test/keys/rsa.spec.ts @@ -9,15 +9,16 @@ import { importFromPem } from '../../src/keys/rsa-utils.js' import fixtures from '../fixtures/go-key-rsa.js' import { RSA_KEY_8200_BITS } from '../fixtures/rsa.js' import { testGarbage } from '../helpers/test-garbage-error-handling.js' +import type { PrivateKey } from '@libp2p/interface' const rsa = crypto.keys.supportedKeys.rsa describe('RSA', function () { this.timeout(20 * 1000) - let key: RsaPrivateKey + let key: PrivateKey<'RSA'> before(async () => { - key = await rsa.generateKeyPair(512) + key = await crypto.keys.generateKeyPair('RSA', 512) }) it('generates a valid key', async () => { @@ -43,7 +44,7 @@ describe('RSA', function () { }) it('signs', async () => { - const text = key.genSecret() + const text = uint8ArrayFromString('hello world') const sig = await key.sign(text) const res = await key.public.verify(text, sig) expect(res).to.be.eql(true) diff --git a/packages/crypto/test/keys/secp256k1.spec.ts b/packages/crypto/test/keys/secp256k1.spec.ts index 27cac0ee54..f88d76dd63 100644 --- a/packages/crypto/test/keys/secp256k1.spec.ts +++ b/packages/crypto/test/keys/secp256k1.spec.ts @@ -7,16 +7,17 @@ import * as crypto from '../../src/index.js' import * as Secp256k1 from '../../src/keys/secp256k1-class.js' import * as secp256k1Crypto from '../../src/keys/secp256k1.js' import fixtures from '../fixtures/go-key-secp256k1.js' +import type { PrivateKey } from '@libp2p/interface' const secp256k1 = crypto.keys.supportedKeys.secp256k1 const keysPBM = crypto.keys.keysPBM const randomBytes = crypto.randomBytes describe('secp256k1 keys', () => { - let key: Secp256k1.Secp256k1PrivateKey + let key: PrivateKey<'secp256k1'> before(async () => { - key = await secp256k1.generateKeyPair() + key = await crypto.keys.generateKeyPair('secp256k1') }) it('generates a valid key', async () => { diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index bddbea2579..7cb9bf8478 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -46,7 +46,7 @@ "@libp2p/fetch": "^1.0.17", "@libp2p/floodsub": "^9.0.19", "@libp2p/identify": "^2.0.1", - "@libp2p/interface": "^1.3.1", + "@libp2p/interface": "^1.7.0", "@libp2p/interface-compliance-tests": "^5.4.4", "@libp2p/interface-internal": "^1.2.1", "@libp2p/interop": "^12.1.0", @@ -54,8 +54,8 @@ "@libp2p/logger": "^4.0.12", "@libp2p/mdns": "^10.0.23", "@libp2p/mplex": "^10.0.23", - "@libp2p/peer-id": "^4.1.1", - "@libp2p/peer-id-factory": "^4.1.1", + "@libp2p/peer-id": "^4.2.4", + "@libp2p/peer-id-factory": "^4.2.4", "@libp2p/ping": "^1.0.18", "@libp2p/plaintext": "^1.0.23", "@libp2p/tcp": "^9.0.25", diff --git a/packages/integration-tests/test/bootstrap.spec.ts b/packages/integration-tests/test/bootstrap.spec.ts index e9f80a169a..534c1d47b9 100644 --- a/packages/integration-tests/test/bootstrap.spec.ts +++ b/packages/integration-tests/test/bootstrap.spec.ts @@ -25,13 +25,12 @@ class TestPeerDiscovery extends TypedEventEmitter implement } describe('bootstrap', () => { - let peerId: PeerId let remotePeerId1: PeerId let remotePeerId2: PeerId let libp2p: Libp2p beforeEach(async () => { - [peerId, remotePeerId1, remotePeerId2] = await Promise.all([ + [remotePeerId1, remotePeerId2] = await Promise.all([ createEd25519PeerId(), createEd25519PeerId(), createEd25519PeerId() @@ -48,7 +47,6 @@ describe('bootstrap', () => { const discovery = new TestPeerDiscovery() libp2p = await createLibp2p({ - peerId, peerDiscovery: [ () => discovery ] diff --git a/packages/integration-tests/test/dht.node.ts b/packages/integration-tests/test/dht.node.ts index dc19017730..d320008396 100644 --- a/packages/integration-tests/test/dht.node.ts +++ b/packages/integration-tests/test/dht.node.ts @@ -3,7 +3,6 @@ import { yamux } from '@chainsafe/libp2p-yamux' import { kadDHT, passthroughMapper } from '@libp2p/kad-dht' import { mplex } from '@libp2p/mplex' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { multiaddr } from '@multiformats/multiaddr' @@ -38,23 +37,13 @@ async function getRemoteAddr (remotePeerId: PeerId, libp2p: Libp2p): Promise { - let peerId: PeerId - let remotePeerId: PeerId let libp2p: Libp2p<{ dht: KadDHT }> let remoteLibp2p: Libp2p<{ dht: KadDHT }> let remAddr: Multiaddr - beforeEach(async () => { - [peerId, remotePeerId] = await Promise.all([ - createEd25519PeerId(), - createEd25519PeerId() - ]) - }) - describe('dht started before connect', () => { beforeEach(async () => { libp2p = await createLibp2p({ - peerId, addresses: { listen: [listenAddr.toString()] }, @@ -78,7 +67,6 @@ describe('DHT subsystem operates correctly', () => { }) remoteLibp2p = await createLibp2p({ - peerId: remotePeerId, addresses: { listen: [remoteListenAddr.toString()] }, @@ -106,10 +94,10 @@ describe('DHT subsystem operates correctly', () => { remoteLibp2p.start() ]) - await libp2p.peerStore.patch(remotePeerId, { + await libp2p.peerStore.patch(remoteLibp2p.peerId, { multiaddrs: [remoteListenAddr] }) - remAddr = await getRemoteAddr(remotePeerId, libp2p) + remAddr = await getRemoteAddr(remoteLibp2p.peerId, libp2p) }) afterEach(async () => { @@ -139,7 +127,7 @@ describe('DHT subsystem operates correctly', () => { const key = uint8ArrayFromString('hello') const value = uint8ArrayFromString('world') - await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs) + await libp2p.dialProtocol(remoteLibp2p.peerId, subsystemMulticodecs) await Promise.all([ // @ts-expect-error private field pWaitFor(() => libp2p.services.dht.routingTable.size === 1), @@ -155,13 +143,9 @@ describe('DHT subsystem operates correctly', () => { }) it('kad-dht should discover other peers', async () => { - const remotePeerId1 = await createEd25519PeerId() - const remotePeerId2 = await createEd25519PeerId() - const deferred = pDefer() - const getConfig = (peerId: PeerId): Libp2pOptions<{ dht: KadDHT }> => ({ - peerId, + const getConfig = (): Libp2pOptions<{ dht: KadDHT }> => ({ addresses: { listen: [ listenAddr.toString() @@ -176,17 +160,17 @@ describe('DHT subsystem operates correctly', () => { } }) - const localConfig = getConfig(peerId) + const localConfig = getConfig() libp2p = await createLibp2p(localConfig) - const remoteLibp2p1 = await createLibp2p(getConfig(remotePeerId1)) - const remoteLibp2p2 = await createLibp2p(getConfig(remotePeerId2)) + const remoteLibp2p1 = await createLibp2p(getConfig()) + const remoteLibp2p2 = await createLibp2p(getConfig()) libp2p.addEventListener('peer:discovery', (evt) => { const { id } = evt.detail - if (id.equals(remotePeerId1)) { + if (id.equals(remoteLibp2p1.peerId)) { libp2p.removeEventListener('peer:discovery') deferred.resolve() } @@ -198,10 +182,10 @@ describe('DHT subsystem operates correctly', () => { remoteLibp2p2.start() ]) - await libp2p.peerStore.patch(remotePeerId1, { + await libp2p.peerStore.patch(remoteLibp2p1.peerId, { multiaddrs: remoteLibp2p1.getMultiaddrs() }) - await remoteLibp2p2.peerStore.patch(remotePeerId1, { + await remoteLibp2p2.peerStore.patch(remoteLibp2p1.peerId, { multiaddrs: remoteLibp2p1.getMultiaddrs() }) @@ -209,8 +193,8 @@ describe('DHT subsystem operates correctly', () => { // A -> B // C -> B await Promise.all([ - libp2p.dial(remotePeerId1), - remoteLibp2p2.dial(remotePeerId1) + libp2p.dial(remoteLibp2p1.peerId), + remoteLibp2p2.dial(remoteLibp2p1.peerId) ]) await deferred.promise diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 8f2323674e..6ec3727687 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -12,7 +12,6 @@ import { UnsupportedError, interopTests } from '@libp2p/interop' import { kadDHT, passthroughMapper } from '@libp2p/kad-dht' import { logger } from '@libp2p/logger' import { mplex } from '@libp2p/mplex' -import { peerIdFromKeys } from '@libp2p/peer-id' import { tcp } from '@libp2p/tcp' import { tls } from '@libp2p/tls' import { multiaddr } from '@multiformats/multiaddr' @@ -20,7 +19,7 @@ import { execa } from 'execa' import { path as p2pd } from 'go-libp2p' import { createLibp2p, type Libp2pOptions, type ServiceFactoryMap } from 'libp2p' import pDefer from 'p-defer' -import type { ServiceMap, PeerId } from '@libp2p/interface' +import type { ServiceMap, PrivateKey } from '@libp2p/interface' import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop' /** @@ -119,16 +118,15 @@ async function createGoPeer (options: SpawnOptions): Promise { } async function createJsPeer (options: SpawnOptions): Promise { - let peerId: PeerId | undefined + let privateKey: PrivateKey | undefined if (options.key != null) { const keyFile = fs.readFileSync(options.key) - const privateKey = await unmarshalPrivateKey(keyFile) - peerId = await peerIdFromKeys(privateKey.public.bytes, privateKey.bytes) + privateKey = await unmarshalPrivateKey(keyFile) } const opts: Libp2pOptions = { - peerId, + privateKey, addresses: { listen: [] }, diff --git a/packages/integration-tests/test/mdns.node.ts b/packages/integration-tests/test/mdns.node.ts index dbf03c4579..e46eac2e97 100644 --- a/packages/integration-tests/test/mdns.node.ts +++ b/packages/integration-tests/test/mdns.node.ts @@ -2,30 +2,18 @@ import { randomBytes } from '@libp2p/crypto' import { mdns } from '@libp2p/mdns' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { tcp } from '@libp2p/tcp' import { multiaddr } from '@multiformats/multiaddr' import { createLibp2p, type Libp2pOptions } from 'libp2p' import defer from 'p-defer' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' -import type { Libp2p, PeerId } from '@libp2p/interface' +import type { Libp2p } from '@libp2p/interface' const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') describe('mdns', () => { - let peerId: PeerId - let remotePeerId1: PeerId - let remotePeerId2: PeerId let libp2p: Libp2p - beforeEach(async () => { - [peerId, remotePeerId1, remotePeerId2] = await Promise.all([ - createEd25519PeerId(), - createEd25519PeerId(), - createEd25519PeerId() - ]) - }) - afterEach(async () => { if (libp2p != null) { await libp2p.stop() @@ -38,8 +26,7 @@ describe('mdns', () => { // use a random tag to prevent CI collision const serviceTag = `libp2p-test-${uint8ArrayToString(randomBytes(4), 'base16')}.local` - const getConfig = (peerId: PeerId): Libp2pOptions => ({ - peerId, + const getConfig = (): Libp2pOptions => ({ addresses: { listen: [ listenAddr.toString() @@ -56,13 +43,13 @@ describe('mdns', () => { ] }) - libp2p = await createLibp2p(getConfig(peerId)) - const remoteLibp2p1 = await createLibp2p(getConfig(remotePeerId1)) - const remoteLibp2p2 = await createLibp2p(getConfig(remotePeerId2)) + libp2p = await createLibp2p(getConfig()) + const remoteLibp2p1 = await createLibp2p(getConfig()) + const remoteLibp2p2 = await createLibp2p(getConfig()) const expectedPeers = new Set([ - remotePeerId1.toString(), - remotePeerId2.toString() + remoteLibp2p1.peerId.toString(), + remoteLibp2p2.peerId.toString() ]) libp2p.addEventListener('peer:discovery', (evt) => { diff --git a/packages/interface-compliance-tests/package.json b/packages/interface-compliance-tests/package.json index d117129358..0058a346e9 100644 --- a/packages/interface-compliance-tests/package.json +++ b/packages/interface-compliance-tests/package.json @@ -72,10 +72,6 @@ "types": "./dist/src/peer-discovery/index.d.ts", "import": "./dist/src/peer-discovery/index.js" }, - "./peers": { - "types": "./dist/src/peers.d.ts", - "import": "./dist/src/peers.js" - }, "./pubsub": { "types": "./dist/src/pubsub/index.d.ts", "import": "./dist/src/pubsub/index.js" @@ -112,6 +108,7 @@ "test:electron-main": "aegir test -t electron-main" }, "dependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface": "^1.7.0", "@libp2p/interface-internal": "^1.3.4", "@libp2p/logger": "^4.0.20", diff --git a/packages/interface-compliance-tests/src/connection-encryption/index.ts b/packages/interface-compliance-tests/src/connection-encryption/index.ts index 7918e69b7a..4245f2e8b6 100644 --- a/packages/interface-compliance-tests/src/connection-encryption/index.ts +++ b/packages/interface-compliance-tests/src/connection-encryption/index.ts @@ -1,16 +1,16 @@ -import * as PeerIdFactory from '@libp2p/peer-id-factory' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import all from 'it-all' import { pipe } from 'it-pipe' import toBuffer from 'it-to-buffer' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import peers from '../peers.js' import { createMaConnPair } from './utils/index.js' import type { TestSetup } from '../index.js' -import type { ConnectionEncrypter, PeerId } from '@libp2p/interface' +import type { ConnectionEncrypter, PeerId, PrivateKey } from '@libp2p/interface' export interface ConnectionEncrypterSetupArgs { - peerId: PeerId + privateKey: PrivateKey } export default (common: TestSetup): void => { @@ -29,11 +29,15 @@ export default (common: TestSetup diff --git a/packages/interface-compliance-tests/src/peers.ts b/packages/interface-compliance-tests/src/peers.ts deleted file mode 100644 index 42bacedeac..0000000000 --- a/packages/interface-compliance-tests/src/peers.ts +++ /dev/null @@ -1,25 +0,0 @@ -export default [{ - id: 'QmNMMAqSxPetRS1cVMmutW5BCN1qQQyEr4u98kUvZjcfEw', - privKey: 'CAASpQkwggShAgEAAoIBAQDPek2aeHMa0blL42RTKd6xgtkk4Zkldvq4LHxzcag5uXepiQzWANEUvoD3KcUTmMRmx14PvsxdLCNst7S2JSa0R2n5wSRs14zGy6892lx4H4tLBD1KSpQlJ6vabYM1CJhIQRG90BtzDPrJ/X1iJ2HA0PPDz0Mflam2QUMDDrU0IuV2m7gSCJ5r4EmMs3U0xnH/1gShkVx4ir0WUdoWf5KQUJOmLn1clTRHYPv4KL9A/E38+imNAXfkH3c2T7DrCcYRkZSpK+WecjMsH1dCX15hhhggNqfp3iulO1tGPxHjm7PDGTPUjpCWKpD5e50sLqsUwexac1ja6ktMfszIR+FPAgMBAAECggEAB2H2uPRoRCAKU+T3gO4QeoiJaYKNjIO7UCplE0aMEeHDnEjAKC1HQ1G0DRdzZ8sb0fxuIGlNpFMZv5iZ2ZFg2zFfV//DaAwTek9tIOpQOAYHUtgHxkj5FIlg2BjlflGb+ZY3J2XsVB+2HNHkUEXOeKn2wpTxcoJE07NmywkO8Zfr1OL5oPxOPlRN1gI4ffYH2LbfaQVtRhwONR2+fs5ISfubk5iKso6BX4moMYkxubYwZbpucvKKi/rIjUA3SK86wdCUnno1KbDfdXSgCiUlvxt/IbRFXFURQoTV6BOi3sP5crBLw8OiVubMr9/8WE6KzJ0R7hPd5+eeWvYiYnWj4QKBgQD6jRlAFo/MgPO5NZ/HRAk6LUG+fdEWexA+GGV7CwJI61W/Dpbn9ZswPDhRJKo3rquyDFVZPdd7+RlXYg1wpmp1k54z++L1srsgj72vlg4I8wkZ4YLBg0+zVgHlQ0kxnp16DvQdOgiRFvMUUMEgetsoIx1CQWTd67hTExGsW+WAZQKBgQDT/WaHWvwyq9oaZ8G7F/tfeuXvNTk3HIJdfbWGgRXB7lJ7Gf6FsX4x7PeERfL5a67JLV6JdiLLVuYC2CBhipqLqC2DB962aKMvxobQpSljBBZvZyqP1IGPoKskrSo+2mqpYkeCLbDMuJ1nujgMP7gqVjabs2zj6ACKmmpYH/oNowJ/T0ZVtvFsjkg+1VsiMupUARRQuPUWMwa9HOibM1NIZcoQV2NGXB5Z++kR6JqxQO0DZlKArrviclderUdY+UuuY4VRiSEprpPeoW7ZlbTku/Ap8QZpWNEzZorQDro7bnfBW91fX9/81ets/gCPGrfEn+58U3pdb9oleCOQc/ifpQKBgBTYGbi9bYbd9vgZs6bd2M2um+VFanbMytS+g5bSIn2LHXkVOT2UEkB+eGf9KML1n54QY/dIMmukA8HL1oNAyalpw+/aWj+9Ui5kauUhGEywHjSeBEVYM9UXizxz+m9rsoktLLLUI0o97NxCJzitG0Kub3gn0FEogsUeIc7AdinZAoGBANnM1vcteSQDs7x94TDEnvvqwSkA2UWyLidD2jXgE0PG4V6tTkK//QPBmC9eq6TIqXkzYlsErSw4XeKO91knFofmdBzzVh/ddgx/NufJV4tXF+a2iTpqYBUJiz9wpIKgf43/Ob+P1EA99GAhSdxz1ess9O2aTqf3ANzn6v6g62Pv', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPek2aeHMa0blL42RTKd6xgtkk4Zkldvq4LHxzcag5uXepiQzWANEUvoD3KcUTmMRmx14PvsxdLCNst7S2JSa0R2n5wSRs14zGy6892lx4H4tLBD1KSpQlJ6vabYM1CJhIQRG90BtzDPrJ/X1iJ2HA0PPDz0Mflam2QUMDDrU0IuV2m7gSCJ5r4EmMs3U0xnH/1gShkVx4ir0WUdoWf5KQUJOmLn1clTRHYPv4KL9A/E38+imNAXfkH3c2T7DrCcYRkZSpK+WecjMsH1dCX15hhhggNqfp3iulO1tGPxHjm7PDGTPUjpCWKpD5e50sLqsUwexac1ja6ktMfszIR+FPAgMBAAE=' -}, { - id: 'QmW8rAgaaA6sRydK1k6vonShQME47aDxaFidbtMevWs73t', - privKey: 'CAASpwkwggSjAgEAAoIBAQCTU3gVDv3SRXLOsFln9GEf1nJ/uCEDhOG10eC0H9l9IPpVxjuPT1ep+ykFUdvefq3D3q+W3hbmiHm81o8dYv26RxZIEioToUWp7Ec5M2B/niYoE93za9/ZDwJdl7eh2hNKwAdxTmdbXUPjkIU4vLyHKRFbJIn9X8w9djldz8hoUvC1BK4L1XrT6F2l0ruJXErH2ZwI1youfSzo87TdXIoFKdrQLuW6hOtDCGKTiS+ab/DkMODc6zl8N47Oczv7vjzoWOJMUJs1Pg0ZsD1zmISY38P0y/QyEhatZn0B8BmSWxlLQuukatzOepQI6k+HtfyAAjn4UEqnMaXTP1uwLldVAgMBAAECggEAHq2f8MqpYjLiAFZKl9IUs3uFZkEiZsgx9BmbMAb91Aec+WWJG4OLHrNVTG1KWp+IcaQablEa9bBvoToQnS7y5OpOon1d066egg7Ymfmv24NEMM5KRpktCNcOSA0CySpPIB6yrg6EiUr3ixiaFUGABKkxmwgVz/Q15IqM0ZMmCUsC174PMAz1COFZxD0ZX0zgHblOJQW3dc0X3XSzhht8vU02SMoVObQHQfeXEHv3K/RiVj/Ax0bTc5JVkT8dm8xksTtsFCNOzRBqFS6MYqX6U/u0Onz3Jm5Jt7fLWb5n97gZR4SleyGrqxYNb46d9X7mP0ie7E6bzFW0DsWBIeAqVQKBgQDW0We2L1n44yOvJaMs3evpj0nps13jWidt2I3RlZXjWzWHiYQfvhWUWqps/xZBnAYgnN/38xbKzHZeRNhrqOo+VB0WK1IYl0lZVE4l6TNKCsLsUfQzsb1pePkd1eRZA+TSqsi+I/IOQlQU7HA0bMrah/5FYyUBP0jYvCOvYTlZuwKBgQCvkcVRydVlzjUgv7lY5lYvT8IHV5iYO4Qkk2q6Wjv9VUKAJZauurMdiy05PboWfs5kbETdwFybXMBcknIvZO4ihxmwL8mcoNwDVZHI4bXapIKMTCyHgUKvJ9SeTcKGC7ZuQJ8mslRmYox/HloTOXEJgQgPRxXcwa3amzvdZI+6LwKBgQCLsnQqgxKUi0m6bdR2qf7vzTH4258z6X34rjpT0F5AEyF1edVFOz0XU/q+lQhpNEi7zqjLuvbYfSyA026WXKuwSsz7jMJ/oWqev/duKgAjp2npesY/E9gkjfobD+zGgoS9BzkyhXe1FCdP0A6L2S/1+zg88WOwMvJxl6/xLl24XwKBgCm60xSajX8yIQyUpWBM9yUtpueJ2Xotgz4ST+bVNbcEAddll8gWFiaqgug9FLLuFu5lkYTHiPtgc1RNdphvO+62/9MRuLDixwh/2TPO+iNqwKDKJjda8Nei9vVddCPaOtU/xNQ0xLzFJbG9LBmvqH9izOCcu8SJwGHaTcNUeJj/AoGADCJ26cY30c13F/8awAAmFYpZWCuTP5ppTsRmjd63ixlrqgkeLGpJ7kYb5fXkcTycRGYgP0e1kssBGcmE7DuG955fx3ZJESX3GQZ+XfMHvYGONwF1EiK1f0p6+GReC2VlQ7PIkoD9o0hojM6SnWvv9EXNjCPALEbfPFFvcniKVsE=', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCTU3gVDv3SRXLOsFln9GEf1nJ/uCEDhOG10eC0H9l9IPpVxjuPT1ep+ykFUdvefq3D3q+W3hbmiHm81o8dYv26RxZIEioToUWp7Ec5M2B/niYoE93za9/ZDwJdl7eh2hNKwAdxTmdbXUPjkIU4vLyHKRFbJIn9X8w9djldz8hoUvC1BK4L1XrT6F2l0ruJXErH2ZwI1youfSzo87TdXIoFKdrQLuW6hOtDCGKTiS+ab/DkMODc6zl8N47Oczv7vjzoWOJMUJs1Pg0ZsD1zmISY38P0y/QyEhatZn0B8BmSWxlLQuukatzOepQI6k+HtfyAAjn4UEqnMaXTP1uwLldVAgMBAAE=' -}, { - id: 'QmZqCdSzgpsmB3Qweb9s4fojAoqELWzqku21UVrqtVSKi4', - privKey: 'CAASpgkwggSiAgEAAoIBAQCdbSEsTmw7lp5HagRcx57DaLiSUEkh4iBcKc7Y+jHICEIA8NIVi9FlfGEZj9G21FpiTR4Cy+BLVEuf8Nm90bym4iV+cSumeS21fvD8xGTEbeKGljs6OYHy3M45JhWF85gqHQJOqZufI2NRDuRgMZEO2+qGEXmSlv9mMXba/+9ecze8nSpB7bG2Z2pnKDeYwhF9Cz+ElMyn7TBWDjJERGVgFbTpdM3rBnbhB/TGpvs732QqZmIBlxnDb/Jn0l1gNZCgkEDcJ/0NDMBJTQ8vbvcdmaw3eaMPLkn1ix4wdu9QWCA0IBtuY1R7vSUtf4irnLJG7DnAw2GfM5QrF3xF1GLXAgMBAAECggEAQ1N0qHoxl5pmvqv8iaFlqLSUmx5y6GbI6CGJMQpvV9kQQU68yjItr3VuIXx8d/CBZyEMAK4oko7OeOyMcr3MLKLy3gyQWnXgsopDjhZ/8fH8uwps8g2+IZuFJrO+6LaxEPGvFu06fOiphPUVfn40R2KN/iBjGeox+AaXijmCqaV2vEdNJJPpMfz6VKZBDLTrbiqvo/3GN1U99PUqfPWpOWR29oAhh/Au6blSqvqTUPXB2+D/X6e1JXv31mxMPK68atDHSUjZWKB9lE4FMK1bkSKJRbyXmNIlbZ9V8X4/0r8/6T7JnW7ZT8ugRkquohmwgG7KkDXB1YsOCKXYUqzVYQKBgQDtnopFXWYl7XUyePJ/2MA5i7eoko9jmF44L31irqmHc5unNf6JlNBjlxTNx3WyfzhUzrn3c18psnGkqtow0tkBj5hmqn8/WaPbc5UA/5R1FNaNf8W5khn7MDm6KtYRPjN9djqTDiVHyC6ljONYd+5S+MqyKVWZ3t/xvG60sw85qwKBgQCpmpDtL+2JBwkfeUr3LyDcQxvbfzcv8lXj2otopWxWiLiZF1HzcqgAa2CIwu9kCGEt9Zr+9E4uINbe1To0b01/FhvR6xKO/ukceGA/mBB3vsKDcRmvpBUp+3SmnhY0nOk+ArQl4DhJ34k8pDM3EDPrixPf8SfVdU/8IM32lsdHhQKBgHLgpvCKCwxjFLnmBzcPzz8C8TOqR3BbBZIcQ34l+wflOGdKj1hsfaLoM8KYn6pAHzfBCd88A9Hg11hI0VuxVACRL5jS7NnvuGwsIOluppNEE8Ys86aXn7/0vLPoab3EWJhbRE48FIHzobmft3nZ4XpzlWs02JGfUp1IAC2UM9QpAoGAeWy3pZhSr2/iEC5+hUmwdQF2yEbj8+fDpkWo2VrVnX506uXPPkQwE1zM2Bz31t5I9OaJ+U5fSpcoPpDaAwBMs1fYwwlRWB8YNdHY1q6/23svN3uZsC4BGPV2JnO34iMUudilsRg+NGVdk5TbNejbwx7nM8Urh59djFzQGGMKeSECgYA0QMCARPpdMY50Mf2xQaCP7HfMJhESSPaBq9V3xY6ToEOEnXgAR5pNjnU85wnspHp+82r5XrKfEQlFxGpj2YA4DRRmn239sjDa29qP42UNAFg1+C3OvXTht1d5oOabaGhU0udwKmkEKUbb0bG5xPQJ5qeSJ5T1gLzLk3SIP0GlSw==', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdbSEsTmw7lp5HagRcx57DaLiSUEkh4iBcKc7Y+jHICEIA8NIVi9FlfGEZj9G21FpiTR4Cy+BLVEuf8Nm90bym4iV+cSumeS21fvD8xGTEbeKGljs6OYHy3M45JhWF85gqHQJOqZufI2NRDuRgMZEO2+qGEXmSlv9mMXba/+9ecze8nSpB7bG2Z2pnKDeYwhF9Cz+ElMyn7TBWDjJERGVgFbTpdM3rBnbhB/TGpvs732QqZmIBlxnDb/Jn0l1gNZCgkEDcJ/0NDMBJTQ8vbvcdmaw3eaMPLkn1ix4wdu9QWCA0IBtuY1R7vSUtf4irnLJG7DnAw2GfM5QrF3xF1GLXAgMBAAE=' -}, { - id: 'QmR5VwgsL7jyfZHAGyp66tguVrQhCRQuRc3NokocsCZ3fA', - privKey: 'CAASpwkwggSjAgEAAoIBAQCGXYU+uc2nn1zuJhfdFOl34upztnrD1gpHu58ousgHdGlGgYgbqLBAvIAauXdEL0+e30HofjA634SQxE+9nV+0FQBam1DDzHQlXsuwHV+2SKvSDkk4bVllMFpu2SJtts6VH+OXC/2ANJOm+eTALykQPYXgLIBxrhp/eD+Jz5r6wW2nq3k6OmYyK/4pgGzFjo5UyX+fa/171AJ68UPboFpDy6BZCcUjS0ondxPvD7cv5jMNqqMKIB/7rpi8n+Q3oeccRqVL56wH+FE3/QLjwYHwY6ILNRyvNXRqHjwBEXB2R5moXN0AFUWTw9rt3KhFiEjR1U81BTw5/xS7W2Iu0FgZAgMBAAECggEAS64HK8JZfE09eYGJNWPe8ECmD1C7quw21BpwVe+GVPSTizvQHswPohbKDMNj0srXDMPxCnNw1OgqcaOwyjsGuZaOoXoTroTM8nOHRIX27+PUqzaStS6aCG2IsiCozKUHjGTuupftS7XRaF4eIsUtWtFcQ1ytZ9pJYHypRQTi5NMSrTze5ThjnWxtHilK7gnBXik+aR0mYEVfSn13czQEC4rMOs+b9RAc/iibDNoLopfIdvmCCvfxzmySnR7Cu1iSUAONkir7PB+2Mt/qRFCH6P+jMamtCgQ8AmifXgVmDUlun+4MnKg3KrPd6ZjOEKhVe9mCHtGozk65RDREShfDdQKBgQDi+x2MuRa9peEMOHnOyXTS+v+MFcfmG0InsO08rFNBKZChLB+c9UHBdIvexpfBHigSyERfuDye4z6lxi8ZnierWMYJP30nxmrnxwTGTk1MQquhfs1A0kpmDnPsjlOS/drEIEIssNx2WbfJ7YtMxLWBtp+BJzGpQmr0LKC+NHRSrwKBgQCXiy2kJESIUkIs2ihV55hhT6/bZo1B1O5DPA2nkjOBXqXF6fvijzMDX82JjLd07lQZlI0n1Q/Hw0p4iYi9YVd2bLkLXF5UIb2qOeHj76enVFOrPHUSkC9Y2g/0Xs+60Ths2xRd8RrrfQU3kl5iVpBywkCIrb2M5+wRnNTk1W3TtwKBgQCvplyrteAfSurpJhs9JzE8w/hWU9SqAZYkWQp91W1oE95Um2yrbjBAoQxMjaqKS+f/APPIjy56Vqj4aHGyhW11b/Fw3qzfxvCcBKtxOs8eoMlo5FO6QgJJEA4tlcafDcvp0nzjUMqK28safLU7503+33B35fjMXxWdd5u9FaKfCQKBgC4W6j6tuRosymuRvgrCcRnHfpify/5loEFallyMnpWOD6Tt0OnK25z/GifnYDRz96gAAh5HMpFy18dpLOlMHamqz2yhHx8/U8vd5tHIJZlCkF/X91M5/uxrBccwvsT2tM6Got8fYSyVzWxlW8dUxIHiinYHQUsFjkqdBDLEpq5pAoGASoTw5RBEWFM0GuAZdXsyNyxU+4S+grkTS7WdW/Ymkukh+bJZbnvF9a6MkSehqXnknthmufonds2AFNS//63gixENsoOhzT5+2cdfc6tJECvJ9xXVXkf85AoQ6T/RrXF0W4m9yQyCngNJUrKUOIH3oDIfdZITlYzOC3u1ojj7VuQ=', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCGXYU+uc2nn1zuJhfdFOl34upztnrD1gpHu58ousgHdGlGgYgbqLBAvIAauXdEL0+e30HofjA634SQxE+9nV+0FQBam1DDzHQlXsuwHV+2SKvSDkk4bVllMFpu2SJtts6VH+OXC/2ANJOm+eTALykQPYXgLIBxrhp/eD+Jz5r6wW2nq3k6OmYyK/4pgGzFjo5UyX+fa/171AJ68UPboFpDy6BZCcUjS0ondxPvD7cv5jMNqqMKIB/7rpi8n+Q3oeccRqVL56wH+FE3/QLjwYHwY6ILNRyvNXRqHjwBEXB2R5moXN0AFUWTw9rt3KhFiEjR1U81BTw5/xS7W2Iu0FgZAgMBAAE=' -}, { - id: 'QmScLDqRg7H6ipCYxm9fVk152UWavQFKscTdoT4YNHxgqp', - privKey: 'CAASpwkwggSjAgEAAoIBAQCWEHaTZ6LBLFP5OPrUqjDM/cF4b2zrfh1Zm3kd02ZtgQB3iYtZqRPJT5ctT3A7WdVF/7dCxPGOCkJlLekTx4Y4gD8JtjA+EfN9fR/2RBKbti2N3CD4vkGp9ss4hbBFcXIhl8zuD/ELHutbV6b8b4QXJGnxfp/B+1kNPnyd7SJznS0QyvI8OLI1nAkVKdYLDRW8kPKeHyx1xhdNDuTQVTFyAjRGQ4e3UYFB7bYIHW3E6kCtCoJDlj+JPC02Yt1LHzIzZVLvPvNFnYY2mag6OiGFuh/oMBIqvnPc1zRZ3eLUqeGZjQVaoR0kdgZUKz7Q2TBeNldxK/s6XO0DnkQTlelNAgMBAAECggEAdmt1dyswR2p4tdIeNpY7Pnj9JNIhTNDPznefI0dArCdBvBMhkVaYk6MoNIxcj6l7YOrDroAF8sXr0TZimMY6B/pERKCt/z1hPWTxRQBBAvnHhwvwRPq2jK6BfhAZoyM8IoBNKowP9mum5QUNdGV4Al8s73KyFX0IsCfgZSvNpRdlt+DzPh+hu/CyoZaMpRchJc1UmK8Fyk3KfO+m0DZNfHP5P08lXNfM6MZLgTJVVgERHyG+vBOzTd2RElMe19nVCzHwb3dPPRZSQ7Fnz3rA+GeLqsM2Zi4HNhfbD1OcD9C4wDj5tYL6hWTkdz4IlfVcjCeUHxgIOhdDV2K+OwbuAQKBgQD0FjUZ09UW2FQ/fitbvIB5f1SkXWPxTF9l6mAeuXhoGv2EtQUO4vq/PK6N08RjrZdWQy6UsqHgffi7lVQ8o3hvCKdbtf4sP+cM92OrY0WZV89os79ndj4tyvmnP8WojwRjt/2XEfgdoWcgWxW9DiYINTOQVimZX+X/3on4s8hEgQKBgQCdY3kOMbyQeLTRkqHXjVTY4ddO+v4S4wOUa1l4rTqAbq1W3JYWwoDQgFuIu3limIHmjnSJpCD4EioXFsM7p6csenoc20sHxsaHnJ6Mn5Te41UYmY9EW0otkQ0C3KbXM0hwQkjyplnEmZawGKmjEHW8DJ3vRYTv9TUCgYKxDHgOzQKBgB4A/NYH7BG61eBYKgxEx6YnuMfbkwV+Vdu5S8d7FQn3B2LgvZZu4FPRqcNVXLbEB+5ao8czjiKCWaj1Wj15+rvrXGcxn+Tglg5J+r5+nXeUC7LbJZQaPNp0MOwWMr3dlrSLUWjYlJ9Pz9VyXOG4c4Rexc/gR4zK9QLW4C7qKpwBAoGAZzyUb0cYlPtYQA+asTU3bnvVKy1f8yuNcZFowst+EDiI4u0WVh+HNzy6zdmLKa03p+/RaWeLaK0hhrubnEnAUmCUMNF3ScaM+u804LDcicc8TkKLwx7ObU0z56isl4RAA8K27tNHFrpYKXJD834cfBkaj5ReOrfw6Y/iFhhDuBECgYEA8gbC76uz7LSHhW30DSRTcqOzTyoe2oYKQaxuxYNp7vSSOkcdRen+mrdflDvud2q/zN2QdL4pgqdldHlR35M/lJ0f0B6zp74jlzbO9700wzsOqreezGc5eWiroDL100U9uIZ50BKb8CKtixIHpinUSPIUcVDkSAZ2y7mbfCxQwqQ=', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWEHaTZ6LBLFP5OPrUqjDM/cF4b2zrfh1Zm3kd02ZtgQB3iYtZqRPJT5ctT3A7WdVF/7dCxPGOCkJlLekTx4Y4gD8JtjA+EfN9fR/2RBKbti2N3CD4vkGp9ss4hbBFcXIhl8zuD/ELHutbV6b8b4QXJGnxfp/B+1kNPnyd7SJznS0QyvI8OLI1nAkVKdYLDRW8kPKeHyx1xhdNDuTQVTFyAjRGQ4e3UYFB7bYIHW3E6kCtCoJDlj+JPC02Yt1LHzIzZVLvPvNFnYY2mag6OiGFuh/oMBIqvnPc1zRZ3eLUqeGZjQVaoR0kdgZUKz7Q2TBeNldxK/s6XO0DnkQTlelNAgMBAAE=' -}, { - id: 'QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN', - privKey: 'CAASpwkwggSjAgEAAoIBAQC1/GFud/7xutux7qRfMj1sIdMRh99/chR6HqVj6LQqrgk4jil0mdN/LCk/tqPqmDtObHdmEhCoybzuhLbCKgUqryKDwO6yBJHSKWY9QqrKZtLJ37SgKwGjE3+NUD4r1dJHhtQrICFdOdSCBzs/v8gi+J+KZLHo7+Nms4z09ysy7qZh94Pd7cW4gmSMergqUeANLD9C0ERw1NXolswOW7Bi7UGr7yuBxejICLO3nkxe0OtpQBrYrqdCD9vs3t/HQZbPWVoiRj4VO7fxkAPKLl30HzcIfxj/ayg8NHcH59d08D+N2v5Sdh28gsiYKIPE9CXvuw//HUY2WVRY5fDC5JglAgMBAAECggEBAKb5aN/1w3pBqz/HqRMbQpYLNuD33M3PexBNPAy+P0iFpDo63bh5Rz+A4lvuFNmzUX70MFz7qENlzi6+n/zolxMB29YtWBUH8k904rTEjXXl//NviQgITZk106tx+4k2x5gPEm57LYGfBOdFAUzNhzDnE2LkXwRNzkS161f7zKwOEsaGWRscj6UvhO4MIFxjb32CVwt5eK4yOVqtyMs9u30K4Og+AZYTlhtm+bHg6ndCCBO6CQurCQ3jD6YOkT+L3MotKqt1kORpvzIB0ujZRf49Um8wlcjC5G9aexBeGriXaVdPF62zm7GA7RMsbQM/6aRbA1fEQXvJhHUNF9UFeaECgYEA8wCjKqQA7UQnHjRwTsktdwG6szfxd7z+5MTqHHTWhWzgcQLgdh5/dO/zanEoOThadMk5C1Bqjq96gH2xim8dg5XQofSVtV3Ui0dDa+XRB3E3fyY4D3RF5hHv85O0GcvQc6DIb+Ja1oOhvHowFB1C+CT3yEgwzX/EK9xpe+KtYAkCgYEAv7hCnj/DcZFU3fAfS+unBLuVoVJT/drxv66P686s7J8UM6tW+39yDBZ1IcwY9vHFepBvxY2fFfEeLI02QFM+lZXVhNGzFkP90agNHK01psGgrmIufl9zAo8WOKgkLgbYbSHzkkDeqyjEPU+B0QSsZOCE+qLCHSdsnTmo/TjQhj0CgYAz1+j3yfGgrS+jVBC53lXi0+2fGspbf2jqKdDArXSvFqFzuudki/EpY6AND4NDYfB6hguzjD6PnoSGMUrVfAtR7X6LbwEZpqEX7eZGeMt1yQPMDr1bHrVi9mS5FMQR1NfuM1lP9Xzn00GIUpE7WVrWUhzDEBPJY/7YVLf0hFH08QKBgDWBRQZJIVBmkNrHktRrVddaSq4U/d/Q5LrsCrpymYwH8WliHgpeTQPWmKXwAd+ZJdXIzYjCt202N4eTeVqGYOb6Q/anV2WVYBbM4avpIxoA28kPGY6nML+8EyWIt2ApBOmgGgvtEreNzwaVU9NzjHEyv6n7FlVwlT1jxCe3XWq5AoGASYPKQoPeDlW+NmRG7z9EJXJRPVtmLL40fmGgtju9QIjLnjuK8XaczjAWT+ySI93Whu+Eujf2Uj7Q+NfUjvAEzJgwzuOd3jlQvoALq11kuaxlNQTn7rx0A1QhBgUJE8AkvShPC9FEnA4j/CLJU0re9H/8VvyN6qE0Mho0+YbjpP8=', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1/GFud/7xutux7qRfMj1sIdMRh99/chR6HqVj6LQqrgk4jil0mdN/LCk/tqPqmDtObHdmEhCoybzuhLbCKgUqryKDwO6yBJHSKWY9QqrKZtLJ37SgKwGjE3+NUD4r1dJHhtQrICFdOdSCBzs/v8gi+J+KZLHo7+Nms4z09ysy7qZh94Pd7cW4gmSMergqUeANLD9C0ERw1NXolswOW7Bi7UGr7yuBxejICLO3nkxe0OtpQBrYrqdCD9vs3t/HQZbPWVoiRj4VO7fxkAPKLl30HzcIfxj/ayg8NHcH59d08D+N2v5Sdh28gsiYKIPE9CXvuw//HUY2WVRY5fDC5JglAgMBAAE=' -}] diff --git a/packages/interface-compliance-tests/src/pubsub/index.ts b/packages/interface-compliance-tests/src/pubsub/index.ts index 7e5fa3fe95..bedc3f3c72 100644 --- a/packages/interface-compliance-tests/src/pubsub/index.ts +++ b/packages/interface-compliance-tests/src/pubsub/index.ts @@ -5,11 +5,12 @@ import messagesTest from './messages.js' import multipleNodesTest from './multiple-nodes.js' import twoNodesTest from './two-nodes.js' import type { TestSetup } from '../index.js' -import type { ComponentLogger, PeerId, PubSub, PubSubInit } from '@libp2p/interface' +import type { ComponentLogger, PeerId, PrivateKey, PubSub, PubSubInit } from '@libp2p/interface' import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' export interface PubSubComponents { peerId: PeerId + privateKey: PrivateKey registrar: Registrar connectionManager: ConnectionManager pubsub?: PubSub diff --git a/packages/interface/src/index.ts b/packages/interface/src/index.ts index cd81122d82..708fb4b96d 100644 --- a/packages/interface/src/index.ts +++ b/packages/interface/src/index.ts @@ -347,7 +347,10 @@ export type OpenConnectionProgressEvents = OutboundConnectionUpgradeEvents export interface DialOptions extends AbortOptions, ProgressOptions { - + /** + * If true, open a new connection to the remote even if one already exists + */ + force?: boolean } export interface DialProtocolOptions extends NewStreamOptions { diff --git a/packages/interface/src/keys/index.ts b/packages/interface/src/keys/index.ts index 648a1211b1..9f4cd97073 100644 --- a/packages/interface/src/keys/index.ts +++ b/packages/interface/src/keys/index.ts @@ -1,31 +1,35 @@ import type { Uint8ArrayList } from 'uint8arraylist' -export interface PublicKey { +export interface PublicKey { + readonly type: Type readonly bytes: Uint8Array verify(data: Uint8Array | Uint8ArrayList, sig: Uint8Array): boolean | Promise marshal(): Uint8Array - equals(key: PublicKey): boolean + equals(key?: any): boolean hash(): Uint8Array | Promise } /** * Generic private key interface */ -export interface PrivateKey { +export interface PrivateKey { + readonly type: Type readonly public: PublicKey readonly bytes: Uint8Array sign(data: Uint8Array | Uint8ArrayList): Uint8Array | Promise marshal(): Uint8Array - equals(key: PrivateKey): boolean + equals(key?: any): boolean hash(): Uint8Array | Promise + /** * Gets the ID of the key. * - * The key id is the base58 encoding of the SHA-256 multihash of its public key. - * The public key is a protobuf encoding containing a type and the DER encoding - * of the PKCS SubjectPublicKeyInfo. + * The key id is the base58 encoding of the SHA-256 multihash of its public + * key. The public key is a protobuf encoding containing a type and the DER + * encoding of the PKCS SubjectPublicKeyInfo. */ id(): Promise + /** * Exports the password protected key in the format specified. */ diff --git a/packages/interface/src/peer-id/index.ts b/packages/interface/src/peer-id/index.ts index a88dc8e5dc..e3ecf4cb3b 100644 --- a/packages/interface/src/peer-id/index.ts +++ b/packages/interface/src/peer-id/index.ts @@ -4,39 +4,65 @@ import type { MultihashDigest } from 'multiformats/hashes/interface' export type PeerIdType = KeyType | string -export interface RSAPeerId extends PeerId { +/** + * A PeerId generated from an RSA private key. + * + * The PeerId is a base58btc encoded sha-256 hash of the private key. + * + * RSA public keys are too large to pass around freely, instead Ed25519 or + * secp256k1 should be preferred as they can embed their public key in the + * PeerId itself. + * + * @deprecated Ed25519 or secp256k1 keys are preferred to RSA + */ +export interface RSAPeerId { readonly type: 'RSA' readonly publicKey?: Uint8Array + readonly multihash: MultihashDigest + + toString(): string + toCID(): CID + toBytes(): Uint8Array + equals(other?: any): boolean } -export interface Ed25519PeerId extends PeerId { +export interface Ed25519PeerId { readonly type: 'Ed25519' readonly publicKey: Uint8Array + readonly multihash: MultihashDigest + + toString(): string + toCID(): CID + toBytes(): Uint8Array + equals(other?: any): boolean } -export interface Secp256k1PeerId extends PeerId { +export interface Secp256k1PeerId { readonly type: 'secp256k1' readonly publicKey: Uint8Array -} + readonly multihash: MultihashDigest -export interface URLPeerId extends PeerId { - readonly type: 'url' + toString(): string + toCID(): CID + toBytes(): Uint8Array + equals(other?: any): boolean } -export interface PeerId { - type: PeerIdType - multihash: MultihashDigest - privateKey?: Uint8Array - publicKey?: Uint8Array +export interface URLPeerId { + readonly type: 'url' + readonly multihash: MultihashDigest + readonly publicKey: undefined toString(): string toCID(): CID toBytes(): Uint8Array - equals(other?: PeerId | Uint8Array | string): boolean + equals(other?: any): boolean } +export type PeerId = RSAPeerId | Ed25519PeerId | Secp256k1PeerId | URLPeerId + export const peerIdSymbol = Symbol.for('@libp2p/peer-id') -export function isPeerId (other: any): other is PeerId { - return other != null && Boolean(other[peerIdSymbol]) +export function isPeerId (other?: any): other is PeerId { + return Boolean(other?.[peerIdSymbol]) } diff --git a/packages/interface/src/record/index.ts b/packages/interface/src/record/index.ts index 5698d546b5..f17f50d460 100644 --- a/packages/interface/src/record/index.ts +++ b/packages/interface/src/record/index.ts @@ -1,4 +1,4 @@ -import type { PeerId } from '../peer-id/index.js' +import type { PublicKey } from '../keys/index.js' import type { Uint8ArrayList } from 'uint8arraylist' /** @@ -24,7 +24,7 @@ export interface Record { } export interface Envelope { - peerId: PeerId + publicKey: PublicKey payloadType: Uint8Array | Uint8ArrayList payload: Uint8Array signature: Uint8Array | Uint8ArrayList diff --git a/packages/kad-dht/src/index.ts b/packages/kad-dht/src/index.ts index 00f80e5d53..b80a4aca5f 100644 --- a/packages/kad-dht/src/index.ts +++ b/packages/kad-dht/src/index.ts @@ -84,7 +84,7 @@ import { KadDHT as KadDHTClass } from './kad-dht.js' import { MessageType } from './message/dht.js' import { removePrivateAddressesMapper, removePublicAddressesMapper, passthroughMapper } from './utils.js' import type { ProvidersInit } from './providers.js' -import type { Libp2pEvents, ComponentLogger, TypedEventTarget, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions } from '@libp2p/interface' +import type { Libp2pEvents, ComponentLogger, TypedEventTarget, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions, PrivateKey } from '@libp2p/interface' import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal' import type { AdaptiveTimeoutInit } from '@libp2p/utils/src/adaptive-timeout.js' import type { Datastore } from 'interface-datastore' @@ -445,6 +445,7 @@ export interface KadDHTInit { export interface KadDHTComponents { peerId: PeerId + privateKey: PrivateKey registrar: Registrar addressManager: AddressManager peerStore: PeerStore diff --git a/packages/kad-dht/test/kad-dht.spec.ts b/packages/kad-dht/test/kad-dht.spec.ts index 3fc7ab4b89..3e9219f25f 100644 --- a/packages/kad-dht/test/kad-dht.spec.ts +++ b/packages/kad-dht/test/kad-dht.spec.ts @@ -18,7 +18,7 @@ import * as c from '../src/constants.js' import { EventTypes, MessageType } from '../src/index.js' import { peerResponseEvent } from '../src/query/events.js' import * as kadUtils from '../src/utils.js' -import { createPeerIds } from './utils/create-peer-id.js' +import { createPeerIds, type PeerIdWithPrivateKey } from './utils/create-peer-id.js' import { createValues } from './utils/create-values.js' import { countDiffPeers } from './utils/index.js' import { sortClosestPeers } from './utils/sort-closest-peers.js' @@ -48,7 +48,7 @@ async function findEvent (events: AsyncIterable, name: string): Prom } describe('KadDHT', () => { - let peerIds: PeerId[] + let peerIds: PeerIdWithPrivateKey[] let values: Array<{ cid: CID, value: Uint8Array }> let tdht: TestDHT @@ -696,7 +696,12 @@ describe('KadDHT', () => { new Array(nDHTs).fill(0).map(async () => tdht.spawn()) ) - const dhtsById = new Map(dhts.map((d) => [d.components.peerId, d])) + const dhtsById = new Map(dhts.map((d) => { + const peerId = d.components.peerId as unknown as PeerIdWithPrivateKey + peerId.privateKey = d.components.privateKey + + return [peerId, d] + })) const ids = [...dhtsById.keys()] // The origin node for the FIND_PEER query @@ -710,7 +715,7 @@ describe('KadDHT', () => { // Make connections between nodes close to each other const sorted = await sortClosestPeers(ids, rtval) - const conns: PeerId[][] = [] + const conns: PeerIdWithPrivateKey[][] = [] const maxRightIndex = sorted.length - 1 for (let i = 0; i < sorted.length; i++) { // Connect to 5 nodes on either side (10 in total) diff --git a/packages/kad-dht/test/libp2p-routing.spec.ts b/packages/kad-dht/test/libp2p-routing.spec.ts index 56458f16b7..e9df4fee50 100644 --- a/packages/kad-dht/test/libp2p-routing.spec.ts +++ b/packages/kad-dht/test/libp2p-routing.spec.ts @@ -14,14 +14,15 @@ import { stubInterface, type StubbedInstance } from 'sinon-ts' import { kadDHT, passthroughMapper, type KadDHT } from '../src/index.js' import { Message, MessageType } from '../src/message/dht.js' import { convertBuffer } from '../src/utils.js' -import { createPeerIds } from './utils/create-peer-id.js' +import { createPeerIds, type PeerIdWithPrivateKey } from './utils/create-peer-id.js' import { sortClosestPeers } from './utils/sort-closest-peers.js' -import type { ContentRouting, PeerStore, PeerId, TypedEventTarget, ComponentLogger, Connection, Peer, Stream, PeerRouting } from '@libp2p/interface' +import type { ContentRouting, PeerStore, PeerId, TypedEventTarget, ComponentLogger, Connection, Peer, Stream, PeerRouting, PrivateKey } from '@libp2p/interface' import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal' import type { Datastore } from 'interface-datastore' interface StubbedKadDHTComponents { peerId: PeerId + privateKey: PrivateKey registrar: StubbedInstance addressManager: StubbedInstance peerStore: StubbedInstance @@ -80,7 +81,7 @@ describe('content routing', () => { let contentRouting: ContentRouting let components: StubbedKadDHTComponents let dht: KadDHT - let peers: PeerId[] + let peers: PeerIdWithPrivateKey[] let key: CID beforeEach(async () => { @@ -93,6 +94,7 @@ describe('content routing', () => { components = { peerId: peers[peers.length - 1], + privateKey: peers[peers.length - 1].privateKey, registrar: stubInterface(), addressManager: stubInterface(), peerStore: stubInterface({ @@ -209,7 +211,7 @@ describe('peer routing', () => { let peerRouting: PeerRouting let components: StubbedKadDHTComponents let dht: KadDHT - let peers: PeerId[] + let peers: PeerIdWithPrivateKey[] let key: CID beforeEach(async () => { @@ -222,6 +224,7 @@ describe('peer routing', () => { components = { peerId: peers[peers.length - 1], + privateKey: peers[peers.length - 1].privateKey, registrar: stubInterface(), addressManager: stubInterface(), peerStore: stubInterface({ diff --git a/packages/kad-dht/test/routing-table.spec.ts b/packages/kad-dht/test/routing-table.spec.ts index 49f0ee3463..830a14d1e7 100644 --- a/packages/kad-dht/test/routing-table.spec.ts +++ b/packages/kad-dht/test/routing-table.spec.ts @@ -275,9 +275,7 @@ describe('Routing Table', () => { const tagPeerSpy = sinon.spy(components.peerStore, 'merge') const localNodeId = await kadUtils.convertPeerId(components.peerId) const sortedPeerList = await sortClosestPeers( - await Promise.all( - new Array(KBUCKET_SIZE + 1).fill(0).map(async () => createEd25519PeerId()) - ), + await createPeerIds(KBUCKET_SIZE + 1), localNodeId ) diff --git a/packages/kad-dht/test/utils/create-peer-id.ts b/packages/kad-dht/test/utils/create-peer-id.ts index 8fe7de9296..3f20273be2 100644 --- a/packages/kad-dht/test/utils/create-peer-id.ts +++ b/packages/kad-dht/test/utils/create-peer-id.ts @@ -1,19 +1,30 @@ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' -import type { Ed25519PeerId } from '@libp2p/interface' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createFromPrivKey } from '@libp2p/peer-id-factory' +import type { PeerId, PrivateKey } from '@libp2p/interface' + +export type PeerIdWithPrivateKey = PeerId & { + privateKey: PrivateKey +} /** * Creates multiple PeerIds */ -export async function createPeerIds (length: number): Promise { +export async function createPeerIds (length: number): Promise { return Promise.all( - new Array(length).fill(0).map(async () => createEd25519PeerId()) + new Array(length).fill(0).map(async () => { + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) as unknown as PeerIdWithPrivateKey + peerId.privateKey = privateKey + + return peerId + }) ) } /** * Creates a PeerId */ -export async function createPeerId (): Promise { +export async function createPeerId (): Promise { const ids = await createPeerIds(1) return ids[0] diff --git a/packages/kad-dht/test/utils/sort-closest-peers.ts b/packages/kad-dht/test/utils/sort-closest-peers.ts index 14ccb90c9c..3fe15bcf9d 100644 --- a/packages/kad-dht/test/utils/sort-closest-peers.ts +++ b/packages/kad-dht/test/utils/sort-closest-peers.ts @@ -3,12 +3,12 @@ import map from 'it-map' import { xor as uint8ArrayXor } from 'uint8arrays/xor' import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare' import { convertPeerId } from '../../src/utils.js' -import type { PeerId } from '@libp2p/interface' +import type { PeerIdWithPrivateKey } from './create-peer-id.js' /** * Sort peers by distance to the given `kadId` */ -export async function sortClosestPeers (peers: PeerId[], kadId: Uint8Array): Promise { +export async function sortClosestPeers (peers: PeerIdWithPrivateKey[], kadId: Uint8Array): Promise { const distances = await all( map(peers, async (peer) => { const id = await convertPeerId(peer) diff --git a/packages/kad-dht/test/utils/test-dht.ts b/packages/kad-dht/test/utils/test-dht.ts index 839078edda..febb7f56e6 100644 --- a/packages/kad-dht/test/utils/test-dht.ts +++ b/packages/kad-dht/test/utils/test-dht.ts @@ -1,6 +1,8 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { TypedEventEmitter, start, stop } from '@libp2p/interface' import { mockRegistrar, mockConnectionManager, mockNetwork } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' import { multiaddr } from '@multiformats/multiaddr' import { MemoryDatastore } from 'datastore-core/memory' @@ -10,7 +12,6 @@ import { stubInterface } from 'sinon-ts' import { PROTOCOL } from '../../src/constants.js' import { type KadDHT, type KadDHTComponents, type KadDHTInit } from '../../src/index.js' import { KadDHT as KadDHTClass } from '../../src/kad-dht.js' -import { createPeerId } from './create-peer-id.js' import type { Libp2pEvents, PeerId, PeerStore } from '@libp2p/interface' import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal' @@ -23,8 +24,13 @@ export class TestDHT { async spawn (options: Partial = {}, autoStart = true): Promise { const events = new TypedEventEmitter() + + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + const components: KadDHTComponents = { - peerId: await createPeerId(), + peerId, + privateKey, datastore: new MemoryDatastore(), registrar: mockRegistrar(), // connectionGater: mockConnectionGater(), diff --git a/packages/keychain/package.json b/packages/keychain/package.json index 2c5a59cd9c..71a1672f63 100644 --- a/packages/keychain/package.json +++ b/packages/keychain/package.json @@ -61,16 +61,13 @@ "dependencies": { "@libp2p/crypto": "^4.1.9", "@libp2p/interface": "^1.7.0", - "@libp2p/peer-id": "^4.2.4", "interface-datastore": "^8.2.11", "merge-options": "^3.0.4", - "multiformats": "^13.1.0", "sanitize-filename": "^1.6.3", "uint8arrays": "^5.1.0" }, "devDependencies": { "@libp2p/logger": "^4.0.20", - "@libp2p/peer-id-factory": "^4.2.4", "aegir": "^44.0.1", "datastore-core": "^10.0.0" }, diff --git a/packages/keychain/src/index.ts b/packages/keychain/src/index.ts index 03fdfd8702..4f8056af56 100644 --- a/packages/keychain/src/index.ts +++ b/packages/keychain/src/index.ts @@ -51,10 +51,9 @@ * A key benefit is that now the key chain can be used in browser with the [js-datastore-level](https://github.com/ipfs/js-datastore-level) implementation. */ -import { DefaultKeychain } from './keychain.js' -import type { ComponentLogger, KeyType, PeerId } from '@libp2p/interface' +import { Keychain as KeychainClass } from './keychain.js' +import type { ComponentLogger, PrivateKey } from '@libp2p/interface' import type { Datastore } from 'interface-datastore' -import type { Multibase } from 'multiformats/bases/interface.js' export interface DEKConfig { hash: string @@ -87,73 +86,63 @@ export interface KeyInfo { export interface Keychain { /** - * Export an existing key as a PEM encrypted PKCS #8 string. + * Find a key by name * * @example * * ```TypeScript - * await libp2p.keychain.createKey('keyTest', 'RSA', 4096) - * const pemKey = await libp2p.keychain.exportKey('keyTest', 'password123') - * ``` - */ - exportKey(name: string, password: string): Promise> - - /** - * Import a new key from a PEM encoded PKCS #8 string. + * import { generateKeyPair } from '@libp2p/crypto/keys' * - * @example - * - * ```TypeScript - * await libp2p.keychain.createKey('keyTest', 'RSA', 4096) - * const pemKey = await libp2p.keychain.exportKey('keyTest', 'password123') - * const keyInfo = await libp2p.keychain.importKey('keyTestImport', pemKey, 'password123') + * const key = await generateKeyPair('Ed25519') + * const keyInfo = await libp2p.keychain.importKey('my-key', key) + * const keyInfo2 = await libp2p.keychain.findKeyByName(keyInfo.name) * ``` */ - importKey(name: string, pem: string, password: string): Promise + findKeyByName(name: string): Promise /** - * Import a new key from a PeerId with a private key component + * Find a key by id * * @example * * ```TypeScript - * const keyInfo = await libp2p.keychain.importPeer('keyTestImport', peerIdFromString('12D3Foo...')) - * ``` - */ - importPeer(name: string, peerId: PeerId): Promise - - /** - * Export an existing key as a PeerId + * import { generateKeyPair } from '@libp2p/crypto/keys' * - * @example - * - * ```TypeScript - * const peerId = await libp2p.keychain.exportPeerId('key-name') + * const key = await generateKeyPair('Ed25519') + * const keyInfo = await libp2p.keychain.importKey('my-key', key) + * const keyInfo2 = await libp2p.keychain.findKeyById(keyInfo.id) * ``` */ - exportPeerId(name: string): Promise + findKeyById (id: string): Promise /** - * Create a key in the keychain. + * Import a new private key. * * @example * * ```TypeScript - * const keyInfo = await libp2p.keychain.createKey('keyTest', 'RSA', 4096) + * import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const key = await generateKeyPair('Ed25519') + * const keyInfo = await libp2p.keychain.importKey('my-key', key) * ``` */ - createKey(name: string, type: KeyType, size?: number): Promise + importKey(name: string, key: PrivateKey): Promise /** - * List all the keys. + * Export an existing private key. * * @example * * ```TypeScript - * const keyInfos = await libp2p.keychain.listKeys() + * import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const key = await generateKeyPair('Ed25519') + * const keyInfo = await libp2p.keychain.importKey('my-key', key) + * const key = await libp2p.keychain.exportKey(keyInfo.id) * ``` */ - listKeys(): Promise + exportKey(name: string): Promise /** * Removes a key from the keychain. @@ -168,7 +157,8 @@ export interface Keychain { removeKey(name: string): Promise /** - * Rename a key in the keychain. + * Rename a key in the keychain. This is done in a batch commit with rollback + * so errors thrown during the operation will not cause key loss. * * @example * @@ -180,28 +170,15 @@ export interface Keychain { renameKey(oldName: string, newName: string): Promise /** - * Find a key by it's id. - * - * @example - * - * ```TypeScript - * const keyInfo = await libp2p.keychain.createKey('keyTest', 'RSA', 4096) - * const keyInfo2 = await libp2p.keychain.findKeyById(keyInfo.id) - * ``` - */ - findKeyById(id: string): Promise - - /** - * Find a key by it's name. + * List all the keys. * * @example * * ```TypeScript - * const keyInfo = await libp2p.keychain.createKey('keyTest', 'RSA', 4096) - * const keyInfo2 = await libp2p.keychain.findKeyByName('keyTest') + * const keyInfos = await libp2p.keychain.listKeys() * ``` */ - findKeyByName(name: string): Promise + listKeys(): Promise /** * Rotate keychain password and re-encrypt all associated keys @@ -217,6 +194,6 @@ export interface Keychain { export function keychain (init: KeychainInit = {}): (components: KeychainComponents) => Keychain { return (components: KeychainComponents) => { - return new DefaultKeychain(components, init) + return new KeychainClass(components, init) } } diff --git a/packages/keychain/src/keychain.ts b/packages/keychain/src/keychain.ts index e3bef0b44d..25ac9732f3 100644 --- a/packages/keychain/src/keychain.ts +++ b/packages/keychain/src/keychain.ts @@ -1,16 +1,15 @@ /* eslint max-nested-callbacks: ["error", 5] */ import { pbkdf2, randomBytes } from '@libp2p/crypto' -import { generateKeyPair, importKey, unmarshalPrivateKey } from '@libp2p/crypto/keys' +import { importKey } from '@libp2p/crypto/keys' import { InvalidParametersError, NotFoundError, serviceCapabilities } from '@libp2p/interface' -import { peerIdFromKeys } from '@libp2p/peer-id' import { Key } from 'interface-datastore/key' import mergeOptions from 'merge-options' import sanitize from 'sanitize-filename' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' -import type { KeychainComponents, KeychainInit, Keychain, KeyInfo } from './index.js' -import type { Logger, KeyType, PeerId } from '@libp2p/interface' +import type { KeychainComponents, KeychainInit, Keychain as KeychainInterface, KeyInfo } from './index.js' +import type { Logger, PrivateKey } from '@libp2p/interface' const keyPrefix = '/pkcs8/' const infoPrefix = '/info/' @@ -79,7 +78,7 @@ function DsInfoName (name: string): Key { * - '/pkcs8/*key-name*', contains the PKCS #8 for the key * */ -export class DefaultKeychain implements Keychain { +export class Keychain implements KeychainInterface { private readonly components: KeychainComponents private readonly init: KeychainInit private readonly log: Logger @@ -146,151 +145,149 @@ export class DefaultKeychain implements Keychain { return defaultOptions } - /** - * Create a new key. - * - * @param {string} name - The local key name; cannot already exist. - * @param {string} type - One of the key types; 'rsa'. - * @param {number} [size = 2048] - The key size in bits. Used for rsa keys only - */ - async createKey (name: string, type: KeyType, size = 2048): Promise { - if (!validateKeyName(name) || name === 'self') { + async findKeyByName (name: string): Promise { + if (!validateKeyName(name)) { await randomDelay() - throw new InvalidParametersError('Invalid key name') + throw new InvalidParametersError(`Invalid key name '${name}'`) } - if (typeof type !== 'string') { - await randomDelay() - throw new InvalidParametersError('Invalid key type') - } + const dsname = DsInfoName(name) - const dsname = DsName(name) - const exists = await this.components.datastore.has(dsname) - if (exists) { + try { + const res = await this.components.datastore.get(dsname) + return JSON.parse(uint8ArrayToString(res)) + } catch (err: any) { await randomDelay() - throw new InvalidParametersError('Key name already exists') - } - - switch (type.toLowerCase()) { - case 'rsa': - if (!Number.isSafeInteger(size) || size < 2048) { - await randomDelay() - throw new InvalidParametersError('Invalid RSA key size') - } - break - default: - break + this.log.error(err) + throw new NotFoundError(`Key '${name}' does not exist.`) } + } - let keyInfo + async findKeyById (id: string): Promise { try { - const keypair = await generateKeyPair(type, size) - const kid = await keypair.id() - const cached = privates.get(this) - - if (cached == null) { - throw new InvalidParametersError('dek missing') + const query = { + prefix: infoPrefix } - const dek = cached.dek - const pem = await keypair.export(dek) - keyInfo = { - name, - id: kid + for await (const value of this.components.datastore.query(query)) { + const key = JSON.parse(uint8ArrayToString(value.value)) + + if (key.id === id) { + return key + } } - const batch = this.components.datastore.batch() - batch.put(dsname, uint8ArrayFromString(pem)) - batch.put(DsInfoName(name), uint8ArrayFromString(JSON.stringify(keyInfo))) - await batch.commit() + throw new InvalidParametersError(`Key with id '${id}' does not exist.`) } catch (err: any) { await randomDelay() throw err } - - return keyInfo } - /** - * List all the keys. - * - * @returns {Promise} - */ - async listKeys (): Promise { - const query = { - prefix: infoPrefix + async importKey (name: string, key: PrivateKey): Promise { + if (!validateKeyName(name) || name === 'self') { + await randomDelay() + throw new InvalidParametersError(`Invalid key name '${name}'`) } - - const info = [] - for await (const value of this.components.datastore.query(query)) { - info.push(JSON.parse(uint8ArrayToString(value.value))) + if (key == null) { + await randomDelay() + throw new InvalidParametersError('Key is required') + } + const dsname = DsName(name) + const exists = await this.components.datastore.has(dsname) + if (exists) { + await randomDelay() + throw new InvalidParametersError(`Key '${name}' already exists`) } - return info - } - - /** - * Find a key by it's id - */ - async findKeyById (id: string): Promise { + let kid: string + let pem: string try { - const keys = await this.listKeys() - const key = keys.find((k) => k.id === id) + kid = await key.id() + const cached = privates.get(this) - if (key == null) { - throw new InvalidParametersError(`Key with id '${id}' does not exist.`) + if (cached == null) { + throw new InvalidParametersError('dek missing') } - return key + const dek = cached.dek + pem = await key.export(dek) } catch (err: any) { await randomDelay() throw err } + + const keyInfo = { + name, + id: kid + } + const batch = this.components.datastore.batch() + batch.put(dsname, uint8ArrayFromString(pem)) + batch.put(DsInfoName(name), uint8ArrayFromString(JSON.stringify(keyInfo))) + await batch.commit() + + return keyInfo } - /** - * Find a key by it's name. - * - * @param {string} name - The local key name. - * @returns {Promise} - */ - async findKeyByName (name: string): Promise { + async exportKey (name: string): Promise { if (!validateKeyName(name)) { await randomDelay() throw new InvalidParametersError(`Invalid key name '${name}'`) } - const dsname = DsInfoName(name) + const dsname = DsName(name) try { const res = await this.components.datastore.get(dsname) - return JSON.parse(uint8ArrayToString(res)) + const pem = uint8ArrayToString(res) + const cached = privates.get(this) + + if (cached == null) { + throw new InvalidParametersError('dek missing') + } + + const dek = cached.dek + + return await importKey(pem, dek) } catch (err: any) { await randomDelay() - this.log.error(err) - throw new NotFoundError(`Key '${name}' does not exist.`) + throw err } } - /** - * Remove an existing key. - * - * @param {string} name - The local key name; must already exist. - * @returns {Promise} - */ async removeKey (name: string): Promise { if (!validateKeyName(name) || name === 'self') { await randomDelay() throw new InvalidParametersError(`Invalid key name '${name}'`) } + const dsname = DsName(name) const keyInfo = await this.findKeyByName(name) const batch = this.components.datastore.batch() batch.delete(dsname) batch.delete(DsInfoName(name)) await batch.commit() + return keyInfo } + /** + * List all the keys. + * + * @returns {Promise} + */ + async listKeys (): Promise { + const query = { + prefix: infoPrefix + } + + const info = [] + for await (const value of this.components.datastore.query(query)) { + info.push(JSON.parse(uint8ArrayToString(value.value))) + } + + return info + } + /** * Rename a key * @@ -337,178 +334,6 @@ export class DefaultKeychain implements Keychain { } } - /** - * Export an existing key as a PEM encrypted PKCS #8 string - */ - async exportKey (name: string, password: string): Promise { - if (!validateKeyName(name)) { - await randomDelay() - throw new InvalidParametersError(`Invalid key name '${name}'`) - } - if (password == null) { - await randomDelay() - throw new InvalidParametersError('Password is required') - } - - const dsname = DsName(name) - try { - const res = await this.components.datastore.get(dsname) - const pem = uint8ArrayToString(res) - const cached = privates.get(this) - - if (cached == null) { - throw new InvalidParametersError('dek missing') - } - - const dek = cached.dek - const privateKey = await importKey(pem, dek) - const keyString = await privateKey.export(password) - - return keyString - } catch (err: any) { - await randomDelay() - throw err - } - } - - /** - * Export an existing key as a PeerId - */ - async exportPeerId (name: string): Promise { - const password = 'temporary-password' - const pem = await this.exportKey(name, password) - const privateKey = await importKey(pem, password) - - return peerIdFromKeys(privateKey.public.bytes, privateKey.bytes) - } - - /** - * Import a new key from a PEM encoded PKCS #8 string - * - * @param {string} name - The local key name; must not already exist. - * @param {string} pem - The PEM encoded PKCS #8 string - * @param {string} password - The password. - * @returns {Promise} - */ - async importKey (name: string, pem: string, password: string): Promise { - if (!validateKeyName(name) || name === 'self') { - await randomDelay() - throw new InvalidParametersError(`Invalid key name '${name}'`) - } - if (pem == null) { - await randomDelay() - throw new InvalidParametersError('PEM encoded key is required') - } - const dsname = DsName(name) - const exists = await this.components.datastore.has(dsname) - if (exists) { - await randomDelay() - throw new InvalidParametersError(`Key '${name}' already exists`) - } - - let privateKey - try { - privateKey = await importKey(pem, password) - } catch (err: any) { - await randomDelay() - throw new InvalidParametersError('Cannot read the key, most likely the password is wrong') - } - - let kid - try { - kid = await privateKey.id() - const cached = privates.get(this) - - if (cached == null) { - throw new InvalidParametersError('dek missing') - } - - const dek = cached.dek - pem = await privateKey.export(dek) - } catch (err: any) { - await randomDelay() - throw err - } - - const keyInfo = { - name, - id: kid - } - const batch = this.components.datastore.batch() - batch.put(dsname, uint8ArrayFromString(pem)) - batch.put(DsInfoName(name), uint8ArrayFromString(JSON.stringify(keyInfo))) - await batch.commit() - - return keyInfo - } - - /** - * Import a peer key - */ - async importPeer (name: string, peer: PeerId): Promise { - try { - if (!validateKeyName(name)) { - throw new InvalidParametersError(`Invalid key name '${name}'`) - } - if (peer == null) { - throw new InvalidParametersError('PeerId is required') - } - if (peer.privateKey == null) { - throw new InvalidParametersError('PeerId.privKey is required') - } - - const privateKey = await unmarshalPrivateKey(peer.privateKey) - - const dsname = DsName(name) - const exists = await this.components.datastore.has(dsname) - if (exists) { - await randomDelay() - throw new InvalidParametersError(`Key '${name}' already exists`) - } - - const cached = privates.get(this) - - if (cached == null) { - throw new InvalidParametersError('dek missing') - } - - const dek = cached.dek - const pem = await privateKey.export(dek) - const keyInfo: KeyInfo = { - name, - id: peer.toString() - } - const batch = this.components.datastore.batch() - batch.put(dsname, uint8ArrayFromString(pem)) - batch.put(DsInfoName(name), uint8ArrayFromString(JSON.stringify(keyInfo))) - await batch.commit() - return keyInfo - } catch (err: any) { - await randomDelay() - throw err - } - } - - /** - * Gets the private key as PEM encoded PKCS #8 string - */ - async getPrivateKey (name: string): Promise { - if (!validateKeyName(name)) { - await randomDelay() - throw new InvalidParametersError(`Invalid key name '${name}'`) - } - - try { - const dsname = DsName(name) - const res = await this.components.datastore.get(dsname) - return uint8ArrayToString(res) - } catch (err: any) { - await randomDelay() - this.log.error(err) - throw new InvalidParametersError(`Key '${name}' does not exist.`) - } - } - /** * Rotate keychain password and re-encrypt all associated keys */ diff --git a/packages/keychain/src/util.ts b/packages/keychain/src/util.ts deleted file mode 100644 index e708fd1e03..0000000000 --- a/packages/keychain/src/util.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Finds the first item in a collection that is matched in the - * `asyncCompare` function. - * - * `asyncCompare` is an async function that must - * resolve to either `true` or `false`. - * - * @param {Array} array - * @param {function(*)} asyncCompare - An async function that returns a boolean - */ -export async function findAsync (array: T[], asyncCompare: (val: T) => Promise): Promise { - const promises = array.map(asyncCompare) - const results = await Promise.all(promises) - const index = results.findIndex(result => result) - return array[index] -} diff --git a/packages/keychain/test/keychain.spec.ts b/packages/keychain/test/keychain.spec.ts index 9bddb63705..e7975157fb 100644 --- a/packages/keychain/test/keychain.spec.ts +++ b/packages/keychain/test/keychain.spec.ts @@ -1,18 +1,15 @@ /* eslint max-nested-callbacks: ["error", 8] */ /* eslint-env mocha */ -import { pbkdf2 } from '@libp2p/crypto' -import { unmarshalPrivateKey } from '@libp2p/crypto/keys' +import { generateKeyPair, importKey } from '@libp2p/crypto/keys' import { defaultLogger } from '@libp2p/logger' -import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core/memory' import { Key } from 'interface-datastore/key' -import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' -import { DefaultKeychain } from '../src/keychain.js' +import { Keychain as KeychainClass } from '../src/keychain.js' import type { KeychainInit, Keychain, KeyInfo } from '../src/index.js' -import type { PeerId } from '@libp2p/interface' +import type { PrivateKey } from '@libp2p/interface' import type { Datastore } from 'interface-datastore' describe('keychain', () => { @@ -21,13 +18,13 @@ describe('keychain', () => { const renamedRsaKeyName = 'ชื่อลับ' const logger = defaultLogger() let rsaKeyInfo: KeyInfo - let ks: DefaultKeychain + let ks: Keychain let datastore2: Datastore before(async () => { datastore2 = new MemoryDatastore() - ks = new DefaultKeychain({ + ks = new KeychainClass({ datastore: datastore2, logger }, { pass: passPhrase }) @@ -35,7 +32,7 @@ describe('keychain', () => { it('can start without a password', async () => { await expect(async function () { - return new DefaultKeychain({ + return new KeychainClass({ datastore: datastore2, logger }, {}) @@ -44,7 +41,7 @@ describe('keychain', () => { it('needs a NIST SP 800-132 non-weak pass phrase', async () => { await expect(async function () { - return new DefaultKeychain({ + return new KeychainClass({ datastore: datastore2, logger }, { pass: '< 20 character' }) @@ -52,11 +49,11 @@ describe('keychain', () => { }) it('has default options', () => { - expect(DefaultKeychain.options).to.exist() + expect(KeychainClass.options).to.exist() }) it('supports supported hashing alorithms', async () => { - const ok = new DefaultKeychain({ + const ok = new KeychainClass({ datastore: datastore2, logger }, { pass: passPhrase, dek: { hash: 'sha2-256', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } }) @@ -65,7 +62,7 @@ describe('keychain', () => { it('does not support unsupported hashing alorithms', async () => { await expect(async function () { - return new DefaultKeychain({ + return new KeychainClass({ datastore: datastore2, logger }, { pass: passPhrase, dek: { hash: 'my-hash', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } }) @@ -73,7 +70,7 @@ describe('keychain', () => { }) it('can list keys without a password', async () => { - const keychain = new DefaultKeychain({ + const keychain = new KeychainClass({ datastore: datastore2, logger }, {}) @@ -82,52 +79,45 @@ describe('keychain', () => { }) it('can find a key without a password', async () => { - const keychain = new DefaultKeychain({ + const keychain = new KeychainClass({ datastore: datastore2, logger }, {}) - const keychainWithPassword = new DefaultKeychain({ + const keychainWithPassword = new KeychainClass({ datastore: datastore2, logger }, { pass: `hello-${Date.now()}-${Date.now()}` }) const name = `key-${Math.random()}` - const { id } = await keychainWithPassword.createKey(name, 'Ed25519') + const key = await generateKeyPair('Ed25519') + await keychainWithPassword.importKey(name, key) - await expect(keychain.findKeyById(id)).to.eventually.be.ok() + await expect(keychain.findKeyByName(name)).to.eventually.be.ok() }) it('can remove a key without a password', async () => { - const keychainWithoutPassword = new DefaultKeychain({ + const keychainWithoutPassword = new KeychainClass({ datastore: datastore2, logger }, {}) - const keychainWithPassword = new DefaultKeychain({ + const keychainWithPassword = new KeychainClass({ datastore: datastore2, logger }, { pass: `hello-${Date.now()}-${Date.now()}` }) const name = `key-${Math.random()}` - expect(await keychainWithPassword.createKey(name, 'Ed25519')).to.have.property('name', name) + const key = await generateKeyPair('Ed25519') + await keychainWithPassword.importKey(name, key) + expect(await keychainWithoutPassword.findKeyByName(name)).to.have.property('name', name) await keychainWithoutPassword.removeKey(name) await expect(keychainWithoutPassword.findKeyByName(name)).to.be.rejectedWith(/does not exist/) }) - it('requires a name to create a password', async () => { - const keychain = new DefaultKeychain({ - datastore: datastore2, - logger - }, {}) - - // @ts-expect-error invalid parameters - await expect(keychain.createKey(undefined, 'derp')).to.eventually.be.rejected() - }) - it('can generate options', async () => { - const options = DefaultKeychain.generateOptions() + const options = KeychainClass.generateOptions() options.pass = passPhrase - const chain = new DefaultKeychain({ + const chain = new KeychainClass({ datastore: datastore2, logger }, options) @@ -153,98 +143,52 @@ describe('keychain', () => { }) }) - describe('key', () => { - it('can be an RSA key', async () => { - rsaKeyInfo = await ks.createKey(rsaKeyName, 'RSA', 2048) - expect(rsaKeyInfo).to.exist() - expect(rsaKeyInfo).to.have.property('name', rsaKeyName) - expect(rsaKeyInfo).to.have.property('id') - }) - - it('is encrypted PEM encoded PKCS #8', async () => { - const pem = await ks.getPrivateKey(rsaKeyName) - return expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----') - }) - - it('throws if an invalid private key name is given', async () => { - // @ts-expect-error invalid parameters - await expect(ks.getPrivateKey(undefined)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('throws if a private key cant be found', async () => { - await expect(ks.getPrivateKey('not real')).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('does not overwrite existing key', async () => { - await expect(ks.createKey(rsaKeyName, 'RSA', 2048)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('cannot create the "self" key', async () => { - await expect(ks.createKey('self', 'RSA', 2048)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('should validate name is string', async () => { - // @ts-expect-error invalid parameters - await expect(ks.createKey(5, 'rsa', 2048)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('should validate type is string', async () => { - // @ts-expect-error invalid parameters - await expect(ks.createKey(`TEST-${Date.now()}`, null, 2048)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('should validate size is integer', async () => { - // @ts-expect-error invalid parameters - await expect(ks.createKey(`TEST-${Date.now()}`, 'RSA', 'string')).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - describe('implements NIST SP 800-131A', () => { - it('disallows RSA length < 2048', async () => { - await expect(ks.createKey('bad-nist-rsa', 'RSA', 1024)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - }) - }) - describe('Ed25519 keys', () => { const keyName = 'my custom key' + it('can be an Ed25519 key', async () => { - const keyInfo = await ks.createKey(keyName, 'Ed25519') + const key = await generateKeyPair('Ed25519') + const keyInfo = await ks.importKey(keyName, key) + expect(keyInfo).to.exist() expect(keyInfo).to.have.property('name', keyName) expect(keyInfo).to.have.property('id') }) it('does not overwrite existing key', async () => { - await expect(ks.createKey(keyName, 'Ed25519')).to.eventually.be.rejected + const key = await generateKeyPair('Ed25519') + + await expect(ks.importKey(keyName, key)).to.eventually.be.rejected .with.property('name', 'InvalidParametersError') }) it('can export/import a key', async () => { const keyName = 'a new key' - const password = 'my sneaky password' - const keyInfo = await ks.createKey(keyName, 'Ed25519') - const exportedKey = await ks.exportKey(keyName, password) - // remove it so we can import it + const key = await generateKeyPair('Ed25519') + const keyInfo = await ks.importKey(keyName, key) + const exportedKey = await ks.exportKey(keyName) + // remove it so we can re-import it await ks.removeKey(keyName) - const importedKey = await ks.importKey(keyName, exportedKey, password) + const importedKey = await ks.importKey(keyName, exportedKey) expect(importedKey.id).to.eql(keyInfo.id) }) it('cannot create the "self" key', async () => { - await expect(ks.createKey('self', 'Ed25519')).to.eventually.be.rejected + const key = await generateKeyPair('Ed25519') + + await expect(ks.importKey('self', key)).to.eventually.be.rejected .with.property('name', 'InvalidParametersError') }) }) describe('query', () => { + before(async () => { + const key = await generateKeyPair('RSA') + await ks.importKey(rsaKeyName, key) + + rsaKeyInfo = await ks.findKeyByName(rsaKeyName) + }) + it('finds all existing keys', async () => { const keys = await ks.listKeys() expect(keys).to.exist() @@ -275,13 +219,7 @@ describe('keychain', () => { }) describe('exported key', () => { - let pemKey: string - - it('requires the password', async () => { - // @ts-expect-error invalid parameters - await expect(ks.exportKey(rsaKeyName)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) + let key: PrivateKey it('requires the key name', async () => { // @ts-expect-error invalid parameters @@ -290,116 +228,31 @@ describe('keychain', () => { }) it('is a PKCS #8 encrypted pem', async () => { - pemKey = await ks.exportKey(rsaKeyName, 'password') - expect(pemKey).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----') + key = await ks.exportKey(rsaKeyName) + expect(key).to.be.ok() }) it('can be imported', async () => { - const key = await ks.importKey('imported-key', pemKey, 'password') - expect(key.name).to.equal('imported-key') - expect(key.id).to.equal(rsaKeyInfo.id) + const keyInfo = await ks.importKey('imported-key', key) + expect(keyInfo.name).to.equal('imported-key') + expect(keyInfo.id).to.equal(rsaKeyInfo.id) }) - it('requires the pem', async () => { + it('requires the key', async () => { // @ts-expect-error invalid parameters - await expect(ks.importKey('imported-key', undefined, 'password')).to.eventually.be.rejected + await expect(ks.importKey('imported-key', undefined)).to.eventually.be.rejected .with.property('name', 'InvalidParametersError') }) it('cannot be imported as an existing key name', async () => { - await expect(ks.importKey(rsaKeyName, pemKey, 'password')).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('cannot be imported with the wrong password', async () => { - await expect(ks.importKey('a-new-name-for-import', pemKey, 'not the password')).to.eventually.be.rejected + await expect(ks.importKey(rsaKeyName, key)).to.eventually.be.rejected .with.property('name', 'InvalidParametersError') }) }) - describe('peer id', () => { - const alicePrivKey = 'CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==' - let alice: PeerId - - before(async function () { - const encoded = uint8ArrayFromString(alicePrivKey, 'base64pad') - const privateKey = await unmarshalPrivateKey(encoded) - alice = await createFromPrivKey(privateKey) - }) - - it('private key can be imported', async () => { - const key = await ks.importPeer('alice', alice) - expect(key.name).to.equal('alice') - expect(key.id).to.equal(alice.toString()) - }) - - it('private key can be exported', async () => { - const alice2 = await ks.exportPeerId('alice') - - expect(alice.equals(alice2)).to.be.true() - expect(alice2).to.have.property('privateKey').that.is.ok() - expect(alice2).to.have.property('publicKey').that.is.ok() - }) - - it('private key import requires a valid name', async () => { - // @ts-expect-error invalid parameters - await expect(ks.importPeer(undefined, alice)).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('private key import requires the peer', async () => { - // @ts-expect-error invalid parameters - await expect(ks.importPeer('alice')).to.eventually.be.rejected - .with.property('name', 'InvalidParametersError') - }) - - it('key id exists', async () => { - const key = await ks.findKeyById(alice.toString()) - expect(key).to.exist() - expect(key).to.have.property('name', 'alice') - expect(key).to.have.property('id', alice.toString()) - }) - - it('key name exists', async () => { - const key = await ks.findKeyByName('alice') - expect(key).to.exist() - expect(key).to.have.property('name', 'alice') - expect(key).to.have.property('id', alice.toString()) - }) - - it('can create Ed25519 peer id', async () => { - const name = 'ed-key' - await ks.createKey(name, 'Ed25519') - const peer = await ks.exportPeerId(name) - - expect(peer).to.have.property('type', 'Ed25519') - expect(peer).to.have.property('privateKey').that.is.ok() - expect(peer).to.have.property('publicKey').that.is.ok() - }) - - it('can create RSA peer id', async () => { - const name = 'rsa-key' - await ks.createKey(name, 'RSA', 2048) - const peer = await ks.exportPeerId(name) - - expect(peer).to.have.property('type', 'RSA') - expect(peer).to.have.property('privateKey').that.is.ok() - expect(peer).to.have.property('publicKey').that.is.ok() - }) - - it('can create secp256k1 peer id', async () => { - const name = 'secp256k1-key' - await ks.createKey(name, 'secp256k1') - const peer = await ks.exportPeerId(name) - - expect(peer).to.have.property('type', 'secp256k1') - expect(peer).to.have.property('privateKey').that.is.ok() - expect(peer).to.have.property('publicKey').that.is.ok() - }) - }) - describe('rename', () => { it('requires an existing key name', async () => { + await ks.renameKey('not-there', renamedRsaKeyName) await expect(ks.renameKey('not-there', renamedRsaKeyName)).to.eventually.be.rejected .with.property('name', 'NotFoundError') }) @@ -484,7 +337,7 @@ describe('keychain', () => { hash: 'sha2-512' } } - kc = new DefaultKeychain({ + kc = new KeychainClass({ datastore: ds, logger }, options) @@ -509,7 +362,8 @@ describe('keychain', () => { }) it('can rotate keychain passphrase', async () => { - await kc.createKey('keyCreatedWithOldPassword', 'RSA', 2048) + const key = await generateKeyPair('Ed25519') + await kc.importKey('keyCreatedWithOldPassword', key) await kc.rotateKeychainPass(oldPass, 'newInsecurePassphrase') // Get Key PEM from datastore @@ -517,36 +371,18 @@ describe('keychain', () => { const res = await ds.get(dsname) const pem = uint8ArrayToString(res) - const oldDek = options.pass != null - ? pbkdf2( - options.pass, - options.dek?.salt ?? 'salt', - options.dek?.iterationCount ?? 0, - options.dek?.keyLength ?? 0, - options.dek?.hash ?? 'sha2-256' - ) - : '' - - const newDek = pbkdf2( - 'newInsecurePassphrase', - options.dek?.salt ?? 'salt', - options.dek?.iterationCount ?? 0, - options.dek?.keyLength ?? 0, - options.dek?.hash ?? 'sha2-256' - ) - // Dek with old password should not work: - await expect(kc.importKey('keyWhosePassChanged', pem, oldDek)) + await expect(importKey(pem, 'keyCreatedWithOldPassword')) .to.eventually.be.rejected() // Dek with new password should work: - await expect(kc.importKey('keyWhosePasswordChanged', pem, newDek)) - .to.eventually.have.property('name', 'keyWhosePasswordChanged') + await expect(importKey(pem, 'newInsecurePassphrase')) + .to.eventually.have.property('type', 'Ed25519') }).timeout(10000) }) it('needs a passphrase to be used, otherwise throws an error', async () => { expect(() => { - return new DefaultKeychain({ + return new KeychainClass({ datastore: new MemoryDatastore(), logger }, { @@ -556,38 +392,40 @@ describe('keychain', () => { }) it('can be used when a passphrase is provided', async () => { - const keychain = new DefaultKeychain({ + const keychain = new KeychainClass({ datastore: new MemoryDatastore(), logger }, { pass: '12345678901234567890' }) - const kInfo = await keychain.createKey('keyName', 'Ed25519') + const key = await generateKeyPair('Ed25519') + const kInfo = await keychain.importKey('keyName', key) expect(kInfo).to.exist() }) it('can reload keys', async () => { const datastore = new MemoryDatastore() - const keychain = new DefaultKeychain({ + const keychain = new KeychainClass({ datastore, logger }, { pass: '12345678901234567890' }) - const kInfo = await keychain.createKey('keyName', 'Ed25519') + const key = await generateKeyPair('Ed25519') + const kInfo = await keychain.importKey('keyName', key) expect(kInfo).to.exist() - const keychain2 = new DefaultKeychain({ + const keychain2 = new KeychainClass({ datastore, logger }, { pass: '12345678901234567890' }) - const key = await keychain2.findKeyByName('keyName') + const key2 = await keychain2.findKeyByName('keyName') - expect(key).to.exist() + expect(key2).to.exist() }) }) diff --git a/packages/keychain/test/peerid.spec.ts b/packages/keychain/test/peerid.spec.ts deleted file mode 100644 index d1520b5fff..0000000000 --- a/packages/keychain/test/peerid.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* eslint-env mocha */ - -import { supportedKeys, unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys' -import { createFromPrivKey } from '@libp2p/peer-id-factory' -import { expect } from 'aegir/chai' -import { base58btc } from 'multiformats/bases/base58' -import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import type { PeerId } from '@libp2p/interface' - -const sample = { - id: '122019318b6e5e0cf93a2314bf01269a2cc23cd3dcd452d742cdb9379d8646f6e4a9', - privKey: 'CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==', - pubKey: 'CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=' -} - -describe('peer ID', () => { - let peer: PeerId - let publicKeyDer: Uint8Array // a buffer - - before(async () => { - const encoded = uint8ArrayFromString(sample.privKey, 'base64pad') - peer = await createFromPrivKey(await unmarshalPrivateKey(encoded)) - }) - - it('decoded public key', async () => { - if (peer.publicKey == null) { - throw new Error('PublicKey missing from PeerId') - } - - if (peer.privateKey == null) { - throw new Error('PrivateKey missing from PeerId') - } - - // get protobuf version of the public key - const publicKeyProtobuf = peer.publicKey - const publicKey = unmarshalPublicKey(publicKeyProtobuf) - publicKeyDer = publicKey.marshal() - - // get protobuf version of the private key - const privateKeyProtobuf = peer.privateKey - const key = await unmarshalPrivateKey(privateKeyProtobuf) - expect(key).to.exist() - }) - - it('encoded public key with DER', async () => { - const rsa = supportedKeys.rsa.unmarshalRsaPublicKey(publicKeyDer) - const keyId = await rsa.hash() - const kids = base58btc.encode(keyId).substring(1) - expect(kids).to.equal(peer.toString()) - }) - - it('encoded public key with JWT', async () => { - const jwk = { - kty: 'RSA', - n: 'tkiqPxzBWXgZpdQBd14o868a30F3Sc43jwWQG3caikdTHOo7kR14o-h12D45QJNNQYRdUty5eC8ItHAB4YIH-Oe7DIOeVFsnhinlL9LnILwqQcJUeXENNtItDIM4z1ji1qta7b0mzXAItmRFZ-vkNhHB6N8FL1kbS3is_g2UmX8NjxAwvgxjyT5e3_IO85eemMpppsx_ZYmSza84P6onaJFL-btaXRq3KS7jzXkzg5NHKigfjlG7io_RkoWBAghI2smyQ5fdu-qGpS_YIQbUnhL9tJLoGrU72MufdMBZSZJL8pfpz8SB9BBGDCivV0VpbvV2J6En26IsHL_DN0pbIw', - e: 'AQAB', - alg: 'RS256', - kid: '2011-04-29' - } - const rsa = new supportedKeys.rsa.RsaPublicKey(jwk) - const keyId = await rsa.hash() - const kids = base58btc.encode(keyId).substring(1) - expect(kids).to.equal(peer.toString()) - }) - - it('decoded private key', async () => { - if (peer.privateKey == null) { - throw new Error('PrivateKey missing from PeerId') - } - - // get protobuf version of the private key - const privateKeyProtobuf = peer.privateKey - const key = await unmarshalPrivateKey(privateKeyProtobuf) - expect(key).to.exist() - }) -}) diff --git a/packages/libp2p/src/config.ts b/packages/libp2p/src/config.ts index a8d7619aa0..f90451bd7a 100644 --- a/packages/libp2p/src/config.ts +++ b/packages/libp2p/src/config.ts @@ -1,5 +1,4 @@ import { FaultTolerance, InvalidParametersError } from '@libp2p/interface' -import { peerIdFromKeys } from '@libp2p/peer-id' import { defaultAddressSort } from '@libp2p/utils/address-sort' import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' import mergeOptions from 'merge-options' @@ -25,16 +24,12 @@ const DefaultConfig: Libp2pInit = { } } -export async function validateConfig > (opts: Libp2pInit): Promise & Required, 'peerId'>>> { - const resultingOptions: Libp2pInit & Required, 'peerId'>> = mergeOptions(DefaultConfig, opts) +export async function validateConfig > (opts: Libp2pInit): Promise> { + const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, opts) if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) { // eslint-disable-line no-undef throw new InvalidParametersError('Private network is enforced, but no protector was provided') } - if (resultingOptions.privateKey != null && !(await peerIdFromKeys(resultingOptions.privateKey.public.bytes, resultingOptions.privateKey.bytes)).equals(resultingOptions.peerId)) { - throw new InvalidParametersError('Private key doesn\'t match peer id') - } - return resultingOptions } diff --git a/packages/libp2p/src/index.ts b/packages/libp2p/src/index.ts index 3defada121..a4834d412c 100644 --- a/packages/libp2p/src/index.ts +++ b/packages/libp2p/src/index.ts @@ -14,13 +14,16 @@ * ``` */ -import { createLibp2pNode } from './libp2p.js' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createFromPrivKey } from '@libp2p/peer-id-factory' +import { validateConfig } from './config.js' +import { Libp2p as Libp2pClass } from './libp2p.js' import type { AddressManagerInit } from './address-manager/index.js' import type { Components } from './components.js' import type { ConnectionManagerInit } from './connection-manager/index.js' import type { ConnectionMonitorInit } from './connection-monitor.js' import type { TransportManagerInit } from './transport-manager.js' -import type { Libp2p, ServiceMap, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionEncrypter, ConnectionGater, ContentRouting, Metrics, PeerDiscovery, PeerId, PeerRouting, StreamMuxerFactory, Transport, PrivateKey } from '@libp2p/interface' +import type { Libp2p, ServiceMap, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionEncrypter, ConnectionGater, ContentRouting, Metrics, PeerDiscovery, PeerRouting, StreamMuxerFactory, Transport, PrivateKey } from '@libp2p/interface' import type { PersistentPeerStoreInit } from '@libp2p/peer-store' import type { DNS } from '@multiformats/dns' import type { Datastore } from 'interface-datastore' @@ -34,12 +37,11 @@ export type ServiceFactoryMap = { */ export interface Libp2pInit { /** - * peerId instance (it will be created if not provided) - */ - peerId?: PeerId - - /** - * Private key associated with the peerId + * The private key is used in cryptographic operations and the Peer ID derived + * from it's corresponding public key is used to identify the node to other + * peers on the network. + * + * If this is not passed a new Ed25519 private key will be generated. */ privateKey?: PrivateKey @@ -86,13 +88,36 @@ export interface Libp2pInit { peerStore?: PersistentPeerStoreInit /** - * An array that must include at least 1 compliant transport + * Transports are low-level communication channels */ transports?: Array<(components: Components) => Transport> + + /** + * Stream muxers allow the creation of many data streams over a single + * connection. + */ streamMuxers?: Array<(components: Components) => StreamMuxerFactory> + + /** + * Connection encrypters ensure that data sent over connections cannot be + * eavesdropped on, and that the remote peer posesses the private key that + * corresponds to the public key that it's Peer ID is derived from. + */ connectionEncryption?: Array<(components: Components) => ConnectionEncrypter> + + /** + * Peer discovery mechanisms allow finding peers on the network + */ peerDiscovery?: Array<(components: Components) => PeerDiscovery> + + /** + * Peer routers provide implementations for peer routing queries + */ peerRouters?: Array<(components: Components) => PeerRouting> + + /** + * Content routers provide implementations for content routing queries + */ contentRouters?: Array<(components: Components) => ContentRouting> /** @@ -170,7 +195,12 @@ export type Libp2pOptions = Libp2pInit & { * ``` */ export async function createLibp2p (options: Libp2pOptions = {}): Promise> { - const node = await createLibp2pNode(options) + options.privateKey ??= await generateKeyPair('Ed25519') + + const node = new Libp2pClass({ + ...await validateConfig(options), + peerId: await createFromPrivKey(options.privateKey) + }) if (options.start !== false) { await node.start() diff --git a/packages/libp2p/src/libp2p.ts b/packages/libp2p/src/libp2p.ts index 11529fa87c..0a41aceee9 100644 --- a/packages/libp2p/src/libp2p.ts +++ b/packages/libp2p/src/libp2p.ts @@ -1,9 +1,8 @@ -import { unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys' -import { contentRoutingSymbol, TypedEventEmitter, setMaxListeners, peerDiscoverySymbol, peerRoutingSymbol, InvalidParametersError, InvalidPeerIdError } from '@libp2p/interface' +import { unmarshalPublicKey } from '@libp2p/crypto/keys' +import { contentRoutingSymbol, TypedEventEmitter, setMaxListeners, peerDiscoverySymbol, peerRoutingSymbol, InvalidParametersError } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' import { PeerSet } from '@libp2p/peer-collections' import { peerIdFromString } from '@libp2p/peer-id' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' import { isMultiaddr, type Multiaddr } from '@multiformats/multiaddr' import { MemoryDatastore } from 'datastore-core/memory' @@ -12,7 +11,6 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { DefaultAddressManager } from './address-manager/index.js' import { checkServiceDependencies, defaultComponents } from './components.js' import { connectionGater } from './config/connection-gater.js' -import { validateConfig } from './config.js' import { DefaultConnectionManager } from './connection-manager/index.js' import { ConnectionMonitor } from './connection-monitor.js' import { CompoundContentRouting } from './content-routing.js' @@ -23,11 +21,11 @@ import { DefaultTransportManager } from './transport-manager.js' import { DefaultUpgrader } from './upgrader.js' import * as pkg from './version.js' import type { Components } from './components.js' -import type { Libp2p, Libp2pInit, Libp2pOptions } from './index.js' +import type { Libp2p as Libp2pInterface, Libp2pInit } from './index.js' import type { PeerRouting, ContentRouting, Libp2pEvents, PendingDial, ServiceMap, AbortOptions, ComponentLogger, Logger, Connection, NewStreamOptions, Stream, Metrics, PeerId, PeerInfo, PeerStore, Topology, Libp2pStatus, IsDialableOptions, DialOptions } from '@libp2p/interface' import type { StreamHandler, StreamHandlerOptions } from '@libp2p/interface-internal' -export class Libp2pNode extends TypedEventEmitter implements Libp2p { +export class Libp2p extends TypedEventEmitter implements Libp2pInterface { public peerId: PeerId public peerStore: PeerStore public contentRouting: ContentRouting @@ -40,7 +38,7 @@ export class Libp2pNode extends TypedEventEmi public components: Components & T private readonly log: Logger - constructor (init: Libp2pInit & Required, 'peerId'>>) { + constructor (init: Libp2pInit & { peerId: PeerId }) { super() this.status = 'stopped' @@ -411,19 +409,3 @@ export class Libp2pNode extends TypedEventEmi .catch(err => { this.log.error(err) }) } } - -/** - * Returns a new Libp2pNode instance - this exposes more of the internals than the - * libp2p interface and is useful for testing and debugging. - */ -export async function createLibp2pNode (options: Libp2pOptions = {}): Promise> { - const peerId = options.peerId ??= await createEd25519PeerId() - - if (peerId.privateKey == null) { - throw new InvalidPeerIdError('Peer id was missing private key') - } - - options.privateKey ??= await unmarshalPrivateKey(peerId.privateKey) - - return new Libp2pNode(await validateConfig(options)) -} diff --git a/packages/libp2p/test/addresses/addresses.node.ts b/packages/libp2p/test/addresses/addresses.node.ts index e49bab1654..66581e093e 100644 --- a/packages/libp2p/test/addresses/addresses.node.ts +++ b/packages/libp2p/test/addresses/addresses.node.ts @@ -8,15 +8,16 @@ import { expect } from 'aegir/chai' import { pEvent } from 'p-event' import sinon from 'sinon' import { createNode } from '../fixtures/creators/peer.js' +import { getComponent } from '../fixtures/get-component.js' import { AddressesOptions } from './utils.js' -import type { Libp2pNode } from '../../src/libp2p.js' -import type { PeerUpdate } from '@libp2p/interface' +import type { Libp2p, PeerUpdate } from '@libp2p/interface' +import type { AddressManager, TransportManager } from '@libp2p/interface-internal' const listenAddresses = ['/ip4/127.0.0.1/tcp/0', '/ip4/127.0.0.1/tcp/8000/ws'] const announceAddresses = ['/dns4/peer.io/tcp/433/p2p/12D3KooWNvSZnPi3RrhrTwEY4LuuBeB6K6facKUCJcyWG1aoDd2p'] describe('libp2p.addressManager', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p afterEach(async () => { if (libp2p != null) { @@ -36,7 +37,8 @@ describe('libp2p.addressManager', () => { } }) - let listenAddrs = libp2p.components.addressManager.getListenAddrs().map(ma => ma.toString()) + const addressManager = getComponent(libp2p, 'addressManager') + let listenAddrs = addressManager.getListenAddrs().map(ma => ma.toString()) expect(listenAddrs).to.have.lengthOf(listenAddresses.length) expect(listenAddrs).to.include(listenAddresses[0]) expect(listenAddrs).to.include(listenAddresses[1]) @@ -45,7 +47,7 @@ describe('libp2p.addressManager', () => { // Only transportManager has visibility of the port used await libp2p.start() - listenAddrs = libp2p.components.addressManager.getListenAddrs().map(ma => ma.toString()) + listenAddrs = addressManager.getListenAddrs().map(ma => ma.toString()) expect(listenAddrs).to.have.lengthOf(listenAddresses.length) expect(listenAddrs).to.include(listenAddresses[0]) expect(listenAddrs).to.include(listenAddresses[1]) @@ -64,10 +66,10 @@ describe('libp2p.addressManager', () => { await libp2p.start() - const tmListen = libp2p.components.transportManager.getAddrs().map((ma) => ma.toString()) + const tmListen = getComponent(libp2p, 'transportManager').getAddrs().map((ma) => ma.toString()) // Announce 2 listen (transport) - const advertiseMultiaddrs = libp2p.components.addressManager.getAddresses().map((ma) => ma.decapsulateCode(protocols('p2p').code).toString()) + const advertiseMultiaddrs = getComponent(libp2p, 'addressManager').getAddresses().map((ma) => ma.decapsulateCode(protocols('p2p').code).toString()) expect(advertiseMultiaddrs).to.have.lengthOf(2) tmListen.forEach((m) => { @@ -90,10 +92,10 @@ describe('libp2p.addressManager', () => { await libp2p.start() - const tmListen = libp2p.components.transportManager.getAddrs().map((ma) => ma.toString()) + const tmListen = getComponent(libp2p, 'transportManager').getAddrs().map((ma) => ma.toString()) // Announce 1 announce addr - const advertiseMultiaddrs = libp2p.components.addressManager.getAddresses().map((ma) => ma.decapsulateCode(protocols('p2p').code).toString()) + const advertiseMultiaddrs = getComponent(libp2p, 'addressManager').getAddresses().map((ma) => ma.decapsulateCode(protocols('p2p').code).toString()) expect(advertiseMultiaddrs.length).to.equal(announceAddresses.length) advertiseMultiaddrs.forEach((m) => { expect(tmListen).to.not.include(m) @@ -115,16 +117,16 @@ describe('libp2p.addressManager', () => { await libp2p.start() - expect(libp2p.components.addressManager.getAddresses()).to.have.lengthOf(0) + expect(getComponent(libp2p, 'addressManager').getAddresses()).to.have.lengthOf(0) // Stub transportManager addresses to add a public address const stubMa = multiaddr('/ip4/120.220.10.1/tcp/1000') - sinon.stub(libp2p.components.transportManager, 'getAddrs').returns([ + sinon.stub(getComponent(libp2p, 'transportManager'), 'getAddrs').returns([ ...listenAddresses.map((a) => multiaddr(a)), stubMa ]) - const multiaddrs = libp2p.components.addressManager.getAddresses() + const multiaddrs = getComponent(libp2p, 'addressManager').getAddresses() expect(multiaddrs.length).to.equal(1) expect(multiaddrs[0].decapsulateCode(protocols('p2p').code).equals(stubMa)).to.eql(true) }) @@ -142,14 +144,14 @@ describe('libp2p.addressManager', () => { } }) - const listenAddrs = libp2p.components.addressManager.getListenAddrs().map((ma) => ma.toString()) + const listenAddrs = getComponent(libp2p, 'addressManager').getListenAddrs().map((ma) => ma.toString()) expect(listenAddrs).to.have.lengthOf(listenAddresses.length) expect(listenAddrs).to.include(listenAddresses[0]) expect(listenAddrs).to.include(listenAddresses[1]) await libp2p.start() - const loopbackAddrs = libp2p.components.addressManager.getAddresses().filter(ma => isLoopback(ma)) + const loopbackAddrs = getComponent(libp2p, 'addressManager').getAddresses().filter(ma => isLoopback(ma)) expect(loopbackAddrs).to.be.empty() }) @@ -167,12 +169,14 @@ describe('libp2p.addressManager', () => { await libp2p.start() - expect(libp2p.components.addressManager.getAddresses()).to.have.lengthOf(listenAddresses.length) + const addressManager = getComponent(libp2p, 'addressManager') - libp2p.components.addressManager.confirmObservedAddr(multiaddr(ma)) + expect(addressManager.getAddresses()).to.have.lengthOf(listenAddresses.length) - expect(libp2p.components.addressManager.getAddresses()).to.have.lengthOf(listenAddresses.length + 1) - expect(libp2p.components.addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code).toString())).to.include(ma) + addressManager.confirmObservedAddr(multiaddr(ma)) + + expect(addressManager.getAddresses()).to.have.lengthOf(listenAddresses.length + 1) + expect(addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code).toString())).to.include(ma) }) it('should populate the AddressManager from the config', async () => { @@ -250,10 +254,10 @@ describe('libp2p.addressManager', () => { const eventPromise = pEvent<'self:peer:update', CustomEvent>(libp2p, 'self:peer:update') const unconfirmedAddress = multiaddr('/ip4/127.0.0.1/tcp/4010/ws') - libp2p.components.addressManager.addObservedAddr(unconfirmedAddress) + getComponent(libp2p, 'addressManager').addObservedAddr(unconfirmedAddress) const confirmedAddress = multiaddr('/ip4/127.0.0.1/tcp/4011/ws') - libp2p.components.addressManager.confirmObservedAddr(confirmedAddress) + getComponent(libp2p, 'addressManager').confirmObservedAddr(confirmedAddress) const event = await eventPromise diff --git a/packages/libp2p/test/connection-manager/direct.node.ts b/packages/libp2p/test/connection-manager/direct.node.ts index a71fe105d2..c1d7b1956a 100644 --- a/packages/libp2p/test/connection-manager/direct.node.ts +++ b/packages/libp2p/test/connection-manager/direct.node.ts @@ -4,8 +4,7 @@ import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { yamux } from '@chainsafe/libp2p-yamux' -import { type Connection, type ConnectionProtector, isConnection, type PeerId, type Stream, type Libp2p } from '@libp2p/interface' -import { AbortError, TypedEventEmitter, start, stop } from '@libp2p/interface' +import { isConnection, AbortError, TypedEventEmitter, start, stop } from '@libp2p/interface' import { mockConnection, mockConnectionGater, mockDuplex, mockMultiaddrConnection, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' import { mplex } from '@libp2p/mplex' @@ -30,10 +29,10 @@ import { defaultComponents, type Components } from '../../src/components.js' import { DialQueue } from '../../src/connection-manager/dial-queue.js' import { DefaultConnectionManager } from '../../src/connection-manager/index.js' import { createLibp2p } from '../../src/index.js' -import { createLibp2pNode } from '../../src/libp2p.js' import { DefaultPeerRouting } from '../../src/peer-routing.js' import { DefaultTransportManager } from '../../src/transport-manager.js' import { ECHO_PROTOCOL, echo } from '../fixtures/echo-service.js' +import type { Connection, ConnectionProtector, Stream, Libp2p } from '@libp2p/interface' import type { TransportManager } from '@libp2p/interface-internal' import type { Multiaddr } from '@multiformats/multiaddr' @@ -278,20 +277,12 @@ describe('dialing (direct, TCP)', () => { }) describe('libp2p.dialer (direct, TCP)', () => { - let peerId: PeerId - let remotePeerId: PeerId let libp2p: Libp2p let remoteLibp2p: Libp2p let remoteAddr: Multiaddr beforeEach(async () => { - [peerId, remotePeerId] = await Promise.all([ - createEd25519PeerId(), - createEd25519PeerId() - ]) - remoteLibp2p = await createLibp2p({ - peerId: remotePeerId, addresses: { listen: [listenAddr.toString()] }, @@ -327,8 +318,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should use the dialer for connecting to a peer', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -343,11 +333,11 @@ describe('libp2p.dialer (direct, TCP)', () => { await libp2p.start() - await libp2p.peerStore.patch(remotePeerId, { + await libp2p.peerStore.patch(remoteLibp2p.peerId, { multiaddrs: remoteLibp2p.getMultiaddrs() }) - const connection = await libp2p.dial(remotePeerId) + const connection = await libp2p.dial(remoteLibp2p.peerId) expect(connection).to.exist() const stream = await connection.newStream(ECHO_PROTOCOL) expect(stream).to.exist() @@ -356,8 +346,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should close all streams when the connection closes', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -420,8 +409,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should throw when using dialProtocol with no protocols', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -447,8 +435,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should be able to use hangup to close connections', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -477,8 +464,7 @@ describe('libp2p.dialer (direct, TCP)', () => { } } - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -506,8 +492,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should coalesce parallel dials to the same peer (id in multiaddr)', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -526,7 +511,7 @@ describe('libp2p.dialer (direct, TCP)', () => { // PeerId should be in multiaddr expect(remoteAddr.getPeerId()).to.equal(remoteLibp2p.peerId.toString()) - await libp2p.peerStore.patch(remotePeerId, { + await libp2p.peerStore.patch(remoteLibp2p.peerId, { multiaddrs: remoteLibp2p.getMultiaddrs() }) const dialResults = await Promise.all([...new Array(dials)].map(async (_, index) => { @@ -546,8 +531,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should coalesce parallel dials to the same error on failure', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -567,7 +551,7 @@ describe('libp2p.dialer (direct, TCP)', () => { // @ts-expect-error private field access Sinon.stub(libp2p.components.transportManager, 'dial').callsFake(async () => Promise.reject(error)) - await libp2p.peerStore.patch(remotePeerId, { + await libp2p.peerStore.patch(remoteLibp2p.peerId, { multiaddrs: remoteLibp2p.getMultiaddrs() }) const dialResults = await Promise.allSettled([...new Array(dials)].map(async (_, index) => { @@ -601,8 +585,7 @@ describe('libp2p.dialer (direct, TCP)', () => { const unixAddr = path.join(os.tmpdir(), `test-${Math.random()}.sock`) const unixMultiaddr = multiaddr('/unix' + unixAddr) - remoteLibp2p = await createLibp2pNode({ - peerId: remotePeerId, + remoteLibp2p = await createLibp2p({ addresses: { listen: [ unixMultiaddr.toString() @@ -624,8 +607,7 @@ describe('libp2p.dialer (direct, TCP)', () => { expect(fs.existsSync(unixAddr)).to.be.true() - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -642,11 +624,11 @@ describe('libp2p.dialer (direct, TCP)', () => { const connection = await libp2p.dial(unixMultiaddr) - expect(connection.remotePeer.toString()).to.equal(remotePeerId.toString()) + expect(connection.remotePeer.toString()).to.equal(remoteLibp2p.peerId.toString()) }) it('should negotiate protocol fully when dialing a protocol', async () => { - remoteLibp2p = await createLibp2pNode({ + remoteLibp2p = await createLibp2p({ addresses: { listen: [ '/ip4/0.0.0.0/tcp/0' @@ -663,8 +645,7 @@ describe('libp2p.dialer (direct, TCP)', () => { ] }) - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], @@ -696,7 +677,7 @@ describe('libp2p.dialer (direct, TCP)', () => { }) it('should negotiate protocol fully when opening on a connection', async () => { - remoteLibp2p = await createLibp2pNode({ + remoteLibp2p = await createLibp2p({ addresses: { listen: [ '/ip4/0.0.0.0/tcp/0' @@ -713,8 +694,7 @@ describe('libp2p.dialer (direct, TCP)', () => { ] }) - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ tcp() ], diff --git a/packages/libp2p/test/connection-manager/direct.spec.ts b/packages/libp2p/test/connection-manager/direct.spec.ts index a02ece928d..0ae3a6c000 100644 --- a/packages/libp2p/test/connection-manager/direct.spec.ts +++ b/packages/libp2p/test/connection-manager/direct.spec.ts @@ -26,7 +26,7 @@ import { LAST_DIAL_FAILURE_KEY } from '../../src/connection-manager/constants.js import { DefaultConnectionManager } from '../../src/connection-manager/index.js' import { createLibp2p } from '../../src/index.js' import { DefaultTransportManager } from '../../src/transport-manager.js' -import type { Libp2p, Connection, PeerId, Transport } from '@libp2p/interface' +import type { Libp2p, Connection, Transport } from '@libp2p/interface' import type { TransportManager } from '@libp2p/interface-internal' import type { Multiaddr } from '@multiformats/multiaddr' @@ -326,11 +326,6 @@ describe('dialing (direct, WebSockets)', () => { describe('libp2p.dialer (direct, WebSockets)', () => { let libp2p: Libp2p<{ identify: Identify }> - let peerId: PeerId - - beforeEach(async () => { - peerId = await createEd25519PeerId() - }) afterEach(async () => { sinon.restore() @@ -342,7 +337,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { it('should run identify automatically after connecting', async () => { libp2p = await createLibp2p({ - peerId, transports: [ webSockets({ filter: filters.all @@ -387,7 +381,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { it('should not run identify automatically after connecting', async () => { libp2p = await createLibp2p({ - peerId, transports: [ webSockets({ filter: filters.all @@ -429,7 +422,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { it('should be able to use hangup to close connections', async () => { libp2p = await createLibp2p({ - peerId, transports: [ webSockets({ filter: filters.all @@ -459,7 +451,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { it('should be able to use hangup when no connection exists', async () => { libp2p = await createLibp2p({ - peerId, transports: [ webSockets({ filter: filters.all @@ -480,7 +471,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { it('should fail to dial self', async () => { libp2p = await createLibp2p({ - peerId, transports: [ webSockets({ filter: filters.all @@ -498,7 +488,7 @@ describe('libp2p.dialer (direct, WebSockets)', () => { await libp2p.start() - await expect(libp2p.dial(multiaddr(`/ip4/127.0.0.1/tcp/1234/ws/p2p/${peerId.toString()}`))) + await expect(libp2p.dial(multiaddr(`/ip4/127.0.0.1/tcp/1234/ws/p2p/${libp2p.peerId.toString()}`))) .to.eventually.be.rejected() .and.to.have.property('name', 'DialError') }) @@ -513,7 +503,6 @@ describe('libp2p.dialer (direct, WebSockets)', () => { }) libp2p = await createLibp2p({ - peerId, transports: [ () => transport ], diff --git a/packages/libp2p/test/connection-manager/index.node.ts b/packages/libp2p/test/connection-manager/index.node.ts index e4cdc1746b..2e6e876c1c 100644 --- a/packages/libp2p/test/connection-manager/index.node.ts +++ b/packages/libp2p/test/connection-manager/index.node.ts @@ -16,7 +16,6 @@ import { createBaseOptions } from '../fixtures/base-options.browser.js' import { createNode } from '../fixtures/creators/peer.js' import { ECHO_PROTOCOL, echo } from '../fixtures/echo-service.js' import type { Libp2p } from '../../src/index.js' -import type { Libp2pNode } from '../../src/libp2p.js' import type { ConnectionGater, PeerId, PeerStore } from '@libp2p/interface' import type { TransportManager } from '@libp2p/interface-internal' @@ -34,7 +33,6 @@ describe('Connection Manager', () => { beforeEach(async () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] } @@ -115,16 +113,8 @@ describe('Connection Manager', () => { }) describe('libp2p.connections', () => { - let peerIds: PeerId[] let libp2p: Libp2p - before(async () => { - peerIds = await Promise.all([ - createEd25519PeerId(), - createEd25519PeerId() - ]) - }) - afterEach(async () => { if (libp2p != null) { await libp2p.stop() @@ -134,7 +124,6 @@ describe('libp2p.connections', () => { it('libp2p.connections gets the connectionManager conns', async () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/15003/ws'] } @@ -142,7 +131,6 @@ describe('libp2p.connections', () => { }) const remoteLibp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[1], addresses: { listen: ['/ip4/127.0.0.1/tcp/15004/ws'] } @@ -162,7 +150,7 @@ describe('libp2p.connections', () => { }) describe('proactive connections', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p let nodes: Libp2p[] = [] beforeEach(async () => { @@ -197,7 +185,6 @@ describe('libp2p.connections', () => { it('should be closed status once immediately stopping', async () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/15003/ws'] } @@ -205,7 +192,6 @@ describe('libp2p.connections', () => { }) const remoteLibp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[1], addresses: { listen: ['/ip4/127.0.0.1/tcp/15004/ws'] } @@ -217,7 +203,7 @@ describe('libp2p.connections', () => { }) await libp2p.dial(remoteLibp2p.peerId) - const conns = libp2p.components.connectionManager.getConnections() + const conns = libp2p.getConnections() expect(conns.length).to.eql(1) const conn = conns[0] @@ -237,20 +223,18 @@ describe('libp2p.connections', () => { }) // connect once, should have one connection - await libp2p.components.connectionManager.openConnection(nodes[0].getMultiaddrs()) - expect(libp2p.components.connectionManager.getConnections()).to.have.lengthOf(1) + await libp2p.dial(nodes[0].getMultiaddrs()) + expect(libp2p.getConnections()).to.have.lengthOf(1) // connect twice, should still only have one connection - await libp2p.components.connectionManager.openConnection(nodes[0].getMultiaddrs(), { - force: false - }) - expect(libp2p.components.connectionManager.getConnections()).to.have.lengthOf(1) + await libp2p.dial(nodes[0].getMultiaddrs()) + expect(libp2p.getConnections()).to.have.lengthOf(1) // force connection, should have two connections now - await libp2p.components.connectionManager.openConnection(nodes[0].getMultiaddrs(), { + await libp2p.dial(nodes[0].getMultiaddrs(), { force: true }) - expect(libp2p.components.connectionManager.getConnections()).to.have.lengthOf(2) + expect(libp2p.getConnections()).to.have.lengthOf(2) }) it('should use custom DNS resolver', async () => { @@ -285,7 +269,6 @@ describe('libp2p.connections', () => { beforeEach(async () => { remoteLibp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[1], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -311,7 +294,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -333,7 +315,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -357,7 +338,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -385,7 +365,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -407,7 +386,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -429,7 +407,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -452,7 +429,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -475,7 +451,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, @@ -505,7 +480,6 @@ describe('libp2p.connections', () => { libp2p = await createNode({ config: createBaseOptions({ - peerId: peerIds[0], addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, diff --git a/packages/libp2p/test/connection-manager/index.spec.ts b/packages/libp2p/test/connection-manager/index.spec.ts index 9b52ee8a74..61eec621da 100644 --- a/packages/libp2p/test/connection-manager/index.spec.ts +++ b/packages/libp2p/test/connection-manager/index.spec.ts @@ -13,8 +13,8 @@ import { stubInterface } from 'sinon-ts' import { DefaultConnectionManager, type DefaultConnectionManagerComponents } from '../../src/connection-manager/index.js' import { createBaseOptions } from '../fixtures/base-options.browser.js' import { createNode } from '../fixtures/creators/peer.js' -import type { Libp2pNode } from '../../src/libp2p.js' -import type { AbortOptions, Connection, ConnectionGater, PeerId, PeerRouting, PeerStore } from '@libp2p/interface' +import { getComponent } from '../fixtures/get-component.js' +import type { AbortOptions, Connection, ConnectionGater, Libp2p, PeerId, PeerRouting, PeerStore } from '@libp2p/interface' import type { TransportManager } from '@libp2p/interface-internal' const defaultOptions = { @@ -35,7 +35,7 @@ function defaultComponents (peerId: PeerId): DefaultConnectionManagerComponents } describe('Connection Manager', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p let connectionManager: DefaultConnectionManager afterEach(async () => { @@ -56,7 +56,7 @@ describe('Connection Manager', () => { started: false }) - const spy = sinon.spy(libp2p.components.connectionManager as DefaultConnectionManager, 'start') + const spy = sinon.spy(getComponent(libp2p, 'connectionManager'), 'start') await libp2p.start() expect(spy).to.have.property('callCount', 1) @@ -71,7 +71,7 @@ describe('Connection Manager', () => { started: false }) - const spy = sinon.spy(libp2p.components.connectionManager as DefaultConnectionManager, 'start') + const spy = sinon.spy(getComponent(libp2p, 'connectionManager'), 'start') await libp2p.start() expect(spy).to.have.property('callCount', 1) @@ -91,7 +91,7 @@ describe('Connection Manager', () => { await libp2p.start() - const connectionManager = libp2p.components.connectionManager as DefaultConnectionManager + const connectionManager = getComponent(libp2p, 'connectionManager') const connectionManagerMaybePruneConnectionsSpy = sinon.spy(connectionManager.connectionPruner, 'maybePruneConnections') const spies = new Map>>() @@ -113,7 +113,7 @@ describe('Connection Manager', () => { } }) - libp2p.components.events.safeDispatchEvent('connection:open', { detail: connection }) + getComponent(libp2p, 'events').safeDispatchEvent('connection:open', { detail: connection }) } await eventPromise @@ -149,7 +149,7 @@ describe('Connection Manager', () => { await libp2p.start() - const connectionManager = libp2p.components.connectionManager as DefaultConnectionManager + const connectionManager = getComponent(libp2p, 'connectionManager') const connectionManagerMaybePruneConnectionsSpy = sinon.spy(connectionManager.connectionPruner, 'maybePruneConnections') const spies = new Map>>() const eventPromise = pEvent(libp2p, 'connection:prune') @@ -169,7 +169,7 @@ describe('Connection Manager', () => { } }) - libp2p.components.events.safeDispatchEvent('connection:open', { detail: connection }) + getComponent(libp2p, 'events').safeDispatchEvent('connection:open', { detail: connection }) } // Create one short of enough connections to initiate pruning @@ -216,7 +216,7 @@ describe('Connection Manager', () => { await libp2p.start() - const connectionManager = libp2p.components.connectionManager as DefaultConnectionManager + const connectionManager = getComponent(libp2p, 'connectionManager') const connectionManagerMaybePruneConnectionsSpy = sinon.spy(connectionManager.connectionPruner, 'maybePruneConnections') const spies = new Map>>() const eventPromise = pEvent(libp2p, 'connection:prune') @@ -234,7 +234,7 @@ describe('Connection Manager', () => { } } }) - libp2p.components.events.safeDispatchEvent('connection:open', { detail: connection }) + getComponent(libp2p, 'events').safeDispatchEvent('connection:open', { detail: connection }) } // an outbound connection is opened from an address in the allow list @@ -260,7 +260,7 @@ describe('Connection Manager', () => { } }) - libp2p.components.events.safeDispatchEvent('connection:open', { detail: connection }) + getComponent(libp2p, 'events').safeDispatchEvent('connection:open', { detail: connection }) // wait for prune event await eventPromise @@ -297,7 +297,7 @@ describe('Connection Manager', () => { await libp2p.start() - const connectionManager = libp2p.components.connectionManager as DefaultConnectionManager + const connectionManager = getComponent(libp2p, 'connectionManager') const connectionManagerMaybePruneConnectionsSpy = sinon.spy(connectionManager.connectionPruner, 'maybePruneConnections') const eventPromise = pEvent(libp2p, 'connection:prune') @@ -306,7 +306,7 @@ describe('Connection Manager', () => { for (let i = 0; i < max + 1; i++) { const connection = mockConnection(mockMultiaddrConnection(mockDuplex(), await createEd25519PeerId())) sinon.stub(connection, 'close').callsFake(async () => spy()) // eslint-disable-line - libp2p.components.events.safeDispatchEvent('connection:open', { detail: connection }) + getComponent(libp2p, 'events').safeDispatchEvent('connection:open', { detail: connection }) } // wait for prune event @@ -336,7 +336,7 @@ describe('Connection Manager', () => { started: false }) - const connectionManager = libp2p.components.connectionManager as DefaultConnectionManager + const connectionManager = getComponent(libp2p, 'connectionManager') const connectionManagerOpenConnectionSpy = sinon.spy(connectionManager, 'openConnection') await libp2p.start() diff --git a/packages/libp2p/test/connection-manager/resolver.spec.ts b/packages/libp2p/test/connection-manager/resolver.spec.ts index 13f514c73f..ebe47d0e1f 100644 --- a/packages/libp2p/test/connection-manager/resolver.spec.ts +++ b/packages/libp2p/test/connection-manager/resolver.spec.ts @@ -15,8 +15,8 @@ import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import pDefer from 'p-defer' import sinon from 'sinon' -import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' -import type { PeerId, Transport } from '@libp2p/interface' +import { createLibp2p } from '../../src/index.js' +import type { Libp2p, PeerId, Transport } from '@libp2p/interface' import type { Multiaddr } from '@multiformats/multiaddr' const relayAddr = multiaddr(process.env.RELAY_MULTIADDR) @@ -28,15 +28,15 @@ const getDnsRelayedAddrStub = (peerId: PeerId): string[] => [ ] describe('dialing (resolvable addresses)', () => { - let libp2p: Libp2pNode - let remoteLibp2p: Libp2pNode<{ relay: CircuitRelayService }> + let libp2p: Libp2p + let remoteLibp2p: Libp2p<{ relay: CircuitRelayService }> let resolver: sinon.SinonStub<[Multiaddr], Promise> beforeEach(async () => { resolver = sinon.stub<[Multiaddr], Promise>(); [libp2p, remoteLibp2p] = await Promise.all([ - createLibp2pNode({ + createLibp2p({ addresses: { listen: [`${relayAddr.toString()}/p2p-circuit`] }, @@ -63,7 +63,7 @@ describe('dialing (resolvable addresses)', () => { identify: identify() } }), - createLibp2pNode({ + createLibp2p({ addresses: { listen: [`${relayAddr.toString()}/p2p-circuit`] }, @@ -178,8 +178,8 @@ describe('dialing (resolvable addresses)', () => { }) }) -function getTransport (libp2p: Libp2pNode, tag: string): Transport { - const transport = libp2p.components.transportManager.getTransports().find(t => { +function getTransport (libp2p: any, tag: string): Transport { + const transport = libp2p.components.transportManager.getTransports().find((t: any) => { return t[Symbol.toStringTag] === tag }) diff --git a/packages/libp2p/test/connection/compliance.spec.ts b/packages/libp2p/test/connection/compliance.spec.ts index 94a9df75c8..7158c7c5f7 100644 --- a/packages/libp2p/test/connection/compliance.spec.ts +++ b/packages/libp2p/test/connection/compliance.spec.ts @@ -1,5 +1,4 @@ import tests from '@libp2p/interface-compliance-tests/connection' -import peers from '@libp2p/interface-compliance-tests/peers' import { logger, peerLogger } from '@libp2p/logger' import * as PeerIdFactory from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' @@ -16,7 +15,7 @@ describe('connection compliance', () => { async setup (properties) { const localPeer = await PeerIdFactory.createEd25519PeerId() const remoteAddr = multiaddr('/ip4/127.0.0.1/tcp/8081') - const remotePeer = await PeerIdFactory.createFromJSON(peers[0]) + const remotePeer = await PeerIdFactory.createEd25519PeerId() let openStreams: Stream[] = [] let streamId = 0 diff --git a/packages/libp2p/test/core/consume-peer-record.spec.ts b/packages/libp2p/test/core/consume-peer-record.spec.ts index 020d8f49d8..d47728d3c6 100644 --- a/packages/libp2p/test/core/consume-peer-record.spec.ts +++ b/packages/libp2p/test/core/consume-peer-record.spec.ts @@ -1,18 +1,16 @@ /* eslint-env mocha */ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '@libp2p/plaintext' import { webSockets } from '@libp2p/websockets' import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' +import { createLibp2p } from '../../src/index.js' +import type { Libp2p } from '@libp2p/interface' describe('Consume peer record', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p beforeEach(async () => { - const peerId = await createEd25519PeerId() - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ transports: [ webSockets() ], @@ -40,6 +38,7 @@ describe('Consume peer record', () => { await libp2p.start() + // @ts-expect-error components field is private libp2p.components.addressManager.confirmObservedAddr(multiaddr('/ip4/123.123.123.123/tcp/3983')) await p diff --git a/packages/libp2p/test/core/encryption.spec.ts b/packages/libp2p/test/core/encryption.spec.ts index bccb147878..63bfdef688 100644 --- a/packages/libp2p/test/core/encryption.spec.ts +++ b/packages/libp2p/test/core/encryption.spec.ts @@ -1,21 +1,12 @@ /* eslint-env mocha */ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '@libp2p/plaintext' import { webSockets } from '@libp2p/websockets' import { createLibp2p, type Libp2pOptions } from '../../src/index.js' -import type { PeerId } from '@libp2p/interface' describe('Connection encryption configuration', () => { - let peerId: PeerId - - before(async () => { - peerId = await createEd25519PeerId() - }) - it('can be created', async () => { const config: Libp2pOptions = { - peerId, start: false, transports: [ webSockets() diff --git a/packages/libp2p/test/core/listening.node.ts b/packages/libp2p/test/core/listening.node.ts index f5538b1e95..df6e164096 100644 --- a/packages/libp2p/test/core/listening.node.ts +++ b/packages/libp2p/test/core/listening.node.ts @@ -1,29 +1,22 @@ /* eslint-env mocha */ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { expect } from 'aegir/chai' -import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' -import type { PeerId } from '@libp2p/interface' +import { createLibp2p } from '../../src/index.js' +import type { Libp2p } from '@libp2p/interface' const listenAddr = '/ip4/0.0.0.0/tcp/0' describe('Listening', () => { - let peerId: PeerId - let libp2p: Libp2pNode - - before(async () => { - peerId = await createEd25519PeerId() - }) + let libp2p: Libp2p after(async () => { await libp2p.stop() }) it('should replace wildcard host and port with actual host and port on startup', async () => { - libp2p = await createLibp2pNode({ - peerId, + libp2p = await createLibp2p({ addresses: { listen: [listenAddr] }, @@ -37,6 +30,7 @@ describe('Listening', () => { await libp2p.start() + // @ts-expect-error components field is private const addrs = libp2p.components.transportManager.getAddrs() // Should get something like: diff --git a/packages/libp2p/test/core/status.node.ts b/packages/libp2p/test/core/status.node.ts index 3b9a9cdf0c..8155ae11cd 100644 --- a/packages/libp2p/test/core/status.node.ts +++ b/packages/libp2p/test/core/status.node.ts @@ -3,19 +3,20 @@ import { plaintext } from '@libp2p/plaintext' import { tcp } from '@libp2p/tcp' import { expect } from 'aegir/chai' -import { createLibp2pNode, type Libp2pNode } from '../../src/libp2p.js' +import { createLibp2p } from '../../src/index.js' +import type { Libp2p } from '@libp2p/interface' const listenAddr = '/ip4/0.0.0.0/tcp/0' describe('status', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p after(async () => { await libp2p.stop() }) it('should have status', async () => { - libp2p = await createLibp2pNode({ + libp2p = await createLibp2p({ start: false, addresses: { listen: [listenAddr] diff --git a/packages/libp2p/test/fixtures/creators/peer.ts b/packages/libp2p/test/fixtures/creators/peer.ts index cb158c45fa..aef41f5083 100644 --- a/packages/libp2p/test/fixtures/creators/peer.ts +++ b/packages/libp2p/test/fixtures/creators/peer.ts @@ -1,10 +1,9 @@ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2pNode, type Libp2pNode } from '../../../src/libp2p.js' +import { createLibp2p } from '../../../src/index.js' import { createBaseOptions } from '../base-options.browser.js' import type { AddressManagerInit } from '../../../src/address-manager/index.js' import type { Libp2pOptions } from '../../../src/index.js' -import type { ServiceMap } from '@libp2p/interface' +import type { Libp2p, ServiceMap } from '@libp2p/interface' const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') @@ -25,10 +24,9 @@ export interface CreatePeerOptions { /** * Create libp2p nodes. */ -export async function createNode (options: CreatePeerOptions = {}): Promise> { +export async function createNode (options: CreatePeerOptions = {}): Promise> { const started = options.started ?? true const config = options.config ?? {} - const peerId = await createEd25519PeerId() const addresses: AddressManagerInit = started ? { listen: [listenAddr.toString()], @@ -42,8 +40,7 @@ export async function createNode (options: CreatePeerOpti noAnnounce: [], announceFilter: (addrs) => addrs } - const peer = await createLibp2pNode(createBaseOptions({ - peerId, + const peer = await createLibp2p(createBaseOptions({ addresses, start: started, ...config diff --git a/packages/libp2p/test/fixtures/get-component.ts b/packages/libp2p/test/fixtures/get-component.ts new file mode 100644 index 0000000000..efc03a5883 --- /dev/null +++ b/packages/libp2p/test/fixtures/get-component.ts @@ -0,0 +1,3 @@ +export function getComponent (libp2p: any, name: string): T { + return libp2p.components[name] +} diff --git a/packages/libp2p/test/peer-discovery/peer-discovery.spec.ts b/packages/libp2p/test/peer-discovery/peer-discovery.spec.ts index a9977e4130..847cc96f3a 100644 --- a/packages/libp2p/test/peer-discovery/peer-discovery.spec.ts +++ b/packages/libp2p/test/peer-discovery/peer-discovery.spec.ts @@ -1,22 +1,16 @@ /* eslint-env mocha */ import { TypedEventEmitter } from '@libp2p/interface' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import sinon from 'sinon' import { stubInterface } from 'sinon-ts' import { createLibp2p } from '../../src/index.js' -import type { PeerDiscovery, PeerDiscoveryEvents, PeerId, Startable, Libp2p } from '@libp2p/interface' +import type { PeerDiscovery, PeerDiscoveryEvents, Startable, Libp2p } from '@libp2p/interface' describe('peer discovery', () => { - let peerId: PeerId let libp2p: Libp2p - before(async () => { - peerId = await createEd25519PeerId() - }) - afterEach(async () => { if (libp2p != null) { await libp2p.stop() @@ -29,7 +23,6 @@ describe('peer discovery', () => { const discovery = stubInterface() libp2p = await createLibp2p({ - peerId, peerDiscovery: [ () => discovery ] diff --git a/packages/libp2p/test/registrar/protocols.spec.ts b/packages/libp2p/test/registrar/protocols.spec.ts index d1ba4ef0d9..9239ed3797 100644 --- a/packages/libp2p/test/registrar/protocols.spec.ts +++ b/packages/libp2p/test/registrar/protocols.spec.ts @@ -2,12 +2,11 @@ import { yamux } from '@chainsafe/libp2p-yamux' import { mplex } from '@libp2p/mplex' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { plaintext } from '@libp2p/plaintext' import { webSockets } from '@libp2p/websockets' import { expect } from 'aegir/chai' import pDefer from 'p-defer' -import { createLibp2pNode } from '../../src/libp2p.js' +import { createLibp2p } from '../../src/index.js' import type { Components } from '../../src/components.js' import type { Libp2p } from '@libp2p/interface' @@ -17,8 +16,7 @@ describe('registrar protocols', () => { it('should be able to register and unregister a handler', async () => { const deferred = pDefer() - libp2p = await createLibp2pNode({ - peerId: await createEd25519PeerId(), + libp2p = await createLibp2p({ transports: [ webSockets() ], diff --git a/packages/libp2p/test/transports/transport-manager.spec.ts b/packages/libp2p/test/transports/transport-manager.spec.ts index ac6679bc70..1cce9bd4b2 100644 --- a/packages/libp2p/test/transports/transport-manager.spec.ts +++ b/packages/libp2p/test/transports/transport-manager.spec.ts @@ -14,7 +14,7 @@ import { DefaultAddressManager } from '../../src/address-manager/index.js' import { createLibp2p } from '../../src/index.js' import { DefaultTransportManager } from '../../src/transport-manager.js' import type { Components } from '../../src/components.js' -import type { Libp2p, PeerId } from '@libp2p/interface' +import type { Libp2p } from '@libp2p/interface' const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') @@ -108,13 +108,8 @@ describe('Transport Manager (WebSockets)', () => { }) describe('libp2p.transportManager (dial only)', () => { - let peerId: PeerId let libp2p: Libp2p - before(async () => { - peerId = await createEd25519PeerId() - }) - afterEach(async () => { sinon.restore() @@ -125,7 +120,6 @@ describe('libp2p.transportManager (dial only)', () => { it('fails to start if multiaddr fails to listen', async () => { libp2p = await createLibp2p({ - peerId, addresses: { listen: ['/ip4/127.0.0.1/tcp/0'] }, @@ -140,7 +134,6 @@ describe('libp2p.transportManager (dial only)', () => { it('does not fail to start if provided listen multiaddr are not compatible to configured transports (when supporting dial only mode)', async () => { libp2p = await createLibp2p({ - peerId, addresses: { listen: ['/ip4/127.0.0.1/tcp/0'] }, @@ -161,7 +154,6 @@ describe('libp2p.transportManager (dial only)', () => { it('does not fail to start if provided listen multiaddr fail to listen on configured transports (when supporting dial only mode)', async () => { libp2p = await createLibp2p({ - peerId, addresses: { listen: ['/ip4/127.0.0.1/tcp/12345/p2p/QmWDn2LY8nannvSWJzruUYoLZ4vV83vfCBwd8DipvdgQc3/p2p-circuit'] }, diff --git a/packages/libp2p/test/upgrading/upgrader.spec.ts b/packages/libp2p/test/upgrading/upgrader.spec.ts index 8e71d835bb..9c0f349b95 100644 --- a/packages/libp2p/test/upgrading/upgrader.spec.ts +++ b/packages/libp2p/test/upgrading/upgrader.spec.ts @@ -2,11 +2,12 @@ import { yamux } from '@chainsafe/libp2p-yamux' import { circuitRelayTransport } from '@libp2p/circuit-relay-v2' +import { generateKeyPair } from '@libp2p/crypto/keys' import { identify } from '@libp2p/identify' import { TypedEventEmitter } from '@libp2p/interface' import { mockConnectionGater, mockConnectionManager, mockMultiaddrConnPair, mockRegistrar, mockStream, mockMuxer } from '@libp2p/interface-compliance-tests/mocks' import { mplex } from '@libp2p/mplex' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' import { plaintext } from '@libp2p/plaintext' import { webSockets } from '@libp2p/websockets' @@ -28,7 +29,7 @@ import { type Components, defaultComponents } from '../../src/components.js' import { createLibp2p } from '../../src/index.js' import { DEFAULT_MAX_OUTBOUND_STREAMS } from '../../src/registrar.js' import { DefaultUpgrader } from '../../src/upgrader.js' -import type { Libp2p, Connection, ConnectionProtector, Stream, ConnectionEncrypter, SecuredConnection, PeerId, StreamMuxer, StreamMuxerFactory, StreamMuxerInit, Upgrader } from '@libp2p/interface' +import type { Libp2p, Connection, ConnectionProtector, Stream, ConnectionEncrypter, SecuredConnection, PeerId, StreamMuxer, StreamMuxerFactory, StreamMuxerInit, Upgrader, PrivateKey } from '@libp2p/interface' const addrs = [ multiaddr('/ip4/127.0.0.1/tcp/0'), @@ -595,14 +596,14 @@ describe('Upgrader', () => { }) describe('libp2p.upgrader', () => { - let peers: PeerId[] + let peers: PrivateKey[] let libp2p: Libp2p let remoteLibp2p: Libp2p before(async () => { peers = await Promise.all([ - createEd25519PeerId(), - createEd25519PeerId() + generateKeyPair('Ed25519'), + generateKeyPair('Ed25519') ]) }) @@ -628,7 +629,7 @@ describe('libp2p.upgrader', () => { } libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], transports: [ webSockets() ], @@ -659,7 +660,7 @@ describe('libp2p.upgrader', () => { const remotePeer = peers[1] libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], transports: [ webSockets() ], @@ -680,7 +681,7 @@ describe('libp2p.upgrader', () => { await libp2p.handle(['/echo/1.0.0'], echoHandler) remoteLibp2p = await createLibp2p({ - peerId: remotePeer, + privateKey: remotePeer, transports: [ webSockets() ], @@ -702,7 +703,7 @@ describe('libp2p.upgrader', () => { const localComponents = await localDeferred.promise const remoteComponents = await remoteDeferred.promise - const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer }) + const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer: await createFromPrivKey(remotePeer) }) const [localConnection] = await Promise.all([ localComponents.upgrader.upgradeOutbound(outbound), remoteComponents.upgrader.upgradeInbound(inbound) @@ -719,7 +720,7 @@ describe('libp2p.upgrader', () => { it('should emit connect and disconnect events', async () => { const remotePeer = peers[1] libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], addresses: { listen: [ `${process.env.RELAY_MULTIADDR}/p2p-circuit` @@ -746,7 +747,7 @@ describe('libp2p.upgrader', () => { await libp2p.start() remoteLibp2p = await createLibp2p({ - peerId: remotePeer, + privateKey: remotePeer, transports: [ webSockets({ filter: filters.all @@ -800,7 +801,7 @@ describe('libp2p.upgrader', () => { const protocol = '/a-test-protocol/1.0.0' const remotePeer = peers[1] libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], transports: [ webSockets() ], @@ -819,7 +820,7 @@ describe('libp2p.upgrader', () => { }) remoteLibp2p = await createLibp2p({ - peerId: remotePeer, + privateKey: remotePeer, transports: [ webSockets() ], @@ -837,7 +838,7 @@ describe('libp2p.upgrader', () => { connectionGater: mockConnectionGater() }) - const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer }) + const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer: await createFromPrivKey(remotePeer) }) const localComponents = await localDeferred.promise const remoteComponents = await remoteDeferred.promise @@ -879,7 +880,7 @@ describe('libp2p.upgrader', () => { const protocol = '/a-test-protocol/1.0.0' const remotePeer = peers[1] libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], transports: [ webSockets() ], @@ -898,7 +899,7 @@ describe('libp2p.upgrader', () => { }) remoteLibp2p = await createLibp2p({ - peerId: remotePeer, + privateKey: remotePeer, transports: [ webSockets() ], @@ -915,7 +916,7 @@ describe('libp2p.upgrader', () => { } }) - const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer }) + const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer: await createFromPrivKey(remotePeer) }) const localComponents = await localDeferred.promise const remoteComponents = await remoteDeferred.promise @@ -955,7 +956,7 @@ describe('libp2p.upgrader', () => { const protocol = '/a-test-protocol/1.0.0' const remotePeer = peers[1] libp2p = await createLibp2p({ - peerId: peers[0], + privateKey: peers[0], transports: [ webSockets() ], @@ -974,7 +975,7 @@ describe('libp2p.upgrader', () => { }) remoteLibp2p = await createLibp2p({ - peerId: remotePeer, + privateKey: remotePeer, transports: [ webSockets() ], @@ -991,7 +992,7 @@ describe('libp2p.upgrader', () => { } }) - const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer }) + const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer: await createFromPrivKey(remotePeer) }) const localComponents = await localDeferred.promise const remoteComponents = await remoteDeferred.promise diff --git a/packages/peer-id-factory/package.json b/packages/peer-id-factory/package.json index 36615fe3c6..fe88f1a1de 100644 --- a/packages/peer-id-factory/package.json +++ b/packages/peer-id-factory/package.json @@ -62,13 +62,13 @@ "@libp2p/interface": "^1.7.0", "@libp2p/peer-id": "^4.2.4", "protons-runtime": "^5.4.0", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" + "uint8arraylist": "^2.4.8" }, "devDependencies": { "aegir": "^44.0.1", "multiformats": "^13.1.0", - "protons": "^7.5.0" + "protons": "^7.5.0", + "uint8arrays": "^5.1.0" }, "sideEffects": false } diff --git a/packages/peer-id-factory/src/index.ts b/packages/peer-id-factory/src/index.ts index 1d3ae475bf..c23dcbd877 100644 --- a/packages/peer-id-factory/src/index.ts +++ b/packages/peer-id-factory/src/index.ts @@ -22,10 +22,10 @@ */ import { generateKeyPair, marshalPrivateKey, unmarshalPrivateKey, marshalPublicKey, unmarshalPublicKey } from '@libp2p/crypto/keys' +import { InvalidParametersError } from '@libp2p/interface' import { peerIdFromKeys, peerIdFromBytes } from '@libp2p/peer-id' -import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { PeerIdProto } from './proto.js' -import type { PublicKey, PrivateKey, RSAPeerId, Ed25519PeerId, Secp256k1PeerId, KeyType } from '@libp2p/interface' +import type { PublicKey, PrivateKey, RSAPeerId, Ed25519PeerId, Secp256k1PeerId, KeyType, PeerId } from '@libp2p/interface' export const createEd25519PeerId = async (): Promise => { const key = await generateKeyPair('Ed25519') @@ -49,6 +49,9 @@ export const createSecp256k1PeerId = async (): Promise => { throw new Error(`Generated unexpected PeerId type "${id.type}"`) } +/** + * @deprecated Please use Ed25519 or secp256k1 keys instead + */ export const createRSAPeerId = async (opts?: { bits: number }): Promise => { const key = await generateKeyPair('RSA', opts?.bits ?? 2048) const id = await createFromPrivKey(key) @@ -64,15 +67,19 @@ export async function createFromPubKey (publicKey: PublicKe return peerIdFromKeys(marshalPublicKey(publicKey)) } +export async function createFromPrivKey (privateKey: PrivateKey<'Ed25519'>): Promise +export async function createFromPrivKey (privateKey: PrivateKey<'RSA'>): Promise +export async function createFromPrivKey (privateKey: PrivateKey<'secp256k1'>): Promise +export async function createFromPrivKey (privateKey: PrivateKey): Promise export async function createFromPrivKey (privateKey: PrivateKey): Promise { return peerIdFromKeys(marshalPublicKey(privateKey.public), marshalPrivateKey(privateKey)) } -export function exportToProtobuf (peerId: RSAPeerId | Ed25519PeerId | Secp256k1PeerId, excludePrivateKey?: boolean): Uint8Array { +export function exportToProtobuf (peerId: PeerId, privateKey?: PrivateKey): Uint8Array { return PeerIdProto.encode({ id: peerId.multihash.bytes, pubKey: peerId.publicKey, - privKey: excludePrivateKey === true || peerId.privateKey == null ? undefined : peerId.privateKey + privKey: privateKey?.bytes }) } @@ -90,14 +97,6 @@ export async function createFromProtobuf (buf: Uint8Array): Promise { - return createFromParts( - uint8ArrayFromString(obj.id, 'base58btc'), - obj.privKey != null ? uint8ArrayFromString(obj.privKey, 'base64pad') : undefined, - obj.pubKey != null ? uint8ArrayFromString(obj.pubKey, 'base64pad') : undefined - ) -} - async function createFromParts (multihash: Uint8Array, privKey?: Uint8Array, pubKey?: Uint8Array): Promise { if (privKey != null) { const key = await unmarshalPrivateKey(privKey) @@ -114,7 +113,7 @@ async function createFromParts (multihash: Uint8Array, privKey?: Uint8Array, pub if (peerId.type !== 'Ed25519' && peerId.type !== 'secp256k1' && peerId.type !== 'RSA') { // should not be possible since `multihash` is derived from keys and these // are the cryptographic peer id types - throw new Error('Supplied PeerID is invalid') + throw new InvalidParametersError('Supplied PeerID is invalid') } return peerId diff --git a/packages/peer-id-factory/test/index.spec.ts b/packages/peer-id-factory/test/index.spec.ts index aa32dd2574..feb667a833 100644 --- a/packages/peer-id-factory/test/index.spec.ts +++ b/packages/peer-id-factory/test/index.spec.ts @@ -14,7 +14,6 @@ import { identity } from 'multiformats/hashes/identity' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import * as PeerIdFactory from '../src/index.js' -import goId from './fixtures/go-private-key.js' import testId from './fixtures/sample-id.js' const LIBP2P_KEY_CODE = 0x72 @@ -126,7 +125,9 @@ describe('PeerId', () => { }) it('recreate from a Private Key', async () => { - const id = await PeerIdFactory.createFromPrivKey(await keys.unmarshalPrivateKey(uint8ArrayFromString(testId.privKey, 'base64pad'))) + const buf = uint8ArrayFromString(testId.privKey, 'base64pad') + const privateKey = await keys.unmarshalPrivateKey(buf) + const id = await PeerIdFactory.createFromPrivKey(privateKey) expect(testIdB58String).to.equal(id.toString()) const encoded = await keys.unmarshalPrivateKey(uint8ArrayFromString(testId.privKey, 'base64pad')) @@ -185,7 +186,7 @@ describe('PeerId', () => { }) it('can be created from a secp256k1 public key', async () => { - const privKey = await keys.generateKeyPair('secp256k1', 256) + const privKey = await keys.generateKeyPair('secp256k1') const id = await PeerIdFactory.createFromPubKey(privKey.public) if (id.publicKey == null) { @@ -197,7 +198,7 @@ describe('PeerId', () => { }) it('can be created from a Secp256k1 private key', async () => { - const privKey = await keys.generateKeyPair('secp256k1', 256) + const privKey = await keys.generateKeyPair('secp256k1') const id = await PeerIdFactory.createFromPrivKey(privKey) if (id.publicKey == null) { @@ -220,17 +221,6 @@ describe('PeerId', () => { expect(id.toString().length).to.equal(52) }) - it('Non-default # of bits', async function () { - const shortId = await PeerIdFactory.createRSAPeerId({ bits: 512 }) - const longId = await PeerIdFactory.createRSAPeerId({ bits: 1024 }) - - if (longId.privateKey == null) { - throw new Error('No private key found on peer id') - } - - expect(shortId.privateKey).to.have.property('length').that.is.lessThan(longId.privateKey.length) - }) - it('equals', async () => { const ids = await Promise.all([ PeerIdFactory.createEd25519PeerId(), @@ -243,39 +233,6 @@ describe('PeerId', () => { expect(ids[0].equals(ids[1].multihash.bytes)).to.equal(false) }) - describe('fromJSON', () => { - it('full node', async () => { - const id = await PeerIdFactory.createEd25519PeerId() - const other = await PeerIdFactory.createFromJSON({ - id: id.toString(), - privKey: id.privateKey != null ? uint8ArrayToString(id.privateKey, 'base64pad') : undefined, - pubKey: uint8ArrayToString(id.publicKey, 'base64pad') - }) - expect(id.toString()).to.equal(other.toString()) - expect(id.privateKey).to.equalBytes(other.privateKey) - expect(id.publicKey).to.equalBytes(other.publicKey) - }) - - it('only id', async () => { - const key = await keys.generateKeyPair('RSA', 1024) - const digest = await key.public.hash() - const id = peerIdFromBytes(digest) - expect(id.privateKey).to.not.exist() - expect(id.publicKey).to.not.exist() - const other = await PeerIdFactory.createFromJSON({ - id: id.toString(), - privKey: id.privateKey != null ? uint8ArrayToString(id.privateKey, 'base64pad') : undefined, - pubKey: id.publicKey != null ? uint8ArrayToString(id.publicKey, 'base64pad') : undefined - }) - expect(id.toString()).to.equal(other.toString()) - }) - - it('go interop', async () => { - const id = await PeerIdFactory.createFromJSON(goId) - expect(id.toString()).to.eql(goId.id) - }) - }) - it('keys are equal after one is stringified', async () => { const peerId = await PeerIdFactory.createEd25519PeerId() const peerId1 = peerIdFromString(peerId.toString()) @@ -295,7 +252,7 @@ describe('PeerId', () => { uint8ArrayFromString(''), 'aGVsbG93b3JsZA==', 'helloworld', '' ] - const fncs = ['createFromPubKey', 'createFromPrivKey', 'createFromJSON', 'createFromProtobuf'] + const fncs = ['createFromPubKey', 'createFromPrivKey', 'createFromProtobuf'] for (const gb of garbage) { for (const fn of fncs) { diff --git a/packages/peer-id/src/index.ts b/packages/peer-id/src/index.ts index 8e73c44e20..3f389ac11b 100644 --- a/packages/peer-id/src/index.ts +++ b/packages/peer-id/src/index.ts @@ -189,8 +189,7 @@ const TRANSPORT_IPFS_GATEWAY_HTTP_CODE = 0x0920 class URLPeerIdImpl implements URLPeerId { readonly type = 'url' readonly multihash: MultihashDigest - readonly privateKey?: Uint8Array - readonly publicKey?: Uint8Array + readonly publicKey: undefined readonly url: string constructor (url: URL) { @@ -229,7 +228,7 @@ class URLPeerIdImpl implements URLPeerId { } } -export function createPeerId (init: PeerIdInit): Ed25519PeerId | Secp256k1PeerId | RSAPeerId { +export function createPeerId (init: PeerIdInit): PeerId { if (init.type === 'RSA') { return new RSAPeerIdImpl(init) } @@ -245,7 +244,7 @@ export function createPeerId (init: PeerIdInit): Ed25519PeerId | Secp256k1PeerId throw new InvalidParametersError('Type must be "RSA", "Ed25519" or "secp256k1"') } -export function peerIdFromPeerId (other: any): Ed25519PeerId | Secp256k1PeerId | RSAPeerId { +export function peerIdFromPeerId (other: any): PeerId { if (other.type === 'RSA') { return new RSAPeerIdImpl(other) } @@ -261,7 +260,7 @@ export function peerIdFromPeerId (other: any): Ed25519PeerId | Secp256k1PeerId | throw new InvalidParametersError('Not a PeerId') } -export function peerIdFromString (str: string, decoder?: MultibaseDecoder): Ed25519PeerId | Secp256k1PeerId | RSAPeerId | URLPeerId { +export function peerIdFromString (str: string, decoder?: MultibaseDecoder): PeerId { decoder = decoder ?? baseDecoder if (str.charAt(0) === '1' || str.charAt(0) === 'Q') { @@ -281,7 +280,7 @@ export function peerIdFromString (str: string, decoder?: MultibaseDecoder): return peerIdFromBytes(baseDecoder.decode(str)) } -export function peerIdFromBytes (buf: Uint8Array): Ed25519PeerId | Secp256k1PeerId | RSAPeerId | URLPeerId { +export function peerIdFromBytes (buf: Uint8Array): PeerId { try { const multihash = Digest.decode(buf) diff --git a/packages/peer-record/README.md b/packages/peer-record/README.md index f9a447af66..60af694bb8 100644 --- a/packages/peer-record/README.md +++ b/packages/peer-record/README.md @@ -40,16 +40,18 @@ Create an envelope with an instance of an [interface-record](https://github.com/ ```TypeScript import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createFromPrivKey } from '@libp2p/peer-id-factory' -const peerId = await createEd25519PeerId() +const privateKey = await generateKeyPair('Ed25519') +const peerId = await createFromPrivKey(privateKey) const record = new PeerRecord({ peerId, // ...other data }) -const envelope = await RecordEnvelope.seal(record, peerId) +const envelope = await RecordEnvelope.seal(record, privateKey) const wireData = envelope.marshal() ``` diff --git a/packages/peer-record/src/envelope/index.ts b/packages/peer-record/src/envelope/index.ts index 4bc29e4ef0..d5e98681ff 100644 --- a/packages/peer-record/src/envelope/index.ts +++ b/packages/peer-record/src/envelope/index.ts @@ -1,15 +1,14 @@ -import { unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys' -import { peerIdFromKeys } from '@libp2p/peer-id' +import { unmarshalPublicKey } from '@libp2p/crypto/keys' import * as varint from 'uint8-varint' import { Uint8ArrayList } from 'uint8arraylist' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import { fromString as uint8arraysFromString } from 'uint8arrays/from-string' import { Envelope as Protobuf } from './envelope.js' import { InvalidSignatureError } from './errors.js' -import type { PeerId, Record, Envelope } from '@libp2p/interface' +import type { Record, Envelope, PrivateKey, PublicKey } from '@libp2p/interface' export interface RecordEnvelopeInit { - peerId: PeerId + publicKey: PublicKey payloadType: Uint8Array payload: Uint8Array signature: Uint8Array @@ -21,10 +20,10 @@ export class RecordEnvelope implements Envelope { */ static createFromProtobuf = async (data: Uint8Array | Uint8ArrayList): Promise => { const envelopeData = Protobuf.decode(data) - const peerId = await peerIdFromKeys(envelopeData.publicKey) + const publicKey = unmarshalPublicKey(envelopeData.publicKey) return new RecordEnvelope({ - peerId, + publicKey, payloadType: envelopeData.payloadType, payload: envelopeData.payload, signature: envelopeData.signature @@ -35,8 +34,8 @@ export class RecordEnvelope implements Envelope { * Seal marshals the given Record, places the marshaled bytes inside an Envelope * and signs it with the given peerId's private key */ - static seal = async (record: Record, peerId: PeerId): Promise => { - if (peerId.privateKey == null) { + static seal = async (record: Record, privateKey: PrivateKey): Promise => { + if (privateKey == null) { throw new Error('Missing private key') } @@ -44,11 +43,10 @@ export class RecordEnvelope implements Envelope { const payloadType = record.codec const payload = record.marshal() const signData = formatSignaturePayload(domain, payloadType, payload) - const key = await unmarshalPrivateKey(peerId.privateKey) - const signature = await key.sign(signData.subarray()) + const signature = await privateKey.sign(signData.subarray()) return new RecordEnvelope({ - peerId, + publicKey: privateKey.public, payloadType, payload, signature @@ -70,7 +68,7 @@ export class RecordEnvelope implements Envelope { return envelope } - public peerId: PeerId + public publicKey: PublicKey public payloadType: Uint8Array public payload: Uint8Array public signature: Uint8Array @@ -81,9 +79,9 @@ export class RecordEnvelope implements Envelope { * by a libp2p peer. */ constructor (init: RecordEnvelopeInit) { - const { peerId, payloadType, payload, signature } = init + const { publicKey, payloadType, payload, signature } = init - this.peerId = peerId + this.publicKey = publicKey this.payloadType = payloadType this.payload = payload this.signature = signature @@ -93,13 +91,9 @@ export class RecordEnvelope implements Envelope { * Marshal the envelope content */ marshal (): Uint8Array { - if (this.peerId.publicKey == null) { - throw new Error('Missing public key') - } - if (this.marshaled == null) { this.marshaled = Protobuf.encode({ - publicKey: this.peerId.publicKey, + publicKey: this.publicKey.marshal(), payloadType: this.payloadType, payload: this.payload.subarray(), signature: this.signature @@ -122,13 +116,7 @@ export class RecordEnvelope implements Envelope { async validate (domain: string): Promise { const signData = formatSignaturePayload(domain, this.payloadType, this.payload) - if (this.peerId.publicKey == null) { - throw new Error('Missing public key') - } - - const key = unmarshalPublicKey(this.peerId.publicKey) - - return key.verify(signData.subarray(), this.signature) + return this.publicKey.verify(signData.subarray(), this.signature) } } diff --git a/packages/peer-record/src/index.ts b/packages/peer-record/src/index.ts index 624c535108..963c4b9d72 100644 --- a/packages/peer-record/src/index.ts +++ b/packages/peer-record/src/index.ts @@ -17,16 +17,18 @@ * * ```TypeScript * import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' - * import { createEd25519PeerId } from '@libp2p/peer-id-factory' + * import { generateKeyPair } from '@libp2p/crypto/keys' + * import { createFromPrivKey } from '@libp2p/peer-id-factory' * - * const peerId = await createEd25519PeerId() + * const privateKey = await generateKeyPair('Ed25519') + * const peerId = await createFromPrivKey(privateKey) * * const record = new PeerRecord({ - * peerId, + * peerId, * // ...other data * }) * - * const envelope = await RecordEnvelope.seal(record, peerId) + * const envelope = await RecordEnvelope.seal(record, privateKey) * const wireData = envelope.marshal() * ``` * diff --git a/packages/peer-record/test/envelope.spec.ts b/packages/peer-record/test/envelope.spec.ts index 3b071faadc..03c2634550 100644 --- a/packages/peer-record/test/envelope.spec.ts +++ b/packages/peer-record/test/envelope.spec.ts @@ -1,9 +1,9 @@ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { generateKeyPair } from '@libp2p/crypto/keys' import { expect } from 'aegir/chai' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' import { RecordEnvelope } from '../src/envelope/index.js' -import type { PeerId, Record } from '@libp2p/interface' +import type { PrivateKey, Record } from '@libp2p/interface' const domain = 'libp2p-testing' const codec = uint8arrayFromString('/libp2p/testdata') @@ -30,11 +30,11 @@ class TestRecord implements Record { describe('Envelope', () => { const payloadType = codec - let peerId: PeerId + let key: PrivateKey let testRecord: TestRecord before(async () => { - peerId = await createEd25519PeerId() + key = await generateKeyPair('Ed25519') testRecord = new TestRecord('test-data') }) @@ -43,30 +43,30 @@ describe('Envelope', () => { const signature = uint8arrayFromString(Math.random().toString(36).substring(7)) const envelope = new RecordEnvelope({ - peerId, + publicKey: key.public, payloadType, payload, signature }) expect(envelope).to.exist() - expect(envelope.peerId.equals(peerId)).to.eql(true) + expect(envelope.publicKey.equals(key.public)).to.eql(true) expect(envelope.payloadType).to.equalBytes(payloadType) expect(envelope.payload.subarray()).to.equalBytes(payload.subarray()) expect(envelope.signature).to.equalBytes(signature) }) it('can seal a record', async () => { - const envelope = await RecordEnvelope.seal(testRecord, peerId) + const envelope = await RecordEnvelope.seal(testRecord, key) expect(envelope).to.exist() - expect(envelope.peerId.equals(peerId)).to.eql(true) + expect(envelope.publicKey.equals(key.public)).to.eql(true) expect(envelope.payloadType).to.eql(payloadType) expect(envelope.payload).to.exist() expect(envelope.signature).to.exist() }) it('can open and verify a sealed record', async () => { - const envelope = await RecordEnvelope.seal(testRecord, peerId) + const envelope = await RecordEnvelope.seal(testRecord, key) const rawEnvelope = envelope.marshal() const unmarshalledEnvelope = await RecordEnvelope.openAndCertify(rawEnvelope, testRecord.domain) @@ -77,7 +77,7 @@ describe('Envelope', () => { }) it('throw on open and verify when a different domain is used', async () => { - const envelope = await RecordEnvelope.seal(testRecord, peerId) + const envelope = await RecordEnvelope.seal(testRecord, key) const rawEnvelope = envelope.marshal() await expect(RecordEnvelope.openAndCertify(rawEnvelope, '/bad-domain')) diff --git a/packages/peer-record/test/peer-record.spec.ts b/packages/peer-record/test/peer-record.spec.ts index edc623cccc..7e2e17d692 100644 --- a/packages/peer-record/test/peer-record.spec.ts +++ b/packages/peer-record/test/peer-record.spec.ts @@ -1,13 +1,12 @@ /* eslint-env mocha */ -import { unmarshalPrivateKey } from '@libp2p/crypto/keys' -import { peerIdFromKeys } from '@libp2p/peer-id' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { generateKeyPair, unmarshalPrivateKey } from '@libp2p/crypto/keys' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import { RecordEnvelope } from '../src/envelope/index.js' import { PeerRecord } from '../src/peer-record/index.js' -import type { PeerId } from '@libp2p/interface' +import type { PeerId, PrivateKey } from '@libp2p/interface' describe('PeerRecord', () => { let peerId: PeerId @@ -20,17 +19,16 @@ describe('PeerRecord', () => { const privKey = Uint8Array.from([8, 1, 18, 64, 133, 251, 231, 43, 96, 100, 40, 144, 4, 165, 49, 249, 103, 137, 141, 245, 49, 158, 224, 41, 146, 253, 216, 64, 33, 250, 80, 82, 67, 75, 246, 238, 17, 187, 163, 237, 23, 33, 148, 140, 239, 180, 229, 11, 10, 11, 181, 202, 216, 166, 181, 45, 199, 177, 164, 15, 79, 102, 82, 16, 92, 145, 226, 196]) const rawEnvelope = Uint8Array.from([10, 36, 8, 1, 18, 32, 17, 187, 163, 237, 23, 33, 148, 140, 239, 180, 229, 11, 10, 11, 181, 202, 216, 166, 181, 45, 199, 177, 164, 15, 79, 102, 82, 16, 92, 145, 226, 196, 18, 2, 3, 1, 26, 170, 1, 10, 38, 0, 36, 8, 1, 18, 32, 17, 187, 163, 237, 23, 33, 148, 140, 239, 180, 229, 11, 10, 11, 181, 202, 216, 166, 181, 45, 199, 177, 164, 15, 79, 102, 82, 16, 92, 145, 226, 196, 16, 216, 184, 224, 191, 147, 145, 182, 151, 22, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 0, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 1, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 2, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 3, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 4, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 5, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 6, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 7, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 8, 26, 10, 10, 8, 4, 1, 2, 3, 4, 6, 0, 9, 42, 64, 177, 151, 247, 107, 159, 40, 138, 242, 180, 103, 254, 102, 111, 119, 68, 118, 40, 112, 73, 180, 36, 183, 57, 117, 200, 134, 14, 251, 2, 55, 45, 2, 106, 121, 149, 132, 84, 26, 215, 47, 38, 84, 52, 100, 133, 188, 163, 236, 227, 100, 98, 183, 209, 177, 57, 28, 141, 39, 109, 196, 171, 139, 202, 11]) const key = await unmarshalPrivateKey(privKey) - const peerId = await peerIdFromKeys(key.public.bytes, key.bytes) const env = await RecordEnvelope.openAndCertify(rawEnvelope, PeerRecord.DOMAIN) - expect(peerId.equals(env.peerId)) + expect(key.public.equals(env.publicKey)) const record = PeerRecord.createFromProtobuf(env.payload) // The payload isn't going to match because of how the protobuf encodes uint64 values // They are marshalled correctly on both sides, but will be off by 1 value // Signatures will still be validated - const jsEnv = await RecordEnvelope.seal(record, peerId) + const jsEnv = await RecordEnvelope.seal(record, key) expect(env.payloadType).to.eql(jsEnv.payloadType) }) @@ -116,11 +114,13 @@ describe('PeerRecord', () => { }) describe('PeerRecord inside Envelope', () => { + let key: PrivateKey let peerId: PeerId let peerRecord: PeerRecord before(async () => { - peerId = await createEd25519PeerId() + key = await generateKeyPair('Ed25519') + peerId = await createFromPrivKey(key) const multiaddrs = [ multiaddr('/ip4/127.0.0.1/tcp/2000') ] @@ -129,7 +129,7 @@ describe('PeerRecord inside Envelope', () => { }) it('creates an envelope with the PeerRecord and can unmarshal it', async () => { - const e = await RecordEnvelope.seal(peerRecord, peerId) + const e = await RecordEnvelope.seal(peerRecord, key) const byteE = e.marshal() const decodedE = await RecordEnvelope.openAndCertify(byteE, PeerRecord.DOMAIN) diff --git a/packages/peer-store/package.json b/packages/peer-store/package.json index eb0692a297..2cf229659e 100644 --- a/packages/peer-store/package.json +++ b/packages/peer-store/package.json @@ -62,6 +62,7 @@ "@libp2p/interface": "^1.7.0", "@libp2p/peer-collections": "^5.2.9", "@libp2p/peer-id": "^4.2.4", + "@libp2p/peer-id-factory": "^4.2.4", "@libp2p/peer-record": "^7.0.25", "@multiformats/multiaddr": "^12.2.3", "interface-datastore": "^8.3.0", @@ -73,8 +74,8 @@ "uint8arrays": "^5.1.0" }, "devDependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/logger": "^4.0.20", - "@libp2p/peer-id-factory": "^4.2.4", "@types/sinon": "^17.0.3", "aegir": "^44.0.1", "datastore-core": "^10.0.0", diff --git a/packages/peer-store/src/index.ts b/packages/peer-store/src/index.ts index 73cccabab5..62e09315c7 100644 --- a/packages/peer-store/src/index.ts +++ b/packages/peer-store/src/index.ts @@ -4,6 +4,7 @@ * The peer store is where libp2p stores data about the peers it has encountered on the network. */ +import { createFromPubKey } from '@libp2p/peer-id-factory' import { RecordEnvelope, PeerRecord } from '@libp2p/peer-record' import all from 'it-all' import { PersistentStore, type PeerUpdate } from './store.js' @@ -167,9 +168,10 @@ export class PersistentPeerStore implements PeerStore { async consumePeerRecord (buf: Uint8Array, expectedPeer?: PeerId): Promise { const envelope = await RecordEnvelope.openAndCertify(buf, PeerRecord.DOMAIN) + const peerId = await createFromPubKey(envelope.publicKey) - if (expectedPeer?.equals(envelope.peerId) === false) { - this.log('envelope peer id was not the expected peer id - expected: %p received: %p', expectedPeer, envelope.peerId) + if (expectedPeer?.equals(peerId) === false) { + this.log('envelope peer id was not the expected peer id - expected: %p received: %p', expectedPeer, peerId) return false } @@ -177,7 +179,7 @@ export class PersistentPeerStore implements PeerStore { let peer: Peer | undefined try { - peer = await this.get(envelope.peerId) + peer = await this.get(peerId) } catch (err: any) { if (err.name !== 'NotFoundError') { throw err diff --git a/packages/peer-store/test/index.spec.ts b/packages/peer-store/test/index.spec.ts index 04e821e913..a8722740d4 100644 --- a/packages/peer-store/test/index.spec.ts +++ b/packages/peer-store/test/index.spec.ts @@ -1,9 +1,10 @@ /* eslint-env mocha */ /* eslint max-nested-callbacks: ["error", 6] */ -import { TypedEventEmitter, type TypedEventTarget, type Libp2pEvents, type PeerId } from '@libp2p/interface' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { TypedEventEmitter, type TypedEventTarget, type Libp2pEvents, type PeerId, type PrivateKey } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { RecordEnvelope, PeerRecord } from '@libp2p/peer-record' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' @@ -14,13 +15,15 @@ import { PersistentPeerStore } from '../src/index.js' const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000') describe('PersistentPeerStore', () => { + let key: PrivateKey let peerId: PeerId let otherPeerId: PeerId let peerStore: PersistentPeerStore let events: TypedEventTarget beforeEach(async () => { - peerId = await createEd25519PeerId() + key = await generateKeyPair('Ed25519') + peerId = await createFromPrivKey(key) otherPeerId = await createEd25519PeerId() events = new TypedEventEmitter() peerStore = new PersistentPeerStore({ @@ -176,7 +179,7 @@ describe('PersistentPeerStore', () => { multiaddr('/ip4/127.0.0.1/tcp/1234') ] }) - const signedPeerRecord = await RecordEnvelope.seal(peerRecord, peerId) + const signedPeerRecord = await RecordEnvelope.seal(peerRecord, key) await expect(peerStore.has(peerId)).to.eventually.be.false() await peerStore.consumePeerRecord(signedPeerRecord.marshal()) @@ -205,7 +208,7 @@ describe('PersistentPeerStore', () => { multiaddr('/ip4/127.0.0.1/tcp/4567') ] }) - const signedPeerRecord = await RecordEnvelope.seal(peerRecord, peerId) + const signedPeerRecord = await RecordEnvelope.seal(peerRecord, key) await peerStore.consumePeerRecord(signedPeerRecord.marshal()) @@ -228,7 +231,7 @@ describe('PersistentPeerStore', () => { multiaddr('/ip4/127.0.0.1/tcp/1234') ], seqNumber: 1n - }), peerId) + }), key) const newSignedPeerRecord = await RecordEnvelope.seal(new PeerRecord({ peerId, @@ -236,7 +239,7 @@ describe('PersistentPeerStore', () => { multiaddr('/ip4/127.0.0.1/tcp/4567') ], seqNumber: 2n - }), peerId) + }), key) await expect(peerStore.consumePeerRecord(newSignedPeerRecord.marshal())).to.eventually.equal(true) await expect(peerStore.consumePeerRecord(oldSignedPeerRecord.marshal())).to.eventually.equal(false) @@ -257,7 +260,7 @@ describe('PersistentPeerStore', () => { multiaddrs: [ multiaddr('/ip4/127.0.0.1/tcp/4567') ] - }), peerId) + }), key) await expect(peerStore.has(peerId)).to.eventually.be.false() await expect(peerStore.consumePeerRecord(signedPeerRecord.marshal(), otherPeerId)).to.eventually.equal(false) diff --git a/packages/pnet/package.json b/packages/pnet/package.json index b2a6a48c37..9bd9e1b2f8 100644 --- a/packages/pnet/package.json +++ b/packages/pnet/package.json @@ -50,7 +50,7 @@ "doc-check": "aegir doc-check" }, "dependencies": { - "@libp2p/crypto": "^4.1.1", + "@libp2p/crypto": "^4.1.9", "@libp2p/interface": "^1.3.1", "it-byte-stream": "^1.0.10", "it-map": "^3.1.0", diff --git a/packages/protocol-identify/package.json b/packages/protocol-identify/package.json index 5390c1284c..effba0fcdf 100644 --- a/packages/protocol-identify/package.json +++ b/packages/protocol-identify/package.json @@ -55,6 +55,7 @@ "@libp2p/interface": "^1.7.0", "@libp2p/interface-internal": "^1.3.4", "@libp2p/peer-id": "^4.2.4", + "@libp2p/peer-id-factory": "^4.2.4", "@libp2p/peer-record": "^7.0.25", "@multiformats/multiaddr": "^12.2.3", "@multiformats/multiaddr-matcher": "^1.2.1", @@ -67,9 +68,9 @@ "wherearewe": "^2.0.1" }, "devDependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface-compliance-tests": "^5.4.12", "@libp2p/logger": "^4.0.20", - "@libp2p/peer-id-factory": "^4.2.4", "aegir": "^44.0.1", "delay": "^6.0.0", "it-length-prefixed": "^9.0.4", diff --git a/packages/protocol-identify/src/identify-push.ts b/packages/protocol-identify/src/identify-push.ts index a966557fe9..02cb9f0f5c 100644 --- a/packages/protocol-identify/src/identify-push.ts +++ b/packages/protocol-identify/src/identify-push.ts @@ -58,7 +58,7 @@ export class IdentifyPush extends AbstractIdentify implements Startable, Identif peerId: this.peerId, multiaddrs: listenAddresses }) - const signedPeerRecord = await RecordEnvelope.seal(peerRecord, this.peerId) + const signedPeerRecord = await RecordEnvelope.seal(peerRecord, this.privateKey) const supportedProtocols = this.registrar.getProtocols() const peer = await this.peerStore.get(this.peerId) const agentVersion = uint8ArrayToString(peer.metadata.get('AgentVersion') ?? uint8ArrayFromString(this.host.agentVersion)) diff --git a/packages/protocol-identify/src/identify.ts b/packages/protocol-identify/src/identify.ts index 6d82665421..e9024a272a 100644 --- a/packages/protocol-identify/src/identify.ts +++ b/packages/protocol-identify/src/identify.ts @@ -121,7 +121,6 @@ export class Identify extends AbstractIdentify implements Startable, IdentifyInt setMaxListeners(Infinity, signal) try { - const publicKey = this.peerId.publicKey ?? new Uint8Array(0) const peerData = await this.peerStore.get(this.peerId) const multiaddrs = this.addressManager.getAddresses().map(ma => ma.decapsulateCode(protocols('p2p').code)) let signedPeerRecord = peerData.peerRecordEnvelope @@ -132,7 +131,7 @@ export class Identify extends AbstractIdentify implements Startable, IdentifyInt multiaddrs }) - const envelope = await RecordEnvelope.seal(peerRecord, this.peerId) + const envelope = await RecordEnvelope.seal(peerRecord, this.privateKey) signedPeerRecord = envelope.marshal().subarray() } @@ -147,7 +146,7 @@ export class Identify extends AbstractIdentify implements Startable, IdentifyInt await pb.write({ protocolVersion: this.host.protocolVersion, agentVersion: this.host.agentVersion, - publicKey, + publicKey: this.privateKey.public.marshal(), listenAddrs: multiaddrs.map(addr => addr.bytes), signedPeerRecord, observedAddr, diff --git a/packages/protocol-identify/src/index.ts b/packages/protocol-identify/src/index.ts index a7ebc633e0..3443bb01e8 100644 --- a/packages/protocol-identify/src/index.ts +++ b/packages/protocol-identify/src/index.ts @@ -43,7 +43,7 @@ import { IdentifyPush as IdentifyPushClass } from './identify-push.js' import { Identify as IdentifyClass } from './identify.js' -import type { AbortOptions, IdentifyResult, Libp2pEvents, ComponentLogger, NodeInfo, TypedEventTarget, PeerId, PeerStore, Connection } from '@libp2p/interface' +import type { AbortOptions, IdentifyResult, Libp2pEvents, ComponentLogger, NodeInfo, TypedEventTarget, PeerId, PeerStore, Connection, PrivateKey } from '@libp2p/interface' import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal' export interface IdentifyInit { @@ -127,6 +127,7 @@ export interface IdentifyPushInit extends Omit connectionManager: StubbedInstance registrar: StubbedInstance diff --git a/packages/protocol-identify/test/index.spec.ts b/packages/protocol-identify/test/index.spec.ts index 6ee9067672..be2dcc958d 100644 --- a/packages/protocol-identify/test/index.spec.ts +++ b/packages/protocol-identify/test/index.spec.ts @@ -1,6 +1,7 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { TypedEventEmitter, start, stop } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' @@ -24,8 +25,12 @@ describe('identify', () => { let identify: Identify beforeEach(async () => { + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + components = { - peerId: await createEd25519PeerId(), + peerId, + privateKey, peerStore: stubInterface(), connectionManager: stubInterface(), registrar: stubInterface(), @@ -214,7 +219,8 @@ describe('identify', () => { await start(identify) - const remotePeer = await createEd25519PeerId() + const remotePrivateKey = await generateKeyPair('Ed25519') + const remotePeer = await createFromPrivKey(remotePrivateKey) const oldPeerRecord = await RecordEnvelope.seal(new PeerRecord({ peerId: remotePeer, @@ -222,7 +228,7 @@ describe('identify', () => { multiaddr('/ip4/127.0.0.1/tcp/1234') ], seqNumber: BigInt(1n) - }), remotePeer) + }), remotePrivateKey) const connection = identifyConnection(remotePeer, { listenAddrs: [], @@ -238,7 +244,7 @@ describe('identify', () => { multiaddr('/ip4/127.0.0.1/tcp/1234') ], seqNumber: BigInt(Date.now() * 2) - }), remotePeer) + }), remotePrivateKey) components.peerStore.get.resolves({ id: remotePeer, @@ -297,7 +303,8 @@ describe('identify', () => { await start(identify) - const remotePeer = await createEd25519PeerId() + const remotePrivateKey = await generateKeyPair('Ed25519') + const remotePeer = await createFromPrivKey(remotePrivateKey) const signedPeerRecord = await RecordEnvelope.seal(new PeerRecord({ peerId: remotePeer, @@ -305,7 +312,7 @@ describe('identify', () => { multiaddr('/ip4/127.0.0.1/tcp/5678') ], seqNumber: BigInt(Date.now() * 2) - }), remotePeer) + }), remotePrivateKey) const peerRecordEnvelope = signedPeerRecord.marshal() const message = { diff --git a/packages/protocol-identify/test/push.spec.ts b/packages/protocol-identify/test/push.spec.ts index 7edc7b5daa..3d4dc013e0 100644 --- a/packages/protocol-identify/test/push.spec.ts +++ b/packages/protocol-identify/test/push.spec.ts @@ -1,7 +1,8 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { TypedEventEmitter, start, stop } from '@libp2p/interface' import { matchPeerId } from '@libp2p/interface-compliance-tests/matchers' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import { pair } from 'it-pair' @@ -18,8 +19,12 @@ describe('identify (push)', () => { let identify: IdentifyPush beforeEach(async () => { + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + components = { - peerId: await createEd25519PeerId(), + peerId, + privateKey, peerStore: stubInterface(), connectionManager: stubInterface(), registrar: stubInterface(), diff --git a/packages/pubsub-floodsub/package.json b/packages/pubsub-floodsub/package.json index 2e494f66c1..e42754180a 100644 --- a/packages/pubsub-floodsub/package.json +++ b/packages/pubsub-floodsub/package.json @@ -67,6 +67,7 @@ "uint8arrays": "^5.1.0" }, "devDependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface-compliance-tests": "^5.4.12", "@libp2p/logger": "^4.0.20", "@libp2p/peer-collections": "^5.2.9", diff --git a/packages/pubsub-floodsub/test/floodsub.spec.ts b/packages/pubsub-floodsub/test/floodsub.spec.ts index cae44d0f7e..ce3d2e21ca 100644 --- a/packages/pubsub-floodsub/test/floodsub.spec.ts +++ b/packages/pubsub-floodsub/test/floodsub.spec.ts @@ -1,10 +1,11 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/src/keys/index.js' import { type Message, type PubSubRPC, StrictNoSign } from '@libp2p/interface' import { mockRegistrar } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' import { PeerSet } from '@libp2p/peer-collections' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { PeerStreams } from '@libp2p/pubsub/peer-streams' import { expect } from 'aegir/chai' import { sha256 } from 'multiformats/hashes/sha2' @@ -23,8 +24,12 @@ describe('floodsub', () => { before(async () => { expect(multicodec).to.exist() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + floodsub = new FloodSub({ - peerId: await createEd25519PeerId(), + peerId, + privateKey, registrar: mockRegistrar(), logger: defaultLogger() }, { diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index 4af33e31ce..84fc25be8b 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -89,6 +89,7 @@ "@libp2p/interface-internal": "^1.3.4", "@libp2p/peer-collections": "^5.2.9", "@libp2p/peer-id": "^4.2.4", + "@libp2p/peer-id-factory": "^4.2.4", "@libp2p/utils": "^5.4.9", "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", @@ -100,7 +101,6 @@ }, "devDependencies": { "@libp2p/logger": "^4.0.20", - "@libp2p/peer-id-factory": "^4.2.4", "@types/sinon": "^17.0.3", "aegir": "^44.0.1", "delay": "^6.0.0", diff --git a/packages/pubsub/src/index.ts b/packages/pubsub/src/index.ts index e692b8e2ea..1b35e368f2 100644 --- a/packages/pubsub/src/index.ts +++ b/packages/pubsub/src/index.ts @@ -40,12 +40,13 @@ import { verifySignature } from './sign.js' import { toMessage, ensureArray, noSignMsgId, msgId, toRpcMessage, randomSeqno } from './utils.js' -import type { PubSub, Message, StrictNoSign, StrictSign, PubSubInit, PubSubEvents, PeerStreams, PubSubRPCMessage, PubSubRPC, PubSubRPCSubscription, SubscriptionChangeData, PublishResult, TopicValidatorFn, ComponentLogger, Logger, Connection, PeerId } from '@libp2p/interface' +import type { PubSub, Message, StrictNoSign, StrictSign, PubSubInit, PubSubEvents, PeerStreams, PubSubRPCMessage, PubSubRPC, PubSubRPCSubscription, SubscriptionChangeData, PublishResult, TopicValidatorFn, ComponentLogger, Logger, Connection, PeerId, PrivateKey } from '@libp2p/interface' import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal' import type { Uint8ArrayList } from 'uint8arraylist' export interface PubSubComponents { peerId: PeerId + privateKey: PrivateKey registrar: Registrar logger: ComponentLogger } @@ -260,9 +261,7 @@ export abstract class PubSubBaseProtocol = Pu * Registrar notifies a closing connection with pubsub protocol */ protected _onPeerDisconnected (peerId: PeerId, conn?: Connection): void { - const idB58Str = peerId.toString() - - this.log('connection ended', idB58Str) + this.log('connection ended %p', peerId) this._removePeer(peerId) } @@ -629,7 +628,7 @@ export abstract class PubSubBaseProtocol = Pu const signaturePolicy = this.globalSignaturePolicy switch (signaturePolicy) { case 'StrictSign': - return signMessage(this.components.peerId, message, this.encodeMessage.bind(this)) + return signMessage(this.components.privateKey, message, this.encodeMessage.bind(this)) case 'StrictNoSign': return Promise.resolve({ type: 'unsigned', diff --git a/packages/pubsub/src/sign.ts b/packages/pubsub/src/sign.ts index 41de3e7bbc..729a200a2a 100644 --- a/packages/pubsub/src/sign.ts +++ b/packages/pubsub/src/sign.ts @@ -1,31 +1,24 @@ import { keys } from '@libp2p/crypto' import { peerIdFromKeys } from '@libp2p/peer-id' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { toRpcMessage } from './utils.js' -import type { PeerId, PubSubRPCMessage, SignedMessage } from '@libp2p/interface' +import type { PeerId, PrivateKey, PubSubRPCMessage, SignedMessage } from '@libp2p/interface' export const SignPrefix = uint8ArrayFromString('libp2p-pubsub:') /** * Signs the provided message with the given `peerId` */ -export async function signMessage (peerId: PeerId, message: { from: PeerId, topic: string, data: Uint8Array, sequenceNumber: bigint }, encode: (rpc: PubSubRPCMessage) => Uint8Array): Promise { - if (peerId.privateKey == null) { - throw new Error('Cannot sign message, no private key present') - } - - if (peerId.publicKey == null) { - throw new Error('Cannot sign message, no public key present') - } - +export async function signMessage (privateKey: PrivateKey, message: { from: PeerId, topic: string, data: Uint8Array, sequenceNumber: bigint }, encode: (rpc: PubSubRPCMessage) => Uint8Array): Promise { // @ts-expect-error signature field is missing, added below const outputMessage: SignedMessage = { type: 'signed', topic: message.topic, data: message.data, sequenceNumber: message.sequenceNumber, - from: peerId + from: await createFromPrivKey(privateKey) } // Get the message in bytes, and prepend with the pubsub prefix @@ -34,9 +27,8 @@ export async function signMessage (peerId: PeerId, message: { from: PeerId, topi encode(toRpcMessage(outputMessage)).subarray() ]) - const privateKey = await keys.unmarshalPrivateKey(peerId.privateKey) outputMessage.signature = await privateKey.sign(bytes) - outputMessage.key = peerId.publicKey + outputMessage.key = privateKey.public.marshal() return outputMessage } diff --git a/packages/pubsub/test/emit-self.spec.ts b/packages/pubsub/test/emit-self.spec.ts index b5abf96785..dbce068506 100644 --- a/packages/pubsub/test/emit-self.spec.ts +++ b/packages/pubsub/test/emit-self.spec.ts @@ -1,9 +1,10 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { defaultLogger } from '@libp2p/logger' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import delay from 'delay' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { - createPeerId, MockRegistrar, PubsubImplementation } from './utils/index.js' @@ -18,10 +19,12 @@ describe('emitSelf', () => { describe('enabled', () => { before(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -74,10 +77,12 @@ describe('emitSelf', () => { describe('disabled', () => { before(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { diff --git a/packages/pubsub/test/instance.spec.ts b/packages/pubsub/test/instance.spec.ts index 8f96356d0b..3182af0a2c 100644 --- a/packages/pubsub/test/instance.spec.ts +++ b/packages/pubsub/test/instance.spec.ts @@ -1,5 +1,6 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import { PubSubBaseProtocol } from '../src/index.js' import { MockRegistrar } from './utils/index.js' @@ -37,11 +38,13 @@ describe('pubsub instance', () => { }) it('should accept valid parameters', async () => { - const peerId = await createEd25519PeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) expect(() => { return new PubsubProtocol({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { // eslint-disable-line no-new diff --git a/packages/pubsub/test/lifecycle.spec.ts b/packages/pubsub/test/lifecycle.spec.ts index 787588700b..257b0593b6 100644 --- a/packages/pubsub/test/lifecycle.spec.ts +++ b/packages/pubsub/test/lifecycle.spec.ts @@ -1,10 +1,11 @@ +import { generateKeyPair } from '@libp2p/crypto/src/keys/index.js' import { defaultLogger } from '@libp2p/logger' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import delay from 'delay' import sinon from 'sinon' import { PubSubBaseProtocol } from '../src/index.js' import { - createPeerId, PubsubImplementation, ConnectionPair, MockRegistrar, @@ -42,7 +43,9 @@ describe('pubsub base lifecycle', () => { let sinonMockRegistrar: Registrar beforeEach(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + // @ts-expect-error incomplete implementation sinonMockRegistrar = { handle: sinon.stub(), @@ -53,6 +56,7 @@ describe('pubsub base lifecycle', () => { pubsub = new PubsubProtocol({ peerId, + privateKey, registrar: sinonMockRegistrar, logger: defaultLogger() }, { @@ -105,14 +109,18 @@ describe('pubsub base lifecycle', () => { // mount pubsub beforeEach(async () => { - peerIdA = await createPeerId() - peerIdB = await createPeerId() + const privateKeyA = await generateKeyPair('Ed25519') + const peerIdA = await createFromPrivKey(privateKeyA) + + const privateKeyB = await generateKeyPair('Ed25519') + const peerIdB = await createFromPrivKey(privateKeyB) registrarA = new MockRegistrar() registrarB = new MockRegistrar() pubsubA = new PubsubImplementation({ peerId: peerIdA, + privateKey: privateKeyA, registrar: registrarA, logger: defaultLogger() }, { @@ -120,6 +128,7 @@ describe('pubsub base lifecycle', () => { }) pubsubB = new PubsubImplementation({ peerId: peerIdB, + privateKey: privateKeyB, registrar: registrarB, logger: defaultLogger() }, { diff --git a/packages/pubsub/test/message.spec.ts b/packages/pubsub/test/message.spec.ts index 137d875ad2..a5c0c0a05c 100644 --- a/packages/pubsub/test/message.spec.ts +++ b/packages/pubsub/test/message.spec.ts @@ -1,11 +1,12 @@ /* eslint-env mocha */ +import { generateKeyPair } from '@libp2p/crypto/keys' import { defaultLogger } from '@libp2p/logger' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import sinon from 'sinon' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { randomSeqno } from '../src/utils.js' import { - createPeerId, MockRegistrar, PubsubImplementation } from './utils/index.js' @@ -16,9 +17,12 @@ describe('pubsub base messages', () => { let pubsub: PubsubImplementation before(async () => { - peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { diff --git a/packages/pubsub/test/pubsub.spec.ts b/packages/pubsub/test/pubsub.spec.ts index 758888f393..e7a7ee4aa5 100644 --- a/packages/pubsub/test/pubsub.spec.ts +++ b/packages/pubsub/test/pubsub.spec.ts @@ -1,7 +1,8 @@ /* eslint max-nested-callbacks: ["error", 6] */ +import { generateKeyPair } from '@libp2p/crypto/keys' import { defaultLogger } from '@libp2p/logger' import { PeerSet } from '@libp2p/peer-collections' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import delay from 'delay' import pDefer from 'p-defer' @@ -11,7 +12,6 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { PeerStreams } from '../src/peer-streams.js' import { noSignMsgId } from '../src/utils.js' import { - createPeerId, MockRegistrar, ConnectionPair, PubsubImplementation, @@ -28,9 +28,12 @@ describe('pubsub base implementation', () => { let pubsub: PubsubImplementation beforeEach(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -102,9 +105,12 @@ describe('pubsub base implementation', () => { let pubsub: PubsubImplementation beforeEach(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -130,14 +136,18 @@ describe('pubsub base implementation', () => { let registrarB: MockRegistrar beforeEach(async () => { - peerIdA = await createPeerId() - peerIdB = await createPeerId() + const privateKeyA = await generateKeyPair('Ed25519') + const peerIdA = await createFromPrivKey(privateKeyA) + + const privateKeyB = await generateKeyPair('Ed25519') + const peerIdB = await createFromPrivKey(privateKeyB) registrarA = new MockRegistrar() registrarB = new MockRegistrar() pubsubA = new PubsubImplementation({ peerId: peerIdA, + privateKey: privateKeyA, registrar: registrarA, logger: defaultLogger() }, { @@ -145,6 +155,7 @@ describe('pubsub base implementation', () => { }) pubsubB = new PubsubImplementation({ peerId: peerIdB, + privateKey: privateKeyB, registrar: registrarB, logger: defaultLogger() }, { @@ -207,9 +218,12 @@ describe('pubsub base implementation', () => { let pubsub: PubsubImplementation beforeEach(async () => { - const peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -239,14 +253,18 @@ describe('pubsub base implementation', () => { let registrarB: MockRegistrar beforeEach(async () => { - peerIdA = await createPeerId() - peerIdB = await createPeerId() + const privateKeyA = await generateKeyPair('Ed25519') + const peerIdA = await createFromPrivKey(privateKeyA) + + const privateKeyB = await generateKeyPair('Ed25519') + const peerIdB = await createFromPrivKey(privateKeyB) registrarA = new MockRegistrar() registrarB = new MockRegistrar() pubsubA = new PubsubImplementation({ peerId: peerIdA, + privateKey: privateKeyA, registrar: registrarA, logger: defaultLogger() }, { @@ -254,6 +272,7 @@ describe('pubsub base implementation', () => { }) pubsubB = new PubsubImplementation({ peerId: peerIdB, + privateKey: privateKeyB, registrar: registrarB, logger: defaultLogger() }, { @@ -336,13 +355,15 @@ describe('pubsub base implementation', () => { }) describe('getTopics', () => { - let peerId: PeerId let pubsub: PubsubImplementation beforeEach(async () => { - peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -370,9 +391,12 @@ describe('pubsub base implementation', () => { let pubsub: PubsubImplementation beforeEach(async () => { - peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { @@ -439,14 +463,16 @@ describe('pubsub base implementation', () => { }) describe('verification', () => { - let peerId: PeerId let pubsub: PubsubImplementation const data = uint8ArrayFromString('bar') beforeEach(async () => { - peerId = await createPeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) + pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { diff --git a/packages/pubsub/test/sign.spec.ts b/packages/pubsub/test/sign.spec.ts index ffcf571104..854fe9bfdd 100644 --- a/packages/pubsub/test/sign.spec.ts +++ b/packages/pubsub/test/sign.spec.ts @@ -1,5 +1,5 @@ -import { keys } from '@libp2p/crypto' -import * as PeerIdFactory from '@libp2p/peer-id-factory' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' @@ -10,19 +10,19 @@ import { } from '../src/sign.js' import { randomSeqno, toRpcMessage } from '../src/utils.js' import { RPC } from './message/rpc.js' -import type { PeerId, PubSubRPCMessage } from '@libp2p/interface' +import type { PeerId, PrivateKey, PubSubRPCMessage } from '@libp2p/interface' function encodeMessage (message: PubSubRPCMessage): Uint8Array { return RPC.Message.encode(message) } describe('message signing', () => { + let privateKey: PrivateKey let peerId: PeerId before(async () => { - peerId = await PeerIdFactory.createRSAPeerId({ - bits: 1024 - }) + privateKey = await generateKeyPair('Ed25519') + peerId = await createFromPrivKey(privateKey) }) it('should be able to sign and verify a message', async () => { @@ -37,14 +37,9 @@ describe('message signing', () => { // @ts-expect-error missing fields const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(toRpcMessage(message)).subarray()]) - if (peerId.privateKey == null) { - throw new Error('No private key found on PeerId') - } - - const privateKey = await keys.unmarshalPrivateKey(peerId.privateKey) const expectedSignature = await privateKey.sign(bytesToSign) - const signedMessage = await signMessage(peerId, message, encodeMessage) + const signedMessage = await signMessage(privateKey, message, encodeMessage) // Check the signature and public key expect(signedMessage.signature).to.equalBytes(expectedSignature) @@ -59,7 +54,8 @@ describe('message signing', () => { }) it('should be able to extract the public key from an inlined key', async () => { - const secPeerId = await PeerIdFactory.createSecp256k1PeerId() + const secPrivateKey = await generateKeyPair('secp256k1') + const secPeerId = await createFromPrivKey(secPrivateKey) const message = { type: 'signed', @@ -71,15 +67,8 @@ describe('message signing', () => { // @ts-expect-error missing fields const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(toRpcMessage(message)).subarray()]) - - if (secPeerId.privateKey == null) { - throw new Error('No private key found on PeerId') - } - - const privateKey = await keys.unmarshalPrivateKey(secPeerId.privateKey) - const expectedSignature = await privateKey.sign(bytesToSign) - - const signedMessage = await signMessage(secPeerId, message, encodeMessage) + const expectedSignature = await secPrivateKey.sign(bytesToSign) + const signedMessage = await signMessage(secPrivateKey, message, encodeMessage) // Check the signature and public key expect(signedMessage.signature).to.eql(expectedSignature) @@ -105,15 +94,8 @@ describe('message signing', () => { // @ts-expect-error missing fields const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(toRpcMessage(message)).subarray()]) - - if (peerId.privateKey == null) { - throw new Error('No private key found on PeerId') - } - - const privateKey = await keys.unmarshalPrivateKey(peerId.privateKey) const expectedSignature = await privateKey.sign(bytesToSign) - - const signedMessage = await signMessage(peerId, message, encodeMessage) + const signedMessage = await signMessage(privateKey, message, encodeMessage) // Check the signature and public key expect(signedMessage.signature).to.equalBytes(expectedSignature) diff --git a/packages/pubsub/test/topic-validators.spec.ts b/packages/pubsub/test/topic-validators.spec.ts index 153d322de7..040431da6a 100644 --- a/packages/pubsub/test/topic-validators.spec.ts +++ b/packages/pubsub/test/topic-validators.spec.ts @@ -1,6 +1,7 @@ +import { generateKeyPair } from '@libp2p/crypto/keys' import { type PubSubRPC, TopicValidatorResult, type PeerId } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createEd25519PeerId, createFromPrivKey } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' import pWaitFor from 'p-wait-for' import sinon from 'sinon' @@ -16,15 +17,16 @@ const protocol = '/pubsub/1.0.0' describe('topic validators', () => { let pubsub: PubsubImplementation - let peerId: PeerId let otherPeerId: PeerId beforeEach(async () => { - peerId = await createEd25519PeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) otherPeerId = await createEd25519PeerId() pubsub = new PubsubImplementation({ peerId, + privateKey, registrar: new MockRegistrar(), logger: defaultLogger() }, { diff --git a/packages/pubsub/test/utils/index.ts b/packages/pubsub/test/utils/index.ts index 9085e808bf..fe0c974727 100644 --- a/packages/pubsub/test/utils/index.ts +++ b/packages/pubsub/test/utils/index.ts @@ -1,16 +1,9 @@ -import * as PeerIdFactory from '@libp2p/peer-id-factory' import { duplexPair } from 'it-pair/duplex' import { PubSubBaseProtocol } from '../../src/index.js' import { RPC } from '../message/rpc.js' import type { Connection, PeerId, PublishResult, PubSubRPC, PubSubRPCMessage, Topology } from '@libp2p/interface' import type { IncomingStreamData, Registrar, StreamHandler, StreamHandlerRecord } from '@libp2p/interface-internal' -export const createPeerId = async (): Promise => { - const peerId = await PeerIdFactory.createEd25519PeerId() - - return peerId -} - export class PubsubImplementation extends PubSubBaseProtocol { async publishMessage (): Promise { return { diff --git a/packages/transport-circuit-relay-v2/package.json b/packages/transport-circuit-relay-v2/package.json index 14d230dffb..dfd48916e8 100644 --- a/packages/transport-circuit-relay-v2/package.json +++ b/packages/transport-circuit-relay-v2/package.json @@ -72,6 +72,7 @@ "uint8arrays": "^5.1.0" }, "devDependencies": { + "@libp2p/crypto": "^4.1.9", "@libp2p/interface-compliance-tests": "^5.4.12", "@libp2p/logger": "^4.0.20", "@libp2p/peer-id-factory": "^4.2.4", diff --git a/packages/transport-circuit-relay-v2/src/server/index.ts b/packages/transport-circuit-relay-v2/src/server/index.ts index f31cef78ec..a442ddb923 100644 --- a/packages/transport-circuit-relay-v2/src/server/index.ts +++ b/packages/transport-circuit-relay-v2/src/server/index.ts @@ -17,7 +17,7 @@ import { createLimitedRelay } from '../utils.js' import { ReservationStore, type ReservationStoreInit } from './reservation-store.js' import { ReservationVoucherRecord } from './reservation-voucher.js' import type { CircuitRelayService, RelayReservation } from '../index.js' -import type { ComponentLogger, Logger, Connection, Stream, ConnectionGater, PeerId, PeerStore, Startable } from '@libp2p/interface' +import type { ComponentLogger, Logger, Connection, Stream, ConnectionGater, PeerId, PeerStore, Startable, PrivateKey } from '@libp2p/interface' import type { AddressManager, ConnectionManager, IncomingStreamData, Registrar } from '@libp2p/interface-internal' import type { PeerMap } from '@libp2p/peer-collections' @@ -68,6 +68,7 @@ export interface CircuitRelayServerComponents { peerStore: PeerStore addressManager: AddressManager peerId: PeerId + privateKey: PrivateKey connectionManager: ConnectionManager connectionGater: ConnectionGater logger: ComponentLogger @@ -88,6 +89,7 @@ class CircuitRelayServer extends TypedEventEmitter implements private readonly peerStore: PeerStore private readonly addressManager: AddressManager private readonly peerId: PeerId + private readonly privateKey: PrivateKey private readonly connectionManager: ConnectionManager private readonly connectionGater: ConnectionGater private readonly reservationStore: ReservationStore @@ -110,6 +112,7 @@ class CircuitRelayServer extends TypedEventEmitter implements this.peerStore = components.peerStore this.addressManager = components.addressManager this.peerId = components.peerId + this.privateKey = components.privateKey this.connectionManager = components.connectionManager this.connectionGater = components.connectionGater this.started = false @@ -282,7 +285,7 @@ class CircuitRelayServer extends TypedEventEmitter implements peer: remotePeer, relay: this.peerId, expiration: Number(expire) - }), this.peerId) + }), this.privateKey) return { addrs, diff --git a/packages/transport-circuit-relay-v2/test/hop.spec.ts b/packages/transport-circuit-relay-v2/test/hop.spec.ts index 97c10a913e..64691ffb56 100644 --- a/packages/transport-circuit-relay-v2/test/hop.spec.ts +++ b/packages/transport-circuit-relay-v2/test/hop.spec.ts @@ -1,11 +1,12 @@ /* eslint-disable max-nested-callbacks */ +import { generateKeyPair } from '@libp2p/crypto/keys' import { TypedEventEmitter, isStartable } from '@libp2p/interface' import { matchPeerId } from '@libp2p/interface-compliance-tests/matchers' import { mockRegistrar, mockUpgrader, mockNetwork, mockConnectionManager, mockConnectionGater } from '@libp2p/interface-compliance-tests/mocks' import { defaultLogger } from '@libp2p/logger' import { PeerMap } from '@libp2p/peer-collections' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { type Multiaddr, multiaddr } from '@multiformats/multiaddr' import { expect } from 'aegir/chai' import { type MessageStream, pbStream } from 'it-protobuf-stream' @@ -15,11 +16,12 @@ import { DEFAULT_MAX_RESERVATION_STORE_SIZE, RELAY_SOURCE_TAG, RELAY_V2_HOP_CODE import { circuitRelayServer, type CircuitRelayService, circuitRelayTransport } from '../src/index.js' import { HopMessage, Status } from '../src/pb/index.js' import type { CircuitRelayServerInit } from '../src/server/index.js' -import type { TypedEventTarget, ComponentLogger, Libp2pEvents, Connection, Stream, ConnectionGater, PeerId, PeerStore, Upgrader, Transport } from '@libp2p/interface' +import type { TypedEventTarget, ComponentLogger, Libp2pEvents, Connection, Stream, ConnectionGater, PeerId, PeerStore, Upgrader, Transport, PrivateKey } from '@libp2p/interface' import type { RandomWalk, AddressManager, ConnectionManager, Registrar, TransportManager } from '@libp2p/interface-internal' interface Node { peerId: PeerId + privateKey: PrivateKey multiaddr: Multiaddr registrar: Registrar peerStore: StubbedInstance @@ -43,7 +45,8 @@ describe('circuit-relay hop protocol', function () { async function createNode (circuitRelayInit?: CircuitRelayServerInit): Promise { peerIndex++ - const peerId = await createEd25519PeerId() + const privateKey = await generateKeyPair('Ed25519') + const peerId = await createFromPrivKey(privateKey) const registrar = mockRegistrar() const connections = new PeerMap() @@ -84,6 +87,7 @@ describe('circuit-relay hop protocol', function () { addressManager, connectionManager, peerId, + privateKey, peerStore, registrar, connectionGater, @@ -114,6 +118,7 @@ describe('circuit-relay hop protocol', function () { const node: Node = { peerId, + privateKey, multiaddr: ma, registrar, circuitRelayService: service,