From 1f38ab7ac8380c9501b252d076bb356662978882 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Wed, 17 Aug 2022 21:34:57 +0100 Subject: [PATCH] fix!: load self key into keychain on startup if not present (#1357) To prevent triggering keychain attack prevention on startup, refactor the `KeyChain` class to load the current PeerId as the `'self'` key on startup. Fixes #1315 BREAKING CHANGE: the `loadKeychain` method has been removed as it is no longer necessary --- doc/API.md | 30 ------------------------------ doc/CONFIGURATION.md | 2 -- src/index.ts | 6 ------ src/keychain/index.ts | 30 +++++++++++++++++++++++++++--- src/libp2p.ts | 16 ---------------- test/configuration/utils.ts | 2 -- test/keychain/keychain.spec.ts | 6 ------ 7 files changed, 27 insertions(+), 65 deletions(-) diff --git a/doc/API.md b/doc/API.md index a4ae0830..402a6b37 100644 --- a/doc/API.md +++ b/doc/API.md @@ -185,36 +185,6 @@ Required keys in the `options` object: ## Libp2p Instance Methods -### loadKeychain - -Load keychain keys from the datastore, importing the private key as 'self', if needed. - -`libp2p.loadKeychain()` - -#### Returns - -| Type | Description | -|------|-------------| -| `Promise` | Promise resolves when the keychain is ready | - -#### Example - -```js -import { createLibp2p } from 'libp2p' - -// ... - -const libp2p = await createLibp2p({ - // ... - keychain: { - pass: '0123456789pass1234567890' - } -}) - -// load keychain -await libp2p.loadKeychain() -``` - ### start Starts the libp2p node. diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 0740154a..fc3cab84 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -494,8 +494,6 @@ const node = await createLibp2p({ datastore: dsInstant, } }) - -await node.loadKeychain() ``` #### Configuring Dialing diff --git a/src/index.ts b/src/index.ts index d5c38307..0ba5ad7b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -140,12 +140,6 @@ export interface Libp2p extends Startable, EventEmitter { pubsub: PubSub dht: DualDHT - /** - * Load keychain keys from the datastore. - * Imports the private key as 'self', if needed. - */ - loadKeychain: () => Promise - /** * Get a deduplicated list of peer advertising multiaddrs by concatenating * the listen addresses used by transports with any configured diff --git a/src/keychain/index.ts b/src/keychain/index.ts index 67543d49..df044864 100644 --- a/src/keychain/index.ts +++ b/src/keychain/index.ts @@ -13,6 +13,7 @@ import { generateKeyPair, importKey, unmarshalPrivateKey } from '@libp2p/crypto/ import type { PeerId } from '@libp2p/interface-peer-id' import type { Components } from '@libp2p/components' import { pbkdf2, randomBytes } from '@libp2p/crypto' +import type { Startable } from '@libp2p/interfaces/dist/src/startable' const log = logger('libp2p:keychain') @@ -110,9 +111,10 @@ function DsInfoName (name: string) { * - '/pkcs8/*key-name*', contains the PKCS #8 for the key * */ -export class KeyChain { +export class KeyChain implements Startable { private readonly components: Components private init: KeyChainInit + private started: boolean /** * Creates a new instance of a key chain @@ -145,6 +147,25 @@ export class KeyChain { : '' privates.set(this, { dek }) + this.started = false + } + + isStarted () { + return this.started + } + + async start () { + const dsname = DsInfoName('self') + + if (!(await this.components.getDatastore().has(dsname))) { + await this.importPeer('self', this.components.getPeerId()) + } + + this.started = true + } + + stop () { + this.started = false } /** @@ -474,8 +495,11 @@ export class KeyChain { if (!validateKeyName(name)) { throw errCode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME) } - if (peer == null || peer.privateKey == null) { - throw errCode(new Error('Peer.privKey is required'), codes.ERR_MISSING_PRIVATE_KEY) + if (peer == null) { + throw errCode(new Error('PeerId is required'), codes.ERR_MISSING_PRIVATE_KEY) + } + if (peer.privateKey == null) { + throw errCode(new Error('PeerId.privKey is required'), codes.ERR_MISSING_PRIVATE_KEY) } const privateKey = await unmarshalPrivateKey(peer.privateKey) diff --git a/src/libp2p.ts b/src/libp2p.ts index 0a5a435d..c08b9e21 100644 --- a/src/libp2p.ts +++ b/src/libp2p.ts @@ -352,22 +352,6 @@ export class Libp2pNode extends EventEmitter implements Libp2p { log('libp2p has stopped') } - /** - * Load keychain keys from the datastore. - * Imports the private key as 'self', if needed. - */ - async loadKeychain () { - if (this.keychain == null) { - return - } - - try { - await this.keychain.findKeyByName('self') - } catch (err: any) { - await this.keychain.importPeer('self', this.peerId) - } - } - isStarted () { return this.started } diff --git a/test/configuration/utils.ts b/test/configuration/utils.ts index a34385c9..cfec4078 100644 --- a/test/configuration/utils.ts +++ b/test/configuration/utils.ts @@ -9,12 +9,10 @@ import type { Message, PublishResult, PubSubInit, PubSubRPC, PubSubRPCMessage } import type { Libp2pInit, Libp2pOptions } from '../../src/index.js' import type { PeerId } from '@libp2p/interface-peer-id' import * as cborg from 'cborg' -import { peerIdFromString } from '@libp2p/peer-id' const relayAddr = MULTIADDRS_WEBSOCKETS[0] export const baseOptions: Partial = { - peerId: peerIdFromString('12D3KooWJKCJW8Y26pRFNv78TCMGLNTfyN8oKaFswMRYXTzSbSst'), transports: [new WebSockets()], streamMuxers: [new Mplex()], connectionEncryption: [new Plaintext()] diff --git a/test/keychain/keychain.spec.ts b/test/keychain/keychain.spec.ts index dd742d48..d93fe7e1 100644 --- a/test/keychain/keychain.spec.ts +++ b/test/keychain/keychain.spec.ts @@ -512,8 +512,6 @@ describe('libp2p.keychain', () => { } }) - await libp2p.loadKeychain() - const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519') expect(kInfo).to.exist() }) @@ -526,8 +524,6 @@ describe('libp2p.keychain', () => { } }) - await libp2p.loadKeychain() - const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519') expect(kInfo).to.exist() }) @@ -543,7 +539,6 @@ describe('libp2p.keychain', () => { } } }) - await libp2p.loadKeychain() const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519') expect(kInfo).to.exist() @@ -558,7 +553,6 @@ describe('libp2p.keychain', () => { } }) - await libp2p2.loadKeychain() const key = await libp2p2.keychain.findKeyByName('keyName') expect(key).to.exist()