mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 10:32:14 +00:00
fix: load keychain on startup
Renames KeyChain to DefaultKeyChain and makes it implement the Startable interface. Loads the current peer id into the keychain on startup instead of the user having to do it manually.
This commit is contained in:
parent
1b9bab68ed
commit
82330ac4e6
30
doc/API.md
30
doc/API.md
@ -181,36 +181,6 @@ Required keys in the `options` object:
|
|||||||
|
|
||||||
## Libp2p Instance Methods
|
## 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
|
### start
|
||||||
|
|
||||||
Starts the libp2p node.
|
Starts the libp2p node.
|
||||||
|
@ -494,8 +494,6 @@ const node = await createLibp2p({
|
|||||||
datastore: dsInstant,
|
datastore: dsInstant,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await node.loadKeychain()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Configuring Dialing
|
#### Configuring Dialing
|
||||||
|
@ -20,7 +20,7 @@ import type { ConnectionManager, Registrar, StreamHandler } from '@libp2p/interf
|
|||||||
import type { Metrics, MetricsInit } from '@libp2p/interfaces/metrics'
|
import type { Metrics, MetricsInit } from '@libp2p/interfaces/metrics'
|
||||||
import type { PeerInfo } from '@libp2p/interfaces/peer-info'
|
import type { PeerInfo } from '@libp2p/interfaces/peer-info'
|
||||||
import type { DialerInit } from '@libp2p/interfaces/dialer'
|
import type { DialerInit } from '@libp2p/interfaces/dialer'
|
||||||
import type { KeyChain } from './keychain/index.js'
|
import type { KeyChain } from '@libp2p/interfaces/keychain'
|
||||||
|
|
||||||
export interface PersistentPeerStoreOptions {
|
export interface PersistentPeerStoreOptions {
|
||||||
threshold?: number
|
threshold?: number
|
||||||
@ -158,12 +158,6 @@ export interface Libp2p extends Startable, EventEmitter<Libp2pEvents> {
|
|||||||
pubsub?: PubSub
|
pubsub?: PubSub
|
||||||
dht?: DualDHT
|
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
|
* Get a deduplicated list of peer advertising multiaddrs by concatenating
|
||||||
* the listen addresses used by transports with any configured
|
* the listen addresses used by transports with any configured
|
||||||
|
@ -8,7 +8,7 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|||||||
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
||||||
import { codes } from '../errors.js'
|
import { codes } from '../errors.js'
|
||||||
import { logger } from '@libp2p/logger'
|
import { logger } from '@libp2p/logger'
|
||||||
import type { KeyChain } from './index.js'
|
import type { DefaultKeyChain } from './index.js'
|
||||||
|
|
||||||
const log = logger('libp2p:keychain:cms')
|
const log = logger('libp2p:keychain:cms')
|
||||||
|
|
||||||
@ -24,12 +24,12 @@ const privates = new WeakMap<object, { dek: string }>()
|
|||||||
* See RFC 5652 for all the details.
|
* See RFC 5652 for all the details.
|
||||||
*/
|
*/
|
||||||
export class CMS {
|
export class CMS {
|
||||||
private readonly keychain: KeyChain
|
private readonly keychain: DefaultKeyChain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance with a keychain
|
* Creates a new instance with a keychain
|
||||||
*/
|
*/
|
||||||
constructor (keychain: KeyChain, dek: string) {
|
constructor (keychain: DefaultKeyChain, dek: string) {
|
||||||
if (keychain == null) {
|
if (keychain == null) {
|
||||||
throw errCode(new Error('keychain is required'), codes.ERR_KEYCHAIN_REQUIRED)
|
throw errCode(new Error('keychain is required'), codes.ERR_KEYCHAIN_REQUIRED)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import { generateKeyPair, importKey, unmarshalPrivateKey } from '@libp2p/crypto/
|
|||||||
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
||||||
import type { Components } from '@libp2p/interfaces/components'
|
import type { Components } from '@libp2p/interfaces/components'
|
||||||
import { pbkdf2, randomBytes } from '@libp2p/crypto'
|
import { pbkdf2, randomBytes } from '@libp2p/crypto'
|
||||||
|
import type { KeyChain } from '@libp2p/interfaces/keychain'
|
||||||
|
import type { Startable } from '@libp2p/interfaces'
|
||||||
|
|
||||||
const log = logger('libp2p:keychain')
|
const log = logger('libp2p:keychain')
|
||||||
|
|
||||||
@ -111,9 +113,10 @@ function DsInfoName (name: string) {
|
|||||||
* - '/pkcs8/*key-name*', contains the PKCS #8 for the key
|
* - '/pkcs8/*key-name*', contains the PKCS #8 for the key
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export class KeyChain {
|
export class DefaultKeyChain implements KeyChain, Startable {
|
||||||
private readonly components: Components
|
private readonly components: Components
|
||||||
private init: KeyChainInit
|
private init: KeyChainInit
|
||||||
|
private started: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of a key chain
|
* Creates a new instance of a key chain
|
||||||
@ -146,6 +149,27 @@ export class KeyChain {
|
|||||||
: ''
|
: ''
|
||||||
|
|
||||||
privates.set(this, { dek })
|
privates.set(this, { dek })
|
||||||
|
this.started = false
|
||||||
|
}
|
||||||
|
|
||||||
|
isStarted () {
|
||||||
|
return this.started
|
||||||
|
}
|
||||||
|
|
||||||
|
async start () {
|
||||||
|
// Load keychain keys from the datastore.
|
||||||
|
// Imports the private key as 'self', if needed.
|
||||||
|
try {
|
||||||
|
await this.findKeyByName('self')
|
||||||
|
} catch (err: any) {
|
||||||
|
await this.importPeer('self', this.components.getPeerId())
|
||||||
|
}
|
||||||
|
|
||||||
|
this.started = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async stop () {
|
||||||
|
this.started = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,7 +12,7 @@ import { AutoDialler } from './connection-manager/auto-dialler.js'
|
|||||||
import { Circuit } from './circuit/transport.js'
|
import { Circuit } from './circuit/transport.js'
|
||||||
import { Relay } from './circuit/index.js'
|
import { Relay } from './circuit/index.js'
|
||||||
import { DefaultDialer } from './dialer/index.js'
|
import { DefaultDialer } from './dialer/index.js'
|
||||||
import { KeyChain } from './keychain/index.js'
|
import { DefaultKeyChain } from './keychain/index.js'
|
||||||
import { DefaultMetrics } from './metrics/index.js'
|
import { DefaultMetrics } from './metrics/index.js'
|
||||||
import { DefaultTransportManager } from './transport-manager.js'
|
import { DefaultTransportManager } from './transport-manager.js'
|
||||||
import { DefaultUpgrader } from './upgrader.js'
|
import { DefaultUpgrader } from './upgrader.js'
|
||||||
@ -44,6 +44,7 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|||||||
import errCode from 'err-code'
|
import errCode from 'err-code'
|
||||||
import { unmarshalPublicKey } from '@libp2p/crypto/keys'
|
import { unmarshalPublicKey } from '@libp2p/crypto/keys'
|
||||||
import type { Metrics } from '@libp2p/interfaces/metrics'
|
import type { Metrics } from '@libp2p/interfaces/metrics'
|
||||||
|
import type { KeyChain } from '@libp2p/interfaces/keychain'
|
||||||
|
|
||||||
const log = logger('libp2p')
|
const log = logger('libp2p')
|
||||||
|
|
||||||
@ -140,8 +141,8 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Create keychain
|
// Create keychain
|
||||||
const keychainOpts = KeyChain.generateOptions()
|
const keychainOpts = DefaultKeyChain.generateOptions()
|
||||||
this.keychain = this.configureComponent(new KeyChain(this.components, {
|
this.keychain = this.configureComponent(new DefaultKeyChain(this.components, {
|
||||||
...keychainOpts,
|
...keychainOpts,
|
||||||
...init.keychain
|
...init.keychain
|
||||||
}))
|
}))
|
||||||
@ -352,22 +353,6 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|||||||
log('libp2p has stopped')
|
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 () {
|
isStarted () {
|
||||||
return this.started
|
return this.started
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,17 @@ import { expect } from 'aegir/chai'
|
|||||||
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
||||||
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
||||||
import { MemoryDatastore } from 'datastore-core/memory'
|
import { MemoryDatastore } from 'datastore-core/memory'
|
||||||
import { KeyChain } from '../../src/keychain/index.js'
|
import { DefaultKeyChain } from '../../src/keychain/index.js'
|
||||||
import { Components } from '@libp2p/interfaces/components'
|
import { Components } from '@libp2p/interfaces/components'
|
||||||
|
|
||||||
describe('cms interop', () => {
|
describe('cms interop', () => {
|
||||||
const passPhrase = 'this is not a secure phrase'
|
const passPhrase = 'this is not a secure phrase'
|
||||||
const aliceKeyName = 'cms-interop-alice'
|
const aliceKeyName = 'cms-interop-alice'
|
||||||
let ks: KeyChain
|
let ks: DefaultKeyChain
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
const datastore = new MemoryDatastore()
|
const datastore = new MemoryDatastore()
|
||||||
ks = new KeyChain(new Components({ datastore }), { pass: passPhrase })
|
ks = new DefaultKeyChain(new Components({ datastore }), { pass: passPhrase })
|
||||||
})
|
})
|
||||||
|
|
||||||
const plainData = uint8ArrayFromString('This is a message from Alice to Bob')
|
const plainData = uint8ArrayFromString('This is a message from Alice to Bob')
|
||||||
|
@ -7,7 +7,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|||||||
import { createNode } from '../utils/creators/peer.js'
|
import { createNode } from '../utils/creators/peer.js'
|
||||||
import { Key } from 'interface-datastore/key'
|
import { Key } from 'interface-datastore/key'
|
||||||
import { MemoryDatastore } from 'datastore-core/memory'
|
import { MemoryDatastore } from 'datastore-core/memory'
|
||||||
import { KeyChain, KeyChainInit, KeyInfo } from '../../src/keychain/index.js'
|
import { DefaultKeyChain, KeyChainInit, KeyInfo } from '../../src/keychain/index.js'
|
||||||
import { pbkdf2 } from '@libp2p/crypto'
|
import { pbkdf2 } from '@libp2p/crypto'
|
||||||
import { Components } from '@libp2p/interfaces/components'
|
import { Components } from '@libp2p/interfaces/components'
|
||||||
import type { Datastore } from 'interface-datastore'
|
import type { Datastore } from 'interface-datastore'
|
||||||
@ -20,16 +20,16 @@ describe('keychain', () => {
|
|||||||
const rsaKeyName = 'tajné jméno'
|
const rsaKeyName = 'tajné jméno'
|
||||||
const renamedRsaKeyName = 'ชื่อลับ'
|
const renamedRsaKeyName = 'ชื่อลับ'
|
||||||
let rsaKeyInfo: KeyInfo
|
let rsaKeyInfo: KeyInfo
|
||||||
let emptyKeystore: KeyChain
|
let emptyKeystore: DefaultKeyChain
|
||||||
let ks: KeyChain
|
let ks: DefaultKeyChain
|
||||||
let datastore1: Datastore, datastore2: Datastore
|
let datastore1: Datastore, datastore2: Datastore
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
datastore1 = new MemoryDatastore()
|
datastore1 = new MemoryDatastore()
|
||||||
datastore2 = new MemoryDatastore()
|
datastore2 = new MemoryDatastore()
|
||||||
|
|
||||||
ks = new KeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase })
|
ks = new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase })
|
||||||
emptyKeystore = new KeyChain(new Components({ datastore: datastore1 }), { pass: passPhrase })
|
emptyKeystore = new DefaultKeyChain(new Components({ datastore: datastore1 }), { pass: passPhrase })
|
||||||
|
|
||||||
await datastore1.open()
|
await datastore1.open()
|
||||||
await datastore2.open()
|
await datastore2.open()
|
||||||
@ -41,35 +41,35 @@ describe('keychain', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can start without a password', () => {
|
it('can start without a password', () => {
|
||||||
expect(() => new KeyChain(new Components({ datastore: datastore2 }), {})).to.not.throw()
|
expect(() => new DefaultKeyChain(new Components({ datastore: datastore2 }), {})).to.not.throw()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('needs a NIST SP 800-132 non-weak pass phrase', () => {
|
it('needs a NIST SP 800-132 non-weak pass phrase', () => {
|
||||||
expect(() => new KeyChain(new Components({ datastore: datastore2 }), { pass: '< 20 character' })).to.throw()
|
expect(() => new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: '< 20 character' })).to.throw()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('has default options', () => {
|
it('has default options', () => {
|
||||||
expect(KeyChain.options).to.exist()
|
expect(DefaultKeyChain.options).to.exist()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('supports supported hashing alorithms', () => {
|
it('supports supported hashing alorithms', () => {
|
||||||
const ok = new KeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase, dek: { hash: 'sha2-256', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } })
|
const ok = new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase, dek: { hash: 'sha2-256', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } })
|
||||||
expect(ok).to.exist()
|
expect(ok).to.exist()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not support unsupported hashing alorithms', () => {
|
it('does not support unsupported hashing alorithms', () => {
|
||||||
expect(() => new KeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase, dek: { hash: 'my-hash', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } })).to.throw()
|
expect(() => new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: passPhrase, dek: { hash: 'my-hash', salt: 'salt-salt-salt-salt', iterationCount: 1000, keyLength: 14 } })).to.throw()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can list keys without a password', async () => {
|
it('can list keys without a password', async () => {
|
||||||
const keychain = new KeyChain(new Components({ datastore: datastore2 }), {})
|
const keychain = new DefaultKeyChain(new Components({ datastore: datastore2 }), {})
|
||||||
|
|
||||||
expect(await keychain.listKeys()).to.have.lengthOf(0)
|
expect(await keychain.listKeys()).to.have.lengthOf(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can find a key without a password', async () => {
|
it('can find a key without a password', async () => {
|
||||||
const keychain = new KeyChain(new Components({ datastore: datastore2 }), {})
|
const keychain = new DefaultKeyChain(new Components({ datastore: datastore2 }), {})
|
||||||
const keychainWithPassword = new KeyChain(new Components({ datastore: datastore2 }), { pass: `hello-${Date.now()}-${Date.now()}` })
|
const keychainWithPassword = new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: `hello-${Date.now()}-${Date.now()}` })
|
||||||
const name = `key-${Math.random()}`
|
const name = `key-${Math.random()}`
|
||||||
|
|
||||||
const { id } = await keychainWithPassword.createKey(name, 'Ed25519')
|
const { id } = await keychainWithPassword.createKey(name, 'Ed25519')
|
||||||
@ -78,8 +78,8 @@ describe('keychain', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('can remove a key without a password', async () => {
|
it('can remove a key without a password', async () => {
|
||||||
const keychainWithoutPassword = new KeyChain(new Components({ datastore: datastore2 }), {})
|
const keychainWithoutPassword = new DefaultKeyChain(new Components({ datastore: datastore2 }), {})
|
||||||
const keychainWithPassword = new KeyChain(new Components({ datastore: datastore2 }), { pass: `hello-${Date.now()}-${Date.now()}` })
|
const keychainWithPassword = new DefaultKeyChain(new Components({ datastore: datastore2 }), { pass: `hello-${Date.now()}-${Date.now()}` })
|
||||||
const name = `key-${Math.random()}`
|
const name = `key-${Math.random()}`
|
||||||
|
|
||||||
expect(await keychainWithPassword.createKey(name, 'Ed25519')).to.have.property('name', name)
|
expect(await keychainWithPassword.createKey(name, 'Ed25519')).to.have.property('name', name)
|
||||||
@ -89,16 +89,16 @@ describe('keychain', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('requires a name to create a password', async () => {
|
it('requires a name to create a password', async () => {
|
||||||
const keychain = new KeyChain(new Components({ datastore: datastore2 }), {})
|
const keychain = new DefaultKeyChain(new Components({ datastore: datastore2 }), {})
|
||||||
|
|
||||||
// @ts-expect-error invalid parameters
|
// @ts-expect-error invalid parameters
|
||||||
await expect(keychain.createKey(undefined, 'derp')).to.be.rejected()
|
await expect(keychain.createKey(undefined, 'derp')).to.be.rejected()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can generate options', () => {
|
it('can generate options', () => {
|
||||||
const options = KeyChain.generateOptions()
|
const options = DefaultKeyChain.generateOptions()
|
||||||
options.pass = passPhrase
|
options.pass = passPhrase
|
||||||
const chain = new KeyChain(new Components({ datastore: datastore2 }), options)
|
const chain = new DefaultKeyChain(new Components({ datastore: datastore2 }), options)
|
||||||
expect(chain).to.exist()
|
expect(chain).to.exist()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -418,7 +418,7 @@ describe('keychain', () => {
|
|||||||
|
|
||||||
describe('rotate keychain passphrase', () => {
|
describe('rotate keychain passphrase', () => {
|
||||||
let oldPass: string
|
let oldPass: string
|
||||||
let kc: KeyChain
|
let kc: DefaultKeyChain
|
||||||
let options: KeyChainInit
|
let options: KeyChainInit
|
||||||
let ds: Datastore
|
let ds: Datastore
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -433,7 +433,7 @@ describe('keychain', () => {
|
|||||||
hash: 'sha2-512'
|
hash: 'sha2-512'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kc = new KeyChain(new Components({ datastore: ds }), options)
|
kc = new DefaultKeyChain(new Components({ datastore: ds }), options)
|
||||||
await ds.open()
|
await ds.open()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -512,8 +512,6 @@ describe('libp2p.keychain', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await libp2p.loadKeychain()
|
|
||||||
|
|
||||||
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
||||||
expect(kInfo).to.exist()
|
expect(kInfo).to.exist()
|
||||||
})
|
})
|
||||||
@ -526,8 +524,6 @@ describe('libp2p.keychain', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await libp2p.loadKeychain()
|
|
||||||
|
|
||||||
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
||||||
expect(kInfo).to.exist()
|
expect(kInfo).to.exist()
|
||||||
})
|
})
|
||||||
@ -543,7 +539,6 @@ describe('libp2p.keychain', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await libp2p.loadKeychain()
|
|
||||||
|
|
||||||
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
const kInfo = await libp2p.keychain.createKey('keyName', 'Ed25519')
|
||||||
expect(kInfo).to.exist()
|
expect(kInfo).to.exist()
|
||||||
@ -558,7 +553,6 @@ describe('libp2p.keychain', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await libp2p2.loadKeychain()
|
|
||||||
const key = await libp2p2.keychain.findKeyByName('keyName')
|
const key = await libp2p2.keychain.findKeyByName('keyName')
|
||||||
|
|
||||||
expect(key).to.exist()
|
expect(key).to.exist()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user