Skip to content

Commit

Permalink
fix!: load self key into keychain on startup if not present (#1357)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
achingbrain authored Aug 17, 2022
1 parent 29c803a commit 1f38ab7
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 65 deletions.
30 changes: 0 additions & 30 deletions doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 0 additions & 2 deletions doc/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,6 @@ const node = await createLibp2p({
datastore: dsInstant,
}
})

await node.loadKeychain()
```

#### Configuring Dialing
Expand Down
6 changes: 0 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,6 @@ export interface Libp2p extends Startable, EventEmitter<Libp2pEvents> {
pubsub: PubSub
dht: DualDHT

/**
* Load keychain keys from the datastore.
* Imports the private key as 'self', if needed.
*/
loadKeychain: () => Promise<void>

/**
* Get a deduplicated list of peer advertising multiaddrs by concatenating
* the listen addresses used by transports with any configured
Expand Down
30 changes: 27 additions & 3 deletions src/keychain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

/**
Expand Down Expand Up @@ -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)
Expand Down
16 changes: 0 additions & 16 deletions src/libp2p.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,22 +352,6 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> 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
}
Expand Down
2 changes: 0 additions & 2 deletions test/configuration/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Libp2pInit> = {
peerId: peerIdFromString('12D3KooWJKCJW8Y26pRFNv78TCMGLNTfyN8oKaFswMRYXTzSbSst'),
transports: [new WebSockets()],
streamMuxers: [new Mplex()],
connectionEncryption: [new Plaintext()]
Expand Down
6 changes: 0 additions & 6 deletions test/keychain/keychain.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,6 @@ describe('libp2p.keychain', () => {
}
})

await libp2p.loadKeychain()

const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
expect(kInfo).to.exist()
})
Expand All @@ -526,8 +524,6 @@ describe('libp2p.keychain', () => {
}
})

await libp2p.loadKeychain()

const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
expect(kInfo).to.exist()
})
Expand All @@ -543,7 +539,6 @@ describe('libp2p.keychain', () => {
}
}
})
await libp2p.loadKeychain()

const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
expect(kInfo).to.exist()
Expand All @@ -558,7 +553,6 @@ describe('libp2p.keychain', () => {
}
})

await libp2p2.loadKeychain()
const key = await libp2p2.keychain.findKeyByName('keyName')

expect(key).to.exist()
Expand Down

0 comments on commit 1f38ab7

Please sign in to comment.