libp2p 0.34.0 → 0.35.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/config.d.ts +0 -6
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/connection-manager/auto-dialler.d.ts +56 -0
- package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -0
- package/dist/src/connection-manager/index.d.ts +0 -10
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
- package/dist/src/dialer/dial-request.d.ts.map +1 -1
- package/dist/src/dialer/index.d.ts +1 -1
- package/dist/src/dialer/index.d.ts.map +1 -1
- package/dist/src/errors.d.ts +24 -0
- package/dist/src/index.d.ts +3 -27
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/keychain/cms.d.ts.map +1 -1
- package/dist/src/keychain/index.d.ts.map +1 -1
- package/dist/src/peer-routing.d.ts +8 -1
- package/dist/src/peer-routing.d.ts.map +1 -1
- package/dist/src/peer-store/book.d.ts.map +1 -1
- package/package.json +32 -31
- package/src/circuit/index.js +2 -2
- package/src/config.js +1 -7
- package/src/connection-manager/auto-dialler.js +118 -0
- package/src/connection-manager/index.js +0 -52
- package/src/content-routing/index.js +2 -2
- package/src/dht/dht-peer-routing.js +6 -2
- package/src/dialer/dial-request.js +10 -3
- package/src/dialer/index.js +10 -9
- package/src/errors.js +25 -1
- package/src/index.js +9 -9
- package/src/keychain/cms.js +7 -6
- package/src/keychain/index.js +25 -24
- package/src/nat-manager.js +1 -1
- package/src/peer-routing.js +21 -8
- package/src/peer-store/book.js +4 -7
- package/src/ping/index.js +2 -2
- package/src/upgrader.js +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const debug = require('debug')
|
|
4
|
+
const mergeOptions = require('merge-options')
|
|
5
|
+
// @ts-ignore retimer does not have types
|
|
6
|
+
const retimer = require('retimer')
|
|
7
|
+
|
|
8
|
+
const log = Object.assign(debug('libp2p:connection-manager:auto-dialler'), {
|
|
9
|
+
error: debug('libp2p:connection-manager:auto-dialler:err')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const defaultOptions = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
minConnections: 0,
|
|
15
|
+
autoDialInterval: 10000
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {import('../index')} Libp2p
|
|
20
|
+
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} AutoDiallerOptions
|
|
25
|
+
* @property {boolean} [enabled = true] - Should preemptively guarantee connections are above the low watermark
|
|
26
|
+
* @property {number} [minConnections = 0] - The minimum number of connections to avoid pruning
|
|
27
|
+
* @property {number} [autoDialInterval = 10000] - How often, in milliseconds, it should preemptively guarantee connections are above the low watermark
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
class AutoDialler {
|
|
31
|
+
/**
|
|
32
|
+
* Proactively tries to connect to known peers stored in the PeerStore.
|
|
33
|
+
* It will keep the number of connections below the upper limit and sort
|
|
34
|
+
* the peers to connect based on wether we know their keys and protocols.
|
|
35
|
+
*
|
|
36
|
+
* @class
|
|
37
|
+
* @param {Libp2p} libp2p
|
|
38
|
+
* @param {AutoDiallerOptions} options
|
|
39
|
+
*/
|
|
40
|
+
constructor (libp2p, options = {}) {
|
|
41
|
+
this._options = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, options)
|
|
42
|
+
this._libp2p = libp2p
|
|
43
|
+
this._running = false
|
|
44
|
+
this._autoDialTimeout = null
|
|
45
|
+
this._autoDial = this._autoDial.bind(this)
|
|
46
|
+
|
|
47
|
+
log('options: %j', this._options)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Starts the auto dialer
|
|
52
|
+
*/
|
|
53
|
+
start () {
|
|
54
|
+
if (!this._options.enabled) {
|
|
55
|
+
log('not enabled')
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this._running = true
|
|
60
|
+
this._autoDial()
|
|
61
|
+
log('started')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Stops the auto dialler
|
|
66
|
+
*/
|
|
67
|
+
async stop () {
|
|
68
|
+
if (!this._options.enabled) {
|
|
69
|
+
log('not enabled')
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this._running = false
|
|
74
|
+
this._autoDialTimeout && this._autoDialTimeout.clear()
|
|
75
|
+
log('stopped')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async _autoDial () {
|
|
79
|
+
const minConnections = this._options.minConnections
|
|
80
|
+
|
|
81
|
+
// Already has enough connections
|
|
82
|
+
if (this._libp2p.connections.size >= minConnections) {
|
|
83
|
+
this._autoDialTimeout = retimer(this._autoDial, this._options.autoDialInterval)
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Sort peers on wether we know protocols of public keys for them
|
|
88
|
+
const peers = Array.from(this._libp2p.peerStore.peers.values())
|
|
89
|
+
.sort((a, b) => {
|
|
90
|
+
if (b.protocols && b.protocols.length && (!a.protocols || !a.protocols.length)) {
|
|
91
|
+
return 1
|
|
92
|
+
} else if (b.id.pubKey && !a.id.pubKey) {
|
|
93
|
+
return 1
|
|
94
|
+
}
|
|
95
|
+
return -1
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
for (let i = 0; this._running && i < peers.length && this._libp2p.connections.size < minConnections; i++) {
|
|
99
|
+
if (!this._libp2p.connectionManager.get(peers[i].id)) {
|
|
100
|
+
log('connecting to a peerStore stored peer %s', peers[i].id.toB58String())
|
|
101
|
+
try {
|
|
102
|
+
await this._libp2p.dialer.connectToPeer(peers[i].id)
|
|
103
|
+
} catch (/** @type {any} */ err) {
|
|
104
|
+
log.error('could not connect to peerStore stored peer', err)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Connection Manager was stopped
|
|
110
|
+
if (!this._running) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this._autoDialTimeout = retimer(this._autoDial, this._options.autoDialInterval)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = AutoDialler
|
|
@@ -94,9 +94,7 @@ class ConnectionManager extends EventEmitter {
|
|
|
94
94
|
|
|
95
95
|
this._started = false
|
|
96
96
|
this._timer = null
|
|
97
|
-
this._autoDialTimeout = null
|
|
98
97
|
this._checkMetrics = this._checkMetrics.bind(this)
|
|
99
|
-
this._autoDial = this._autoDial.bind(this)
|
|
100
98
|
|
|
101
99
|
this._latencyMonitor = new LatencyMonitor({
|
|
102
100
|
latencyCheckIntervalMs: this._options.pollInterval,
|
|
@@ -128,8 +126,6 @@ class ConnectionManager extends EventEmitter {
|
|
|
128
126
|
|
|
129
127
|
this._started = true
|
|
130
128
|
log('started')
|
|
131
|
-
|
|
132
|
-
this._options.autoDial && this._autoDial()
|
|
133
129
|
}
|
|
134
130
|
|
|
135
131
|
/**
|
|
@@ -138,7 +134,6 @@ class ConnectionManager extends EventEmitter {
|
|
|
138
134
|
* @async
|
|
139
135
|
*/
|
|
140
136
|
async stop () {
|
|
141
|
-
this._autoDialTimeout && this._autoDialTimeout.clear()
|
|
142
137
|
this._timer && this._timer.clear()
|
|
143
138
|
|
|
144
139
|
this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
|
|
@@ -312,53 +307,6 @@ class ConnectionManager extends EventEmitter {
|
|
|
312
307
|
}
|
|
313
308
|
}
|
|
314
309
|
|
|
315
|
-
/**
|
|
316
|
-
* Proactively tries to connect to known peers stored in the PeerStore.
|
|
317
|
-
* It will keep the number of connections below the upper limit and sort
|
|
318
|
-
* the peers to connect based on wether we know their keys and protocols.
|
|
319
|
-
*
|
|
320
|
-
* @async
|
|
321
|
-
* @private
|
|
322
|
-
*/
|
|
323
|
-
async _autoDial () {
|
|
324
|
-
const minConnections = this._options.minConnections
|
|
325
|
-
|
|
326
|
-
// Already has enough connections
|
|
327
|
-
if (this.size >= minConnections) {
|
|
328
|
-
this._autoDialTimeout = retimer(this._autoDial, this._options.autoDialInterval)
|
|
329
|
-
return
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Sort peers on wether we know protocols of public keys for them
|
|
333
|
-
const peers = Array.from(this._libp2p.peerStore.peers.values())
|
|
334
|
-
.sort((a, b) => {
|
|
335
|
-
if (b.protocols && b.protocols.length && (!a.protocols || !a.protocols.length)) {
|
|
336
|
-
return 1
|
|
337
|
-
} else if (b.id.pubKey && !a.id.pubKey) {
|
|
338
|
-
return 1
|
|
339
|
-
}
|
|
340
|
-
return -1
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
for (let i = 0; i < peers.length && this.size < minConnections; i++) {
|
|
344
|
-
if (!this.get(peers[i].id)) {
|
|
345
|
-
log('connecting to a peerStore stored peer %s', peers[i].id.toB58String())
|
|
346
|
-
try {
|
|
347
|
-
await this._libp2p.dialer.connectToPeer(peers[i].id)
|
|
348
|
-
|
|
349
|
-
// Connection Manager was stopped
|
|
350
|
-
if (!this._started) {
|
|
351
|
-
return
|
|
352
|
-
}
|
|
353
|
-
} catch (/** @type {any} */ err) {
|
|
354
|
-
log.error('could not connect to peerStore stored peer', err)
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
this._autoDialTimeout = retimer(this._autoDial, this._options.autoDialInterval)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
310
|
/**
|
|
363
311
|
* If we have more connections than our maximum, close a connection
|
|
364
312
|
* to the lowest valued peer.
|
|
@@ -54,7 +54,7 @@ class ContentRouting {
|
|
|
54
54
|
*/
|
|
55
55
|
async * findProviders (key, options = {}) {
|
|
56
56
|
if (!this.routers.length) {
|
|
57
|
-
throw errCode(new Error('No content this.routers available'),
|
|
57
|
+
throw errCode(new Error('No content this.routers available'), codes.ERR_NO_ROUTERS_AVAILABLE)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
yield * pipe(
|
|
@@ -77,7 +77,7 @@ class ContentRouting {
|
|
|
77
77
|
*/
|
|
78
78
|
async provide (key) {
|
|
79
79
|
if (!this.routers.length) {
|
|
80
|
-
throw errCode(new Error('No content routers available'),
|
|
80
|
+
throw errCode(new Error('No content routers available'), codes.ERR_NO_ROUTERS_AVAILABLE)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
await Promise.all(this.routers.map((router) => router.provide(key)))
|
|
@@ -27,8 +27,12 @@ class DHTPeerRouting {
|
|
|
27
27
|
*/
|
|
28
28
|
async findPeer (peerId, options = {}) {
|
|
29
29
|
for await (const event of this._dht.findPeer(peerId, options)) {
|
|
30
|
-
if (event.name === '
|
|
31
|
-
|
|
30
|
+
if (event.name === 'PEER_RESPONSE') {
|
|
31
|
+
const peer = event.closer.find(peerData => peerData.id.equals(peerId))
|
|
32
|
+
|
|
33
|
+
if (peer) {
|
|
34
|
+
return peer
|
|
35
|
+
}
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const errCode = require('err-code')
|
|
4
|
-
const AbortController = require('abort-controller').default
|
|
5
4
|
const { anySignal } = require('any-signal')
|
|
6
5
|
// @ts-ignore p-fifo does not export types
|
|
7
6
|
const FIFO = require('p-fifo')
|
|
8
7
|
const pAny = require('p-any')
|
|
8
|
+
// @ts-expect-error setMaxListeners is missing from the types
|
|
9
|
+
const { setMaxListeners } = require('events')
|
|
10
|
+
const { codes } = require('../errors')
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
|
@@ -54,12 +56,17 @@ class DialRequest {
|
|
|
54
56
|
const tokens = this.dialer.getTokens(this.addrs.length)
|
|
55
57
|
// If no tokens are available, throw
|
|
56
58
|
if (tokens.length < 1) {
|
|
57
|
-
throw errCode(new Error('No dial tokens available'),
|
|
59
|
+
throw errCode(new Error('No dial tokens available'), codes.ERR_NO_DIAL_TOKENS)
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const tokenHolder = new FIFO()
|
|
61
63
|
tokens.forEach(token => tokenHolder.push(token))
|
|
62
|
-
const dialAbortControllers = this.addrs.map(() =>
|
|
64
|
+
const dialAbortControllers = this.addrs.map(() => {
|
|
65
|
+
const controller = new AbortController()
|
|
66
|
+
setMaxListeners && setMaxListeners(Infinity, controller.signal)
|
|
67
|
+
|
|
68
|
+
return controller
|
|
69
|
+
})
|
|
63
70
|
let completedDials = 0
|
|
64
71
|
|
|
65
72
|
try {
|
package/src/dialer/index.js
CHANGED
|
@@ -6,8 +6,7 @@ const log = Object.assign(debug('libp2p:dialer'), {
|
|
|
6
6
|
})
|
|
7
7
|
const errCode = require('err-code')
|
|
8
8
|
const { Multiaddr } = require('multiaddr')
|
|
9
|
-
|
|
10
|
-
const TimeoutController = require('timeout-abort-controller')
|
|
9
|
+
const { TimeoutController } = require('timeout-abort-controller')
|
|
11
10
|
const { AbortError } = require('abortable-iterator')
|
|
12
11
|
const { anySignal } = require('any-signal')
|
|
13
12
|
|
|
@@ -156,14 +155,16 @@ class Dialer {
|
|
|
156
155
|
this._pendingDialTargets.set(id, { resolve, reject })
|
|
157
156
|
})
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this._pendingDialTargets.delete(id)
|
|
158
|
+
try {
|
|
159
|
+
const dialTarget = await Promise.race([
|
|
160
|
+
this._createDialTarget(peer),
|
|
161
|
+
cancellablePromise
|
|
162
|
+
])
|
|
165
163
|
|
|
166
|
-
|
|
164
|
+
return dialTarget
|
|
165
|
+
} finally {
|
|
166
|
+
this._pendingDialTargets.delete(id)
|
|
167
|
+
}
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
/**
|
package/src/errors.js
CHANGED
|
@@ -36,5 +36,29 @@ exports.codes = {
|
|
|
36
36
|
ERR_TRANSPORT_DIAL_FAILED: 'ERR_TRANSPORT_DIAL_FAILED',
|
|
37
37
|
ERR_UNSUPPORTED_PROTOCOL: 'ERR_UNSUPPORTED_PROTOCOL',
|
|
38
38
|
ERR_INVALID_MULTIADDR: 'ERR_INVALID_MULTIADDR',
|
|
39
|
-
ERR_SIGNATURE_NOT_VALID: 'ERR_SIGNATURE_NOT_VALID'
|
|
39
|
+
ERR_SIGNATURE_NOT_VALID: 'ERR_SIGNATURE_NOT_VALID',
|
|
40
|
+
ERR_FIND_SELF: 'ERR_FIND_SELF',
|
|
41
|
+
ERR_NO_ROUTERS_AVAILABLE: 'ERR_NO_ROUTERS_AVAILABLE',
|
|
42
|
+
ERR_CONNECTION_NOT_MULTIPLEXED: 'ERR_CONNECTION_NOT_MULTIPLEXED',
|
|
43
|
+
ERR_NO_DIAL_TOKENS: 'ERR_NO_DIAL_TOKENS',
|
|
44
|
+
ERR_KEYCHAIN_REQUIRED: 'ERR_KEYCHAIN_REQUIRED',
|
|
45
|
+
ERR_INVALID_CMS: 'ERR_INVALID_CMS',
|
|
46
|
+
ERR_MISSING_KEYS: 'ERR_MISSING_KEYS',
|
|
47
|
+
ERR_NO_KEY: 'ERR_NO_KEY',
|
|
48
|
+
ERR_INVALID_KEY_NAME: 'ERR_INVALID_KEY_NAME',
|
|
49
|
+
ERR_INVALID_KEY_TYPE: 'ERR_INVALID_KEY_TYPE',
|
|
50
|
+
ERR_KEY_ALREADY_EXISTS: 'ERR_KEY_ALREADY_EXISTS',
|
|
51
|
+
ERR_INVALID_KEY_SIZE: 'ERR_INVALID_KEY_SIZE',
|
|
52
|
+
ERR_KEY_NOT_FOUND: 'ERR_KEY_NOT_FOUND',
|
|
53
|
+
ERR_OLD_KEY_NAME_INVALID: 'ERR_OLD_KEY_NAME_INVALID',
|
|
54
|
+
ERR_NEW_KEY_NAME_INVALID: 'ERR_NEW_KEY_NAME_INVALID',
|
|
55
|
+
ERR_PASSWORD_REQUIRED: 'ERR_PASSWORD_REQUIRED',
|
|
56
|
+
ERR_PEM_REQUIRED: 'ERR_PEM_REQUIRED',
|
|
57
|
+
ERR_CANNOT_READ_KEY: 'ERR_CANNOT_READ_KEY',
|
|
58
|
+
ERR_MISSING_PRIVATE_KEY: 'ERR_MISSING_PRIVATE_KEY',
|
|
59
|
+
ERR_INVALID_OLD_PASS_TYPE: 'ERR_INVALID_OLD_PASS_TYPE',
|
|
60
|
+
ERR_INVALID_NEW_PASS_TYPE: 'ERR_INVALID_NEW_PASS_TYPE',
|
|
61
|
+
ERR_INVALID_PASS_LENGTH: 'ERR_INVALID_PASS_LENGTH',
|
|
62
|
+
ERR_NOT_IMPLEMENTED: 'ERR_NOT_IMPLEMENTED',
|
|
63
|
+
ERR_WRONG_PING_ACK: 'ERR_WRONG_PING_ACK'
|
|
40
64
|
}
|
package/src/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const { codes, messages } = require('./errors')
|
|
|
18
18
|
|
|
19
19
|
const AddressManager = require('./address-manager')
|
|
20
20
|
const ConnectionManager = require('./connection-manager')
|
|
21
|
+
const AutoDialler = require('./connection-manager/auto-dialler')
|
|
21
22
|
const Circuit = require('./circuit/transport')
|
|
22
23
|
const Relay = require('./circuit')
|
|
23
24
|
const Dialer = require('./dialer')
|
|
@@ -55,16 +56,9 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
|
|
55
56
|
* @property {MuxedStream} stream
|
|
56
57
|
* @property {string} protocol
|
|
57
58
|
*
|
|
58
|
-
* @typedef {Object} RandomWalkOptions
|
|
59
|
-
* @property {boolean} [enabled = false]
|
|
60
|
-
* @property {number} [queriesPerPeriod = 1]
|
|
61
|
-
* @property {number} [interval = 300e3]
|
|
62
|
-
* @property {number} [timeout = 10e3]
|
|
63
|
-
*
|
|
64
59
|
* @typedef {Object} DhtOptions
|
|
65
60
|
* @property {boolean} [enabled = false]
|
|
66
61
|
* @property {number} [kBucketSize = 20]
|
|
67
|
-
* @property {RandomWalkOptions} [randomWalk]
|
|
68
62
|
* @property {boolean} [clientMode]
|
|
69
63
|
* @property {import('libp2p-interfaces/src/types').DhtSelectors} [selectors]
|
|
70
64
|
* @property {import('libp2p-interfaces/src/types').DhtValidators} [validators]
|
|
@@ -193,9 +187,13 @@ class Libp2p extends EventEmitter {
|
|
|
193
187
|
|
|
194
188
|
// Create the Connection Manager
|
|
195
189
|
this.connectionManager = new ConnectionManager(this, {
|
|
196
|
-
autoDial: this._config.peerDiscovery.autoDial,
|
|
197
190
|
...this._options.connectionManager
|
|
198
191
|
})
|
|
192
|
+
this._autodialler = new AutoDialler(this, {
|
|
193
|
+
enabled: this._config.peerDiscovery.autoDial,
|
|
194
|
+
minConnections: this._options.connectionManager.minConnections,
|
|
195
|
+
autoDialInterval: this._options.connectionManager.autoDialInterval
|
|
196
|
+
})
|
|
199
197
|
|
|
200
198
|
// Create Metrics
|
|
201
199
|
if (this._options.metrics.enabled) {
|
|
@@ -380,6 +378,8 @@ class Libp2p extends EventEmitter {
|
|
|
380
378
|
|
|
381
379
|
this.relay && this.relay.stop()
|
|
382
380
|
this.peerRouting.stop()
|
|
381
|
+
this._autodialler.stop()
|
|
382
|
+
await (this._dht && this._dht.stop())
|
|
383
383
|
|
|
384
384
|
for (const service of this._discovery.values()) {
|
|
385
385
|
service.removeListener('peer', this._onDiscoveryPeer)
|
|
@@ -394,7 +394,6 @@ class Libp2p extends EventEmitter {
|
|
|
394
394
|
|
|
395
395
|
await Promise.all([
|
|
396
396
|
this.pubsub && this.pubsub.stop(),
|
|
397
|
-
this._dht && this._dht.stop(),
|
|
398
397
|
this.metrics && this.metrics.stop()
|
|
399
398
|
])
|
|
400
399
|
|
|
@@ -650,6 +649,7 @@ class Libp2p extends EventEmitter {
|
|
|
650
649
|
}
|
|
651
650
|
|
|
652
651
|
this.connectionManager.start()
|
|
652
|
+
this._autodialler.start()
|
|
653
653
|
|
|
654
654
|
// Peer discovery
|
|
655
655
|
await this._setupPeerDiscovery()
|
package/src/keychain/cms.js
CHANGED
|
@@ -10,6 +10,7 @@ const { certificateForKey, findAsync } = require('./util')
|
|
|
10
10
|
const errcode = require('err-code')
|
|
11
11
|
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
|
12
12
|
const { toString: uint8ArrayToString } = require('uint8arrays/to-string')
|
|
13
|
+
const { codes } = require('../errors')
|
|
13
14
|
|
|
14
15
|
const privates = new WeakMap()
|
|
15
16
|
|
|
@@ -31,7 +32,7 @@ class CMS {
|
|
|
31
32
|
*/
|
|
32
33
|
constructor (keychain, dek) {
|
|
33
34
|
if (!keychain) {
|
|
34
|
-
throw errcode(new Error('keychain is required'),
|
|
35
|
+
throw errcode(new Error('keychain is required'), codes.ERR_KEYCHAIN_REQUIRED)
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
this.keychain = keychain
|
|
@@ -49,7 +50,7 @@ class CMS {
|
|
|
49
50
|
*/
|
|
50
51
|
async encrypt (name, plain) {
|
|
51
52
|
if (!(plain instanceof Uint8Array)) {
|
|
52
|
-
throw errcode(new Error('Plain data must be a Uint8Array'),
|
|
53
|
+
throw errcode(new Error('Plain data must be a Uint8Array'), codes.ERR_INVALID_PARAMETERS)
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
const key = await this.keychain.findKeyByName(name)
|
|
@@ -81,7 +82,7 @@ class CMS {
|
|
|
81
82
|
*/
|
|
82
83
|
async decrypt (cmsData) {
|
|
83
84
|
if (!(cmsData instanceof Uint8Array)) {
|
|
84
|
-
throw errcode(new Error('CMS data is required'),
|
|
85
|
+
throw errcode(new Error('CMS data is required'), codes.ERR_INVALID_PARAMETERS)
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
let cms
|
|
@@ -91,7 +92,7 @@ class CMS {
|
|
|
91
92
|
// @ts-ignore not defined
|
|
92
93
|
cms = forge.pkcs7.messageFromAsn1(obj)
|
|
93
94
|
} catch (/** @type {any} */ err) {
|
|
94
|
-
throw errcode(new Error('Invalid CMS: ' + err.message),
|
|
95
|
+
throw errcode(new Error('Invalid CMS: ' + err.message), codes.ERR_INVALID_CMS)
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
// Find a recipient whose key we hold. We only deal with recipient certs
|
|
@@ -123,7 +124,7 @@ class CMS {
|
|
|
123
124
|
if (!r) {
|
|
124
125
|
// @ts-ignore cms types not defined
|
|
125
126
|
const missingKeys = recipients.map(r => r.keyId)
|
|
126
|
-
throw errcode(new Error('Decryption needs one of the key(s): ' + missingKeys.join(', ')),
|
|
127
|
+
throw errcode(new Error('Decryption needs one of the key(s): ' + missingKeys.join(', ')), codes.ERR_MISSING_KEYS, {
|
|
127
128
|
missingKeys
|
|
128
129
|
})
|
|
129
130
|
}
|
|
@@ -131,7 +132,7 @@ class CMS {
|
|
|
131
132
|
const key = await this.keychain.findKeyById(r.keyId)
|
|
132
133
|
|
|
133
134
|
if (!key) {
|
|
134
|
-
throw errcode(new Error('No key available to decrypto'),
|
|
135
|
+
throw errcode(new Error('No key available to decrypto'), codes.ERR_NO_KEY)
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
const pem = await this.keychain._getPrivateKey(key.name)
|
package/src/keychain/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const crypto = require('libp2p-crypto')
|
|
|
10
10
|
const { Key } = require('interface-datastore/key')
|
|
11
11
|
const CMS = require('./cms')
|
|
12
12
|
const errcode = require('err-code')
|
|
13
|
+
const { codes } = require('../errors')
|
|
13
14
|
const { toString: uint8ArrayToString } = require('uint8arrays/to-string')
|
|
14
15
|
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
|
15
16
|
|
|
@@ -210,21 +211,21 @@ class Keychain {
|
|
|
210
211
|
const self = this
|
|
211
212
|
|
|
212
213
|
if (!validateKeyName(name) || name === 'self') {
|
|
213
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
214
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
if (typeof type !== 'string') {
|
|
217
|
-
return throwDelayed(errcode(new Error(`Invalid key type '${type}'`),
|
|
218
|
+
return throwDelayed(errcode(new Error(`Invalid key type '${type}'`), codes.ERR_INVALID_KEY_TYPE))
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
const dsname = DsName(name)
|
|
221
222
|
const exists = await self.store.has(dsname)
|
|
222
|
-
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`),
|
|
223
|
+
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`), codes.ERR_KEY_ALREADY_EXISTS))
|
|
223
224
|
|
|
224
225
|
switch (type.toLowerCase()) {
|
|
225
226
|
case 'rsa':
|
|
226
227
|
if (!Number.isSafeInteger(size) || size < 2048) {
|
|
227
|
-
return throwDelayed(errcode(new Error(`Invalid RSA key size ${size}`),
|
|
228
|
+
return throwDelayed(errcode(new Error(`Invalid RSA key size ${size}`), codes.ERR_INVALID_KEY_SIZE))
|
|
228
229
|
}
|
|
229
230
|
break
|
|
230
231
|
default:
|
|
@@ -297,7 +298,7 @@ class Keychain {
|
|
|
297
298
|
*/
|
|
298
299
|
async findKeyByName (name) {
|
|
299
300
|
if (!validateKeyName(name)) {
|
|
300
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
301
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
301
302
|
}
|
|
302
303
|
|
|
303
304
|
const dsname = DsInfoName(name)
|
|
@@ -305,7 +306,7 @@ class Keychain {
|
|
|
305
306
|
const res = await this.store.get(dsname)
|
|
306
307
|
return JSON.parse(uint8ArrayToString(res))
|
|
307
308
|
} catch (/** @type {any} */ err) {
|
|
308
|
-
return throwDelayed(errcode(new Error(`Key '${name}' does not exist. ${err.message}`),
|
|
309
|
+
return throwDelayed(errcode(new Error(`Key '${name}' does not exist. ${err.message}`), codes.ERR_KEY_NOT_FOUND))
|
|
309
310
|
}
|
|
310
311
|
}
|
|
311
312
|
|
|
@@ -318,7 +319,7 @@ class Keychain {
|
|
|
318
319
|
async removeKey (name) {
|
|
319
320
|
const self = this
|
|
320
321
|
if (!validateKeyName(name) || name === 'self') {
|
|
321
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
322
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
322
323
|
}
|
|
323
324
|
const dsname = DsName(name)
|
|
324
325
|
const keyInfo = await self.findKeyByName(name)
|
|
@@ -339,10 +340,10 @@ class Keychain {
|
|
|
339
340
|
async renameKey (oldName, newName) {
|
|
340
341
|
const self = this
|
|
341
342
|
if (!validateKeyName(oldName) || oldName === 'self') {
|
|
342
|
-
return throwDelayed(errcode(new Error(`Invalid old key name '${oldName}'`),
|
|
343
|
+
return throwDelayed(errcode(new Error(`Invalid old key name '${oldName}'`), codes.ERR_OLD_KEY_NAME_INVALID))
|
|
343
344
|
}
|
|
344
345
|
if (!validateKeyName(newName) || newName === 'self') {
|
|
345
|
-
return throwDelayed(errcode(new Error(`Invalid new key name '${newName}'`),
|
|
346
|
+
return throwDelayed(errcode(new Error(`Invalid new key name '${newName}'`), codes.ERR_NEW_KEY_NAME_INVALID))
|
|
346
347
|
}
|
|
347
348
|
const oldDsname = DsName(oldName)
|
|
348
349
|
const newDsname = DsName(newName)
|
|
@@ -350,7 +351,7 @@ class Keychain {
|
|
|
350
351
|
const newInfoName = DsInfoName(newName)
|
|
351
352
|
|
|
352
353
|
const exists = await self.store.has(newDsname)
|
|
353
|
-
if (exists) return throwDelayed(errcode(new Error(`Key '${newName}' already exists`),
|
|
354
|
+
if (exists) return throwDelayed(errcode(new Error(`Key '${newName}' already exists`), codes.ERR_KEY_ALREADY_EXISTS))
|
|
354
355
|
|
|
355
356
|
try {
|
|
356
357
|
const pem = await self.store.get(oldDsname)
|
|
@@ -379,10 +380,10 @@ class Keychain {
|
|
|
379
380
|
*/
|
|
380
381
|
async exportKey (name, password) {
|
|
381
382
|
if (!validateKeyName(name)) {
|
|
382
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
383
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
383
384
|
}
|
|
384
385
|
if (!password) {
|
|
385
|
-
return throwDelayed(errcode(new Error('Password is required'),
|
|
386
|
+
return throwDelayed(errcode(new Error('Password is required'), codes.ERR_PASSWORD_REQUIRED))
|
|
386
387
|
}
|
|
387
388
|
|
|
388
389
|
const dsname = DsName(name)
|
|
@@ -409,20 +410,20 @@ class Keychain {
|
|
|
409
410
|
async importKey (name, pem, password) {
|
|
410
411
|
const self = this
|
|
411
412
|
if (!validateKeyName(name) || name === 'self') {
|
|
412
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
413
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
413
414
|
}
|
|
414
415
|
if (!pem) {
|
|
415
|
-
return throwDelayed(errcode(new Error('PEM encoded key is required'),
|
|
416
|
+
return throwDelayed(errcode(new Error('PEM encoded key is required'), codes.ERR_PEM_REQUIRED))
|
|
416
417
|
}
|
|
417
418
|
const dsname = DsName(name)
|
|
418
419
|
const exists = await self.store.has(dsname)
|
|
419
|
-
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`),
|
|
420
|
+
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`), codes.ERR_KEY_ALREADY_EXISTS))
|
|
420
421
|
|
|
421
422
|
let privateKey
|
|
422
423
|
try {
|
|
423
424
|
privateKey = await crypto.keys.import(pem, password)
|
|
424
425
|
} catch (/** @type {any} */ err) {
|
|
425
|
-
return throwDelayed(errcode(new Error('Cannot read the key, most likely the password is wrong'),
|
|
426
|
+
return throwDelayed(errcode(new Error('Cannot read the key, most likely the password is wrong'), codes.ERR_CANNOT_READ_KEY))
|
|
426
427
|
}
|
|
427
428
|
|
|
428
429
|
let kid
|
|
@@ -457,16 +458,16 @@ class Keychain {
|
|
|
457
458
|
async importPeer (name, peer) {
|
|
458
459
|
const self = this
|
|
459
460
|
if (!validateKeyName(name)) {
|
|
460
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
461
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
461
462
|
}
|
|
462
463
|
if (!peer || !peer.privKey) {
|
|
463
|
-
return throwDelayed(errcode(new Error('Peer.privKey is required'),
|
|
464
|
+
return throwDelayed(errcode(new Error('Peer.privKey is required'), codes.ERR_MISSING_PRIVATE_KEY))
|
|
464
465
|
}
|
|
465
466
|
|
|
466
467
|
const privateKey = peer.privKey
|
|
467
468
|
const dsname = DsName(name)
|
|
468
469
|
const exists = await self.store.has(dsname)
|
|
469
|
-
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`),
|
|
470
|
+
if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`), codes.ERR_KEY_ALREADY_EXISTS))
|
|
470
471
|
|
|
471
472
|
try {
|
|
472
473
|
const kid = await privateKey.id()
|
|
@@ -495,7 +496,7 @@ class Keychain {
|
|
|
495
496
|
*/
|
|
496
497
|
async _getPrivateKey (name) {
|
|
497
498
|
if (!validateKeyName(name)) {
|
|
498
|
-
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`),
|
|
499
|
+
return throwDelayed(errcode(new Error(`Invalid key name '${name}'`), codes.ERR_INVALID_KEY_NAME))
|
|
499
500
|
}
|
|
500
501
|
|
|
501
502
|
try {
|
|
@@ -503,7 +504,7 @@ class Keychain {
|
|
|
503
504
|
const res = await this.store.get(dsname)
|
|
504
505
|
return uint8ArrayToString(res)
|
|
505
506
|
} catch (/** @type {any} */ err) {
|
|
506
|
-
return throwDelayed(errcode(new Error(`Key '${name}' does not exist. ${err.message}`),
|
|
507
|
+
return throwDelayed(errcode(new Error(`Key '${name}' does not exist. ${err.message}`), codes.ERR_KEY_NOT_FOUND))
|
|
507
508
|
}
|
|
508
509
|
}
|
|
509
510
|
|
|
@@ -515,13 +516,13 @@ class Keychain {
|
|
|
515
516
|
*/
|
|
516
517
|
async rotateKeychainPass (oldPass, newPass) {
|
|
517
518
|
if (typeof oldPass !== 'string') {
|
|
518
|
-
return throwDelayed(errcode(new Error(`Invalid old pass type '${typeof oldPass}'`),
|
|
519
|
+
return throwDelayed(errcode(new Error(`Invalid old pass type '${typeof oldPass}'`), codes.ERR_INVALID_OLD_PASS_TYPE))
|
|
519
520
|
}
|
|
520
521
|
if (typeof newPass !== 'string') {
|
|
521
|
-
return throwDelayed(errcode(new Error(`Invalid new pass type '${typeof newPass}'`),
|
|
522
|
+
return throwDelayed(errcode(new Error(`Invalid new pass type '${typeof newPass}'`), codes.ERR_INVALID_NEW_PASS_TYPE))
|
|
522
523
|
}
|
|
523
524
|
if (newPass.length < 20) {
|
|
524
|
-
return throwDelayed(errcode(new Error(`Invalid pass length ${newPass.length}`),
|
|
525
|
+
return throwDelayed(errcode(new Error(`Invalid pass length ${newPass.length}`), codes.ERR_INVALID_PASS_LENGTH))
|
|
525
526
|
}
|
|
526
527
|
log('recreating keychain')
|
|
527
528
|
const oldDek = privates.get(this).dek
|
package/src/nat-manager.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
// @ts-ignore nat-api does not export types
|
|
4
|
-
const NatAPI = require('
|
|
4
|
+
const NatAPI = require('nat-api')
|
|
5
5
|
const debug = require('debug')
|
|
6
6
|
const { promisify } = require('es6-promisify')
|
|
7
7
|
const { Multiaddr } = require('multiaddr')
|