mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 02:22:14 +00:00
feat: connection gater (#1142)
Port of https://github.com/libp2p/go-libp2p-core/blob/master/connmgr/gater.go Adds a new configuration key `connectionGater` which allows denying the dialing of certain peers, individual multiaddrs and the creation of connections at certain points in the connection flow. Fixes: https://github.com/libp2p/js-libp2p/issues/175 Refs: https://github.com/libp2p/js-libp2p/issues/744 Refs: https://github.com/libp2p/js-libp2p/issues/769 Co-authored-by: mzdws <8580712+mzdws@user.noreply.gitee.com>
This commit is contained in:
parent
9b22c6e2f9
commit
ff32eba6a0
@ -23,6 +23,9 @@
|
|||||||
- [Setup with Keychain](#setup-with-keychain)
|
- [Setup with Keychain](#setup-with-keychain)
|
||||||
- [Configuring Dialing](#configuring-dialing)
|
- [Configuring Dialing](#configuring-dialing)
|
||||||
- [Configuring Connection Manager](#configuring-connection-manager)
|
- [Configuring Connection Manager](#configuring-connection-manager)
|
||||||
|
- [Configuring Connection Gater](#configuring-connection-gater)
|
||||||
|
- [Outgoing connections](#outgoing-connections)
|
||||||
|
- [Incoming connections](#incoming-connections)
|
||||||
- [Configuring Transport Manager](#configuring-transport-manager)
|
- [Configuring Transport Manager](#configuring-transport-manager)
|
||||||
- [Configuring Metrics](#configuring-metrics)
|
- [Configuring Metrics](#configuring-metrics)
|
||||||
- [Configuring PeerStore](#configuring-peerstore)
|
- [Configuring PeerStore](#configuring-peerstore)
|
||||||
@ -590,6 +593,127 @@ const node = await Libp2p.create({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Configuring Connection Gater
|
||||||
|
|
||||||
|
The Connection Gater allows us to prevent making incoming and outgoing connections to peers and storing
|
||||||
|
multiaddrs in the address book.
|
||||||
|
|
||||||
|
The order in which methods are called is as follows:
|
||||||
|
|
||||||
|
##### Outgoing connections
|
||||||
|
|
||||||
|
1. `connectionGater.denyDialPeer(...)`
|
||||||
|
2. `connectionGater.denyDialMultiaddr(...)`
|
||||||
|
3. `connectionGater.denyOutboundConnection(...)`
|
||||||
|
4. `connectionGater.denyOutboundEncryptedConnection(...)`
|
||||||
|
5. `connectionGater.denyOutboundUpgradedConnection(...)`
|
||||||
|
|
||||||
|
##### Incoming connections
|
||||||
|
|
||||||
|
1. `connectionGater.denyInboundConnection(...)`
|
||||||
|
2. `connectionGater.denyInboundEncryptedConnection(...)`
|
||||||
|
3. `connectionGater.denyInboundUpgradedConnection(...)`
|
||||||
|
|
||||||
|
```js
|
||||||
|
const node = await Libp2p.create({
|
||||||
|
// .. other config
|
||||||
|
connectionGater: {
|
||||||
|
/**
|
||||||
|
* denyDialMultiaddr tests whether we're permitted to Dial the
|
||||||
|
* specified peer.
|
||||||
|
*
|
||||||
|
* This is called by the dialer.connectToPeer implementation before
|
||||||
|
* dialling a peer.
|
||||||
|
*
|
||||||
|
* Return true to prevent dialing the passed peer.
|
||||||
|
*/
|
||||||
|
denyDialPeer: (peerId: PeerId) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyDialMultiaddr tests whether we're permitted to dial the specified
|
||||||
|
* multiaddr for the given peer.
|
||||||
|
*
|
||||||
|
* This is called by the dialer.connectToPeer implementation after it has
|
||||||
|
* resolved the peer's addrs, and prior to dialling each.
|
||||||
|
*
|
||||||
|
* Return true to prevent dialing the passed peer on the passed multiaddr.
|
||||||
|
*/
|
||||||
|
denyDialMultiaddr: (peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundConnection tests whether an incipient inbound connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, or by the transport directly (e.g. QUIC,
|
||||||
|
* Bluetooth), straight after it has accepted a connection from its socket.
|
||||||
|
*
|
||||||
|
* Return true to deny the incoming passed connection.
|
||||||
|
*/
|
||||||
|
denyInboundConnection: (maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundConnection tests whether an incipient outbound connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, or by the transport directly (e.g. QUIC,
|
||||||
|
* Bluetooth), straight after it has created a connection with its socket.
|
||||||
|
*
|
||||||
|
* Return true to deny the incoming passed connection.
|
||||||
|
*/
|
||||||
|
denyOutboundConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundEncryptedConnection tests whether a given connection, now encrypted,
|
||||||
|
* is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, after it has performed the security
|
||||||
|
* handshake, and before it negotiates the muxer, or by the directly by the
|
||||||
|
* transport, at the exact same checkpoint.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed secured connection.
|
||||||
|
*/
|
||||||
|
denyInboundEncryptedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundEncryptedConnection tests whether a given connection, now encrypted,
|
||||||
|
* is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, after it has performed the security
|
||||||
|
* handshake, and before it negotiates the muxer, or by the directly by the
|
||||||
|
* transport, at the exact same checkpoint.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed secured connection.
|
||||||
|
*/
|
||||||
|
denyOutboundEncryptedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundUpgradedConnection tests whether a fully capable connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called after encryption has been negotiated and the connection has been
|
||||||
|
* multiplexed, if a multiplexer is configured.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed upgraded connection.
|
||||||
|
*/
|
||||||
|
denyInboundUpgradedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundUpgradedConnection tests whether a fully capable connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called after encryption has been negotiated and the connection has been
|
||||||
|
* multiplexed, if a multiplexer is configured.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed upgraded connection.
|
||||||
|
*/
|
||||||
|
denyOutboundUpgradedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the address book to filter passed addresses.
|
||||||
|
*
|
||||||
|
* Return true to allow storing the passed multiaddr for the passed peer.
|
||||||
|
*/
|
||||||
|
filterMultiaddrForPeer: (peer: PeerId, multiaddr: Multiaddr) => Promise<boolean>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
#### Configuring Transport Manager
|
#### Configuring Transport Manager
|
||||||
|
|
||||||
The Transport Manager is responsible for managing the libp2p transports life cycle. This includes starting listeners for the provided listen addresses, closing these listeners and dialing using the provided transports. By default, if a libp2p node has a list of multiaddrs for listening on and there are no valid transports for those multiaddrs, libp2p will throw an error on startup and shutdown. However, for some applications it is perfectly acceptable for libp2p nodes to start in dial only mode if all the listen multiaddrs failed. This error tolerance can be enabled as follows:
|
The Transport Manager is responsible for managing the libp2p transports life cycle. This includes starting listeners for the provided listen addresses, closing these listeners and dialing using the provided transports. By default, if a libp2p node has a list of multiaddrs for listening on and there are no valid transports for those multiaddrs, libp2p will throw an error on startup and shutdown. However, for some applications it is perfectly acceptable for libp2p nodes to start in dial only mode if all the listen multiaddrs failed. This error tolerance can be enabled as follows:
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
"it-drain": "^1.0.3",
|
"it-drain": "^1.0.3",
|
||||||
"it-filter": "^1.0.1",
|
"it-filter": "^1.0.1",
|
||||||
"it-first": "^1.0.4",
|
"it-first": "^1.0.4",
|
||||||
|
"it-foreach": "^0.1.1",
|
||||||
"it-handshake": "^2.0.0",
|
"it-handshake": "^2.0.0",
|
||||||
"it-length-prefixed": "^5.0.2",
|
"it-length-prefixed": "^5.0.2",
|
||||||
"it-map": "^1.0.4",
|
"it-map": "^1.0.4",
|
||||||
|
@ -13,6 +13,7 @@ const { FaultTolerance } = require('./transport-manager')
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||||
|
* @typedef {import('./types').ConnectionGater} ConnectionGater
|
||||||
* @typedef {import('.').Libp2pOptions} Libp2pOptions
|
* @typedef {import('.').Libp2pOptions} Libp2pOptions
|
||||||
* @typedef {import('.').constructorOptions} constructorOptions
|
* @typedef {import('.').constructorOptions} constructorOptions
|
||||||
*/
|
*/
|
||||||
@ -27,6 +28,7 @@ const DefaultConfig = {
|
|||||||
connectionManager: {
|
connectionManager: {
|
||||||
minConnections: 25
|
minConnections: 25
|
||||||
},
|
},
|
||||||
|
connectionGater: /** @type {ConnectionGater} */ {},
|
||||||
transportManager: {
|
transportManager: {
|
||||||
faultTolerance: FaultTolerance.FATAL_ALL
|
faultTolerance: FaultTolerance.FATAL_ALL
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const debug = require('debug')
|
const debug = require('debug')
|
||||||
|
const all = require('it-all')
|
||||||
|
const filter = require('it-filter')
|
||||||
|
const { pipe } = require('it-pipe')
|
||||||
const log = Object.assign(debug('libp2p:dialer'), {
|
const log = Object.assign(debug('libp2p:dialer'), {
|
||||||
error: debug('libp2p:dialer:err')
|
error: debug('libp2p:dialer:err')
|
||||||
})
|
})
|
||||||
@ -33,12 +36,14 @@ const METRICS_PENDING_DIAL_TARGETS = 'pending-dial-targets'
|
|||||||
* @typedef {import('../peer-store/types').PeerStore} PeerStore
|
* @typedef {import('../peer-store/types').PeerStore} PeerStore
|
||||||
* @typedef {import('../peer-store/types').Address} Address
|
* @typedef {import('../peer-store/types').Address} Address
|
||||||
* @typedef {import('../transport-manager')} TransportManager
|
* @typedef {import('../transport-manager')} TransportManager
|
||||||
|
* @typedef {import('../types').ConnectionGater} ConnectionGater
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} DialerProperties
|
* @typedef {Object} DialerProperties
|
||||||
* @property {PeerStore} peerStore
|
* @property {PeerStore} peerStore
|
||||||
* @property {TransportManager} transportManager
|
* @property {TransportManager} transportManager
|
||||||
|
* @property {ConnectionGater} connectionGater
|
||||||
*
|
*
|
||||||
* @typedef {(addr:Multiaddr) => Promise<string[]>} Resolver
|
* @typedef {(addr:Multiaddr) => Promise<string[]>} Resolver
|
||||||
*
|
*
|
||||||
@ -70,6 +75,7 @@ class Dialer {
|
|||||||
constructor ({
|
constructor ({
|
||||||
transportManager,
|
transportManager,
|
||||||
peerStore,
|
peerStore,
|
||||||
|
connectionGater,
|
||||||
addressSorter = publicAddressesFirst,
|
addressSorter = publicAddressesFirst,
|
||||||
maxParallelDials = MAX_PARALLEL_DIALS,
|
maxParallelDials = MAX_PARALLEL_DIALS,
|
||||||
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
|
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
|
||||||
@ -78,6 +84,7 @@ class Dialer {
|
|||||||
resolvers = {},
|
resolvers = {},
|
||||||
metrics
|
metrics
|
||||||
}) {
|
}) {
|
||||||
|
this.connectionGater = connectionGater
|
||||||
this.transportManager = transportManager
|
this.transportManager = transportManager
|
||||||
this.peerStore = peerStore
|
this.peerStore = peerStore
|
||||||
this.addressSorter = addressSorter
|
this.addressSorter = addressSorter
|
||||||
@ -136,6 +143,12 @@ class Dialer {
|
|||||||
* @returns {Promise<Connection>}
|
* @returns {Promise<Connection>}
|
||||||
*/
|
*/
|
||||||
async connectToPeer (peer, options = {}) {
|
async connectToPeer (peer, options = {}) {
|
||||||
|
const { id } = getPeer(peer)
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyDialPeer(id)) {
|
||||||
|
throw errCode(new Error('The dial request is blocked by gater.allowDialPeer'), codes.ERR_PEER_DIAL_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
const dialTarget = await this._createCancellableDialTarget(peer)
|
const dialTarget = await this._createCancellableDialTarget(peer)
|
||||||
|
|
||||||
if (!dialTarget.addrs.length) {
|
if (!dialTarget.addrs.length) {
|
||||||
@ -203,7 +216,13 @@ class Dialer {
|
|||||||
await this.peerStore.addressBook.add(id, multiaddrs)
|
await this.peerStore.addressBook.add(id, multiaddrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
let knownAddrs = await this.peerStore.addressBook.getMultiaddrsForPeer(id, this.addressSorter) || []
|
let knownAddrs = await pipe(
|
||||||
|
await this.peerStore.addressBook.getMultiaddrsForPeer(id, this.addressSorter),
|
||||||
|
(source) => filter(source, async (multiaddr) => {
|
||||||
|
return !(await this.connectionGater.denyDialMultiaddr(id, multiaddr))
|
||||||
|
}),
|
||||||
|
(source) => all(source)
|
||||||
|
)
|
||||||
|
|
||||||
// If received a multiaddr to dial, it should be the first to use
|
// If received a multiaddr to dial, it should be the first to use
|
||||||
// But, if we know other multiaddrs for the peer, we should try them too.
|
// But, if we know other multiaddrs for the peer, we should try them too.
|
||||||
|
@ -12,6 +12,8 @@ exports.codes = {
|
|||||||
PUBSUB_NOT_STARTED: 'ERR_PUBSUB_NOT_STARTED',
|
PUBSUB_NOT_STARTED: 'ERR_PUBSUB_NOT_STARTED',
|
||||||
DHT_NOT_STARTED: 'ERR_DHT_NOT_STARTED',
|
DHT_NOT_STARTED: 'ERR_DHT_NOT_STARTED',
|
||||||
CONN_ENCRYPTION_REQUIRED: 'ERR_CONN_ENCRYPTION_REQUIRED',
|
CONN_ENCRYPTION_REQUIRED: 'ERR_CONN_ENCRYPTION_REQUIRED',
|
||||||
|
ERR_PEER_DIAL_INTERCEPTED: 'ERR_PEER_DIAL_INTERCEPTED',
|
||||||
|
ERR_CONNECTION_INTERCEPTED: 'ERR_CONNECTION_INTERCEPTED',
|
||||||
ERR_INVALID_PROTOCOLS_FOR_STREAM: 'ERR_INVALID_PROTOCOLS_FOR_STREAM',
|
ERR_INVALID_PROTOCOLS_FOR_STREAM: 'ERR_INVALID_PROTOCOLS_FOR_STREAM',
|
||||||
ERR_CONNECTION_ENDED: 'ERR_CONNECTION_ENDED',
|
ERR_CONNECTION_ENDED: 'ERR_CONNECTION_ENDED',
|
||||||
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
|
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
|
||||||
|
21
src/index.js
21
src/index.js
@ -48,6 +48,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
|||||||
* @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions
|
* @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions
|
||||||
* @typedef {import('interface-datastore').Datastore} Datastore
|
* @typedef {import('interface-datastore').Datastore} Datastore
|
||||||
* @typedef {import('./pnet')} Protector
|
* @typedef {import('./pnet')} Protector
|
||||||
|
* @typedef {import('./types').ConnectionGater} ConnectionGater
|
||||||
* @typedef {Object} PersistentPeerStoreOptions
|
* @typedef {Object} PersistentPeerStoreOptions
|
||||||
* @property {number} [threshold]
|
* @property {number} [threshold]
|
||||||
*/
|
*/
|
||||||
@ -106,6 +107,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
|||||||
* @property {Libp2pModules} modules libp2p modules to use
|
* @property {Libp2pModules} modules libp2p modules to use
|
||||||
* @property {import('./address-manager').AddressManagerOptions} [addresses]
|
* @property {import('./address-manager').AddressManagerOptions} [addresses]
|
||||||
* @property {import('./connection-manager').ConnectionManagerOptions} [connectionManager]
|
* @property {import('./connection-manager').ConnectionManagerOptions} [connectionManager]
|
||||||
|
* @property {Partial<import('./types').ConnectionGater>} [connectionGater]
|
||||||
* @property {Datastore} [datastore]
|
* @property {Datastore} [datastore]
|
||||||
* @property {import('./dialer').DialerOptions} [dialer]
|
* @property {import('./dialer').DialerOptions} [dialer]
|
||||||
* @property {import('./identify/index').HostProperties} [host] libp2p host
|
* @property {import('./identify/index').HostProperties} [host] libp2p host
|
||||||
@ -172,10 +174,25 @@ class Libp2p extends EventEmitter {
|
|||||||
this.metrics = metrics
|
this.metrics = metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {ConnectionGater} */
|
||||||
|
this.connectionGater = {
|
||||||
|
denyDialPeer: async () => Promise.resolve(false),
|
||||||
|
denyDialMultiaddr: async () => Promise.resolve(false),
|
||||||
|
denyInboundConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundConnection: async () => Promise.resolve(false),
|
||||||
|
denyInboundEncryptedConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundEncryptedConnection: async () => Promise.resolve(false),
|
||||||
|
denyInboundUpgradedConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundUpgradedConnection: async () => Promise.resolve(false),
|
||||||
|
filterMultiaddrForPeer: async () => Promise.resolve(true),
|
||||||
|
...this._options.connectionGater
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {import('./peer-store/types').PeerStore} */
|
/** @type {import('./peer-store/types').PeerStore} */
|
||||||
this.peerStore = new PeerStore({
|
this.peerStore = new PeerStore({
|
||||||
peerId: this.peerId,
|
peerId: this.peerId,
|
||||||
datastore: (this.datastore && this._options.peerStore.persistence) ? this.datastore : new MemoryDatastore()
|
datastore: (this.datastore && this._options.peerStore.persistence) ? this.datastore : new MemoryDatastore(),
|
||||||
|
addressFilter: this.connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
|
|
||||||
// Addresses {listen, announce, noAnnounce}
|
// Addresses {listen, announce, noAnnounce}
|
||||||
@ -220,6 +237,7 @@ class Libp2p extends EventEmitter {
|
|||||||
|
|
||||||
// Setup the Upgrader
|
// Setup the Upgrader
|
||||||
this.upgrader = new Upgrader({
|
this.upgrader = new Upgrader({
|
||||||
|
connectionGater: this.connectionGater,
|
||||||
localPeer: this.peerId,
|
localPeer: this.peerId,
|
||||||
metrics: this.metrics,
|
metrics: this.metrics,
|
||||||
onConnection: (connection) => this.connectionManager.onConnect(connection),
|
onConnection: (connection) => this.connectionManager.onConnect(connection),
|
||||||
@ -262,6 +280,7 @@ class Libp2p extends EventEmitter {
|
|||||||
|
|
||||||
this.dialer = new Dialer({
|
this.dialer = new Dialer({
|
||||||
transportManager: this.transportManager,
|
transportManager: this.transportManager,
|
||||||
|
connectionGater: this.connectionGater,
|
||||||
peerStore: this.peerStore,
|
peerStore: this.peerStore,
|
||||||
metrics: this.metrics,
|
metrics: this.metrics,
|
||||||
...this._options.dialer
|
...this._options.dialer
|
||||||
|
@ -7,6 +7,11 @@ const PeerId = require('peer-id')
|
|||||||
const { codes } = require('../errors')
|
const { codes } = require('../errors')
|
||||||
const PeerRecord = require('../record/peer-record')
|
const PeerRecord = require('../record/peer-record')
|
||||||
const Envelope = require('../record/envelope')
|
const Envelope = require('../record/envelope')
|
||||||
|
const { pipe } = require('it-pipe')
|
||||||
|
const all = require('it-all')
|
||||||
|
const filter = require('it-filter')
|
||||||
|
const map = require('it-map')
|
||||||
|
const each = require('it-foreach')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('./types').PeerStore} PeerStore
|
* @typedef {import('./types').PeerStore} PeerStore
|
||||||
@ -27,10 +32,12 @@ class PeerStoreAddressBook {
|
|||||||
/**
|
/**
|
||||||
* @param {PeerStore["emit"]} emit
|
* @param {PeerStore["emit"]} emit
|
||||||
* @param {import('./types').Store} store
|
* @param {import('./types').Store} store
|
||||||
|
* @param {(peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>} addressFilter
|
||||||
*/
|
*/
|
||||||
constructor (emit, store) {
|
constructor (emit, store, addressFilter) {
|
||||||
this._emit = emit
|
this._emit = emit
|
||||||
this._store = store
|
this._store = store
|
||||||
|
this._addressFilter = addressFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +95,7 @@ class PeerStoreAddressBook {
|
|||||||
// Replace unsigned addresses by the new ones from the record
|
// Replace unsigned addresses by the new ones from the record
|
||||||
// TODO: Once we have ttls for the addresses, we should merge these in
|
// TODO: Once we have ttls for the addresses, we should merge these in
|
||||||
updatedPeer = await this._store.patchOrCreate(peerId, {
|
updatedPeer = await this._store.patchOrCreate(peerId, {
|
||||||
addresses: convertMultiaddrsToAddresses(multiaddrs, true),
|
addresses: await filterMultiaddrs(peerId, multiaddrs, this._addressFilter, true),
|
||||||
peerRecordEnvelope: envelope.marshal()
|
peerRecordEnvelope: envelope.marshal()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -180,6 +187,11 @@ class PeerStoreAddressBook {
|
|||||||
throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
|
throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(multiaddrs)) {
|
||||||
|
log.error('multiaddrs must be an array of Multiaddrs')
|
||||||
|
throw errcode(new Error('multiaddrs must be an array of Multiaddrs'), codes.ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
log('set await write lock')
|
log('set await write lock')
|
||||||
const release = await this._store.lock.writeLock()
|
const release = await this._store.lock.writeLock()
|
||||||
log('set got write lock')
|
log('set got write lock')
|
||||||
@ -188,7 +200,7 @@ class PeerStoreAddressBook {
|
|||||||
let updatedPeer
|
let updatedPeer
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const addresses = convertMultiaddrsToAddresses(multiaddrs)
|
const addresses = await filterMultiaddrs(peerId, multiaddrs, this._addressFilter)
|
||||||
|
|
||||||
// No valid addresses found
|
// No valid addresses found
|
||||||
if (!addresses.length) {
|
if (!addresses.length) {
|
||||||
@ -238,6 +250,11 @@ class PeerStoreAddressBook {
|
|||||||
throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
|
throw errcode(new Error('peerId must be an instance of peer-id'), codes.ERR_INVALID_PARAMETERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(multiaddrs)) {
|
||||||
|
log.error('multiaddrs must be an array of Multiaddrs')
|
||||||
|
throw errcode(new Error('multiaddrs must be an array of Multiaddrs'), codes.ERR_INVALID_PARAMETERS)
|
||||||
|
}
|
||||||
|
|
||||||
log('add await write lock')
|
log('add await write lock')
|
||||||
const release = await this._store.lock.writeLock()
|
const release = await this._store.lock.writeLock()
|
||||||
log('add got write lock')
|
log('add got write lock')
|
||||||
@ -246,7 +263,7 @@ class PeerStoreAddressBook {
|
|||||||
let updatedPeer
|
let updatedPeer
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const addresses = convertMultiaddrsToAddresses(multiaddrs)
|
const addresses = await filterMultiaddrs(peerId, multiaddrs, this._addressFilter)
|
||||||
|
|
||||||
// No valid addresses found
|
// No valid addresses found
|
||||||
if (!addresses.length) {
|
if (!addresses.length) {
|
||||||
@ -337,33 +354,29 @@ class PeerStoreAddressBook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms received multiaddrs into Address.
|
* @param {PeerId} peerId
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Multiaddr[]} multiaddrs
|
* @param {Multiaddr[]} multiaddrs
|
||||||
* @param {boolean} [isCertified]
|
* @param {(peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>} addressFilter
|
||||||
* @returns {Address[]}
|
* @param {boolean} isCertified
|
||||||
*/
|
*/
|
||||||
function convertMultiaddrsToAddresses (multiaddrs, isCertified = false) {
|
function filterMultiaddrs (peerId, multiaddrs, addressFilter, isCertified = false) {
|
||||||
if (!multiaddrs) {
|
return pipe(
|
||||||
log.error('multiaddrs must be provided to store data')
|
multiaddrs,
|
||||||
throw errcode(new Error('multiaddrs must be provided'), codes.ERR_INVALID_PARAMETERS)
|
(source) => each(source, (multiaddr) => {
|
||||||
|
if (!Multiaddr.isMultiaddr(multiaddr)) {
|
||||||
|
log.error('multiaddr must be an instance of Multiaddr')
|
||||||
|
throw errcode(new Error('multiaddr must be an instance of Multiaddr'), codes.ERR_INVALID_PARAMETERS)
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
// create Address for each address with no duplicates
|
(source) => filter(source, (multiaddr) => addressFilter(peerId, multiaddr)),
|
||||||
return Array.from(
|
(source) => map(source, (multiaddr) => {
|
||||||
new Set(multiaddrs.map(ma => ma.toString()))
|
|
||||||
)
|
|
||||||
.map(addr => {
|
|
||||||
try {
|
|
||||||
return {
|
return {
|
||||||
multiaddr: new Multiaddr(addr),
|
multiaddr: new Multiaddr(multiaddr.toString()),
|
||||||
isCertified
|
isCertified
|
||||||
}
|
}
|
||||||
} catch (err) {
|
}),
|
||||||
throw errcode(err, codes.ERR_INVALID_PARAMETERS)
|
(source) => all(source)
|
||||||
}
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PeerStoreAddressBook
|
module.exports = PeerStoreAddressBook
|
||||||
|
@ -12,6 +12,7 @@ const Store = require('./store')
|
|||||||
* @typedef {import('./types').PeerStore} PeerStore
|
* @typedef {import('./types').PeerStore} PeerStore
|
||||||
* @typedef {import('./types').Peer} Peer
|
* @typedef {import('./types').Peer} Peer
|
||||||
* @typedef {import('peer-id')} PeerId
|
* @typedef {import('peer-id')} PeerId
|
||||||
|
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const log = Object.assign(debug('libp2p:peer-store'), {
|
const log = Object.assign(debug('libp2p:peer-store'), {
|
||||||
@ -28,14 +29,15 @@ class DefaultPeerStore extends EventEmitter {
|
|||||||
* @param {object} properties
|
* @param {object} properties
|
||||||
* @param {PeerId} properties.peerId
|
* @param {PeerId} properties.peerId
|
||||||
* @param {import('interface-datastore').Datastore} properties.datastore
|
* @param {import('interface-datastore').Datastore} properties.datastore
|
||||||
|
* @param {(peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>} properties.addressFilter
|
||||||
*/
|
*/
|
||||||
constructor ({ peerId, datastore }) {
|
constructor ({ peerId, datastore, addressFilter }) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this._peerId = peerId
|
this._peerId = peerId
|
||||||
this._store = new Store(datastore)
|
this._store = new Store(datastore)
|
||||||
|
|
||||||
this.addressBook = new AddressBook(this.emit.bind(this), this._store)
|
this.addressBook = new AddressBook(this.emit.bind(this), this._store, addressFilter)
|
||||||
this.keyBook = new KeyBook(this.emit.bind(this), this._store)
|
this.keyBook = new KeyBook(this.emit.bind(this), this._store)
|
||||||
this.metadataBook = new MetadataBook(this.emit.bind(this), this._store)
|
this.metadataBook = new MetadataBook(this.emit.bind(this), this._store)
|
||||||
this.protoBook = new ProtoBook(this.emit.bind(this), this._store)
|
this.protoBook = new ProtoBook(this.emit.bind(this), this._store)
|
||||||
|
@ -100,10 +100,23 @@ class PersistentStore {
|
|||||||
throw errcode(new Error('publicKey bytes do not match peer id publicKey bytes'), codes.ERR_INVALID_PARAMETERS)
|
throw errcode(new Error('publicKey bytes do not match peer id publicKey bytes'), codes.ERR_INVALID_PARAMETERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dedupe addresses
|
||||||
|
const addressSet = new Set()
|
||||||
|
|
||||||
const buf = PeerPB.encode({
|
const buf = PeerPB.encode({
|
||||||
addresses: peer.addresses.sort((a, b) => {
|
addresses: peer.addresses
|
||||||
|
.filter(address => {
|
||||||
|
if (addressSet.has(address.multiaddr.toString())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
addressSet.add(address.multiaddr.toString())
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
.sort((a, b) => {
|
||||||
return a.multiaddr.toString().localeCompare(b.multiaddr.toString())
|
return a.multiaddr.toString().localeCompare(b.multiaddr.toString())
|
||||||
}).map(({ multiaddr, isCertified }) => ({
|
})
|
||||||
|
.map(({ multiaddr, isCertified }) => ({
|
||||||
multiaddr: multiaddr.bytes,
|
multiaddr: multiaddr.bytes,
|
||||||
isCertified
|
isCertified
|
||||||
})),
|
})),
|
||||||
|
98
src/types.ts
Normal file
98
src/types.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import type PeerId from 'peer-id'
|
||||||
|
import type { Multiaddr } from 'multiaddr'
|
||||||
|
import type { MultiaddrConnection } from 'libp2p-interfaces/src/transport/types'
|
||||||
|
|
||||||
|
export interface ConnectionGater {
|
||||||
|
/**
|
||||||
|
* denyDialMultiaddr tests whether we're permitted to Dial the
|
||||||
|
* specified peer.
|
||||||
|
*
|
||||||
|
* This is called by the dialer.connectToPeer implementation before
|
||||||
|
* dialling a peer.
|
||||||
|
*
|
||||||
|
* Return true to prevent dialing the passed peer.
|
||||||
|
*/
|
||||||
|
denyDialPeer: (peerId: PeerId) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyDialMultiaddr tests whether we're permitted to dial the specified
|
||||||
|
* multiaddr for the given peer.
|
||||||
|
*
|
||||||
|
* This is called by the dialer.connectToPeer implementation after it has
|
||||||
|
* resolved the peer's addrs, and prior to dialling each.
|
||||||
|
*
|
||||||
|
* Return true to prevent dialing the passed peer on the passed multiaddr.
|
||||||
|
*/
|
||||||
|
denyDialMultiaddr: (peerId: PeerId, multiaddr: Multiaddr) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundConnection tests whether an incipient inbound connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, or by the transport directly (e.g. QUIC,
|
||||||
|
* Bluetooth), straight after it has accepted a connection from its socket.
|
||||||
|
*
|
||||||
|
* Return true to deny the incoming passed connection.
|
||||||
|
*/
|
||||||
|
denyInboundConnection: (maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundConnection tests whether an incipient outbound connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, or by the transport directly (e.g. QUIC,
|
||||||
|
* Bluetooth), straight after it has created a connection with its socket.
|
||||||
|
*
|
||||||
|
* Return true to deny the incoming passed connection.
|
||||||
|
*/
|
||||||
|
denyOutboundConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundEncryptedConnection tests whether a given connection, now encrypted,
|
||||||
|
* is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, after it has performed the security
|
||||||
|
* handshake, and before it negotiates the muxer, or by the directly by the
|
||||||
|
* transport, at the exact same checkpoint.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed secured connection.
|
||||||
|
*/
|
||||||
|
denyInboundEncryptedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundEncryptedConnection tests whether a given connection, now encrypted,
|
||||||
|
* is allowed.
|
||||||
|
*
|
||||||
|
* This is called by the upgrader, after it has performed the security
|
||||||
|
* handshake, and before it negotiates the muxer, or by the directly by the
|
||||||
|
* transport, at the exact same checkpoint.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed secured connection.
|
||||||
|
*/
|
||||||
|
denyOutboundEncryptedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyInboundUpgradedConnection tests whether a fully capable connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called after encryption has been negotiated and the connection has been
|
||||||
|
* multiplexed, if a multiplexer is configured.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed upgraded connection.
|
||||||
|
*/
|
||||||
|
denyInboundUpgradedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* denyOutboundUpgradedConnection tests whether a fully capable connection is allowed.
|
||||||
|
*
|
||||||
|
* This is called after encryption has been negotiated and the connection has been
|
||||||
|
* multiplexed, if a multiplexer is configured.
|
||||||
|
*
|
||||||
|
* Return true to deny the passed upgraded connection.
|
||||||
|
*/
|
||||||
|
denyOutboundUpgradedConnection: (peerId: PeerId, maConn: MultiaddrConnection) => Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the address book to filter passed addresses.
|
||||||
|
*
|
||||||
|
* Return true to allow storing the passed multiaddr for the passed peer.
|
||||||
|
*/
|
||||||
|
filterMultiaddrForPeer: (peer: PeerId, multiaddr: Multiaddr) => Promise<boolean>
|
||||||
|
}
|
@ -22,6 +22,7 @@ const { codes } = require('./errors')
|
|||||||
* @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto
|
* @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto
|
||||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||||
|
* @typedef {import('./types').ConnectionGater} ConnectionGater
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,6 +36,8 @@ class Upgrader {
|
|||||||
/**
|
/**
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @param {PeerId} options.localPeer
|
* @param {PeerId} options.localPeer
|
||||||
|
* @param {ConnectionGater} options.connectionGater
|
||||||
|
*
|
||||||
* @param {import('./metrics')} [options.metrics]
|
* @param {import('./metrics')} [options.metrics]
|
||||||
* @param {Map<string, Crypto>} [options.cryptos]
|
* @param {Map<string, Crypto>} [options.cryptos]
|
||||||
* @param {Map<string, MuxerFactory>} [options.muxers]
|
* @param {Map<string, MuxerFactory>} [options.muxers]
|
||||||
@ -44,11 +47,13 @@ class Upgrader {
|
|||||||
constructor ({
|
constructor ({
|
||||||
localPeer,
|
localPeer,
|
||||||
metrics,
|
metrics,
|
||||||
|
connectionGater,
|
||||||
cryptos = new Map(),
|
cryptos = new Map(),
|
||||||
muxers = new Map(),
|
muxers = new Map(),
|
||||||
onConnectionEnd = () => {},
|
onConnectionEnd = () => {},
|
||||||
onConnection = () => {}
|
onConnection = () => {}
|
||||||
}) {
|
}) {
|
||||||
|
this.connectionGater = connectionGater
|
||||||
this.localPeer = localPeer
|
this.localPeer = localPeer
|
||||||
this.metrics = metrics
|
this.metrics = metrics
|
||||||
this.cryptos = cryptos
|
this.cryptos = cryptos
|
||||||
@ -76,6 +81,10 @@ class Upgrader {
|
|||||||
let setPeer
|
let setPeer
|
||||||
let proxyPeer
|
let proxyPeer
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyInboundConnection(maConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by gater.acceptConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.metrics) {
|
if (this.metrics) {
|
||||||
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
|
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
|
||||||
const idString = (Math.random() * 1e9).toString(36) + Date.now()
|
const idString = (Math.random() * 1e9).toString(36) + Date.now()
|
||||||
@ -99,6 +108,10 @@ class Upgrader {
|
|||||||
protocol: cryptoProtocol
|
protocol: cryptoProtocol
|
||||||
} = await this._encryptInbound(this.localPeer, protectedConn, this.cryptos))
|
} = await this._encryptInbound(this.localPeer, protectedConn, this.cryptos))
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyInboundEncryptedConnection(remotePeer, encryptedConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
// Multiplex the connection
|
// Multiplex the connection
|
||||||
if (this.muxers.size) {
|
if (this.muxers.size) {
|
||||||
({ stream: upgradedConn, Muxer } = await this._multiplexInbound(encryptedConn, this.muxers))
|
({ stream: upgradedConn, Muxer } = await this._multiplexInbound(encryptedConn, this.muxers))
|
||||||
@ -111,6 +124,10 @@ class Upgrader {
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyInboundUpgradedConnection(remotePeer, encryptedConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.metrics) {
|
if (this.metrics) {
|
||||||
this.metrics.updatePlaceholder(proxyPeer, remotePeer)
|
this.metrics.updatePlaceholder(proxyPeer, remotePeer)
|
||||||
setPeer(remotePeer)
|
setPeer(remotePeer)
|
||||||
@ -143,6 +160,10 @@ class Upgrader {
|
|||||||
|
|
||||||
const remotePeerId = PeerId.createFromB58String(idStr)
|
const remotePeerId = PeerId.createFromB58String(idStr)
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyOutboundConnection(remotePeerId, maConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by connectionGater.denyOutboundConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
let encryptedConn
|
let encryptedConn
|
||||||
let remotePeer
|
let remotePeer
|
||||||
let upgradedConn
|
let upgradedConn
|
||||||
@ -174,6 +195,10 @@ class Upgrader {
|
|||||||
protocol: cryptoProtocol
|
protocol: cryptoProtocol
|
||||||
} = await this._encryptOutbound(this.localPeer, protectedConn, remotePeerId, this.cryptos))
|
} = await this._encryptOutbound(this.localPeer, protectedConn, remotePeerId, this.cryptos))
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyOutboundEncryptedConnection(remotePeer, encryptedConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
// Multiplex the connection
|
// Multiplex the connection
|
||||||
if (this.muxers.size) {
|
if (this.muxers.size) {
|
||||||
({ stream: upgradedConn, Muxer } = await this._multiplexOutbound(encryptedConn, this.muxers))
|
({ stream: upgradedConn, Muxer } = await this._multiplexOutbound(encryptedConn, this.muxers))
|
||||||
@ -186,6 +211,10 @@ class Upgrader {
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await this.connectionGater.denyOutboundUpgradedConnection(remotePeer, encryptedConn)) {
|
||||||
|
throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.metrics) {
|
if (this.metrics) {
|
||||||
this.metrics.updatePlaceholder(proxyPeer, remotePeer)
|
this.metrics.updatePlaceholder(proxyPeer, remotePeer)
|
||||||
setPeer(remotePeer)
|
setPeer(remotePeer)
|
||||||
|
@ -7,12 +7,11 @@ const { CLOSED } = require('libp2p-interfaces/src/connection/status')
|
|||||||
|
|
||||||
const delay = require('delay')
|
const delay = require('delay')
|
||||||
const pWaitFor = require('p-wait-for')
|
const pWaitFor = require('p-wait-for')
|
||||||
|
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
const mockConnection = require('../utils/mockConnection')
|
const mockConnection = require('../utils/mockConnection')
|
||||||
const baseOptions = require('../utils/base-options.browser')
|
const baseOptions = require('../utils/base-options.browser')
|
||||||
|
const { codes } = require('../../src/errors')
|
||||||
const listenMultiaddr = '/ip4/127.0.0.1/tcp/15002/ws'
|
const { Multiaddr } = require('multiaddr')
|
||||||
|
|
||||||
describe('Connection Manager', () => {
|
describe('Connection Manager', () => {
|
||||||
let libp2p
|
let libp2p
|
||||||
@ -27,7 +26,7 @@ describe('Connection Manager', () => {
|
|||||||
config: {
|
config: {
|
||||||
peerId: peerIds[0],
|
peerId: peerIds[0],
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: [listenMultiaddr]
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
},
|
},
|
||||||
modules: baseOptions.modules
|
modules: baseOptions.modules
|
||||||
}
|
}
|
||||||
@ -305,4 +304,230 @@ describe('libp2p.connections', () => {
|
|||||||
await remoteLibp2p.stop()
|
await remoteLibp2p.stop()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('connection gater', () => {
|
||||||
|
let libp2p
|
||||||
|
let remoteLibp2p
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
[remoteLibp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[1],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
remoteLibp2p && await remoteLibp2p.stop()
|
||||||
|
libp2p && await libp2p.stop()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept peer dial', async () => {
|
||||||
|
const denyDialPeer = sinon.stub().returns(true)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyDialPeer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
|
||||||
|
await expect(libp2p.dial(remoteLibp2p.peerId))
|
||||||
|
.to.eventually.be.rejected().with.property('code', codes.ERR_PEER_DIAL_INTERCEPTED)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept addr dial', async () => {
|
||||||
|
const denyDialMultiaddr = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyDialMultiaddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
await libp2p.dialer.connectToPeer(remoteLibp2p.peerId)
|
||||||
|
|
||||||
|
const peerIdMultiaddr = new Multiaddr(`/p2p/${remoteLibp2p.peerId}`)
|
||||||
|
|
||||||
|
for (const multiaddr of remoteLibp2p.multiaddrs) {
|
||||||
|
expect(denyDialMultiaddr.calledWith(remoteLibp2p.peerId, multiaddr.encapsulate(peerIdMultiaddr))).to.be.true()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept multiaddr store during multiaddr dial', async () => {
|
||||||
|
const filterMultiaddrForPeer = sinon.stub().returns(true)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
filterMultiaddrForPeer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const peerIdMultiaddr = new Multiaddr(`/p2p/${remoteLibp2p.peerId}`)
|
||||||
|
const fullMultiaddr = remoteLibp2p.multiaddrs[0].encapsulate(peerIdMultiaddr)
|
||||||
|
|
||||||
|
await libp2p.dialer.connectToPeer(fullMultiaddr)
|
||||||
|
|
||||||
|
expect(filterMultiaddrForPeer.callCount).to.equal(2)
|
||||||
|
|
||||||
|
const args = filterMultiaddrForPeer.getCall(1).args
|
||||||
|
expect(args[0].toString()).to.equal(remoteLibp2p.peerId.toString())
|
||||||
|
expect(args[1].toString()).to.equal(fullMultiaddr.toString())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept accept inbound connection', async () => {
|
||||||
|
const denyInboundConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyInboundConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await remoteLibp2p.peerStore.addressBook.set(libp2p.peerId, libp2p.multiaddrs)
|
||||||
|
await remoteLibp2p.dial(libp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyInboundConnection.called).to.be.true()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept accept outbound connection', async () => {
|
||||||
|
const denyOutboundConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyOutboundConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
await libp2p.dial(remoteLibp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyOutboundConnection.called).to.be.true()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept inbound encrypted', async () => {
|
||||||
|
const denyInboundEncryptedConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyInboundEncryptedConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await remoteLibp2p.peerStore.addressBook.set(libp2p.peerId, libp2p.multiaddrs)
|
||||||
|
await remoteLibp2p.dial(libp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyInboundEncryptedConnection.called).to.be.true()
|
||||||
|
expect(denyInboundEncryptedConnection.getCall(0)).to.have.nested.property('args[0].id').that.equalBytes(remoteLibp2p.peerId.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept outbound encrypted', async () => {
|
||||||
|
const denyOutboundEncryptedConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyOutboundEncryptedConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
await libp2p.dial(remoteLibp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyOutboundEncryptedConnection.called).to.be.true()
|
||||||
|
expect(denyOutboundEncryptedConnection.getCall(0)).to.have.nested.property('args[0].id').that.equalBytes(remoteLibp2p.peerId.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept inbound upgraded', async () => {
|
||||||
|
const denyInboundUpgradedConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyInboundUpgradedConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await remoteLibp2p.peerStore.addressBook.set(libp2p.peerId, libp2p.multiaddrs)
|
||||||
|
await remoteLibp2p.dial(libp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyInboundUpgradedConnection.called).to.be.true()
|
||||||
|
expect(denyInboundUpgradedConnection.getCall(0)).to.have.nested.property('args[0].id').that.equalBytes(remoteLibp2p.peerId.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('intercept outbound upgraded', async () => {
|
||||||
|
const denyOutboundUpgradedConnection = sinon.stub().returns(false)
|
||||||
|
|
||||||
|
;[libp2p] = await peerUtils.createPeer({
|
||||||
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
|
addresses: {
|
||||||
|
listen: ['/ip4/127.0.0.1/tcp/0/ws']
|
||||||
|
},
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
connectionGater: {
|
||||||
|
denyOutboundUpgradedConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await libp2p.peerStore.addressBook.set(remoteLibp2p.peerId, remoteLibp2p.multiaddrs)
|
||||||
|
await libp2p.dial(remoteLibp2p.peerId)
|
||||||
|
|
||||||
|
expect(denyOutboundUpgradedConnection.called).to.be.true()
|
||||||
|
expect(denyOutboundUpgradedConnection.getCall(0)).to.have.nested.property('args[0].id').that.equalBytes(remoteLibp2p.peerId.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -27,7 +27,7 @@ const TransportManager = require('../../src/transport-manager')
|
|||||||
const { codes: ErrorCodes } = require('../../src/errors')
|
const { codes: ErrorCodes } = require('../../src/errors')
|
||||||
const Protector = require('../../src/pnet')
|
const Protector = require('../../src/pnet')
|
||||||
const swarmKeyBuffer = uint8ArrayFromString(require('../fixtures/swarm.key'))
|
const swarmKeyBuffer = uint8ArrayFromString(require('../fixtures/swarm.key'))
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const mockUpgrader = require('../utils/mockUpgrader')
|
const mockUpgrader = require('../utils/mockUpgrader')
|
||||||
const createMockConnection = require('../utils/mockConnection')
|
const createMockConnection = require('../utils/mockConnection')
|
||||||
const Peers = require('../fixtures/peers')
|
const Peers = require('../fixtures/peers')
|
||||||
@ -37,6 +37,7 @@ const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
|||||||
const unsupportedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
|
const unsupportedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
|
||||||
|
|
||||||
describe('Dialing (direct, TCP)', () => {
|
describe('Dialing (direct, TCP)', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let remoteTM
|
let remoteTM
|
||||||
let localTM
|
let localTM
|
||||||
let peerStore
|
let peerStore
|
||||||
@ -50,7 +51,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
|
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId: remotePeerId,
|
peerId: remotePeerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
remoteTM = new TransportManager({
|
remoteTM = new TransportManager({
|
||||||
libp2p: {
|
libp2p: {
|
||||||
@ -67,7 +69,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
peerId: localPeerId,
|
peerId: localPeerId,
|
||||||
peerStore: new PeerStore({
|
peerStore: new PeerStore({
|
||||||
peerId: localPeerId,
|
peerId: localPeerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
upgrader: mockUpgrader
|
upgrader: mockUpgrader
|
||||||
@ -86,7 +89,11 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to connect to a remote node via its multiaddr', async () => {
|
it('should be able to connect to a remote node via its multiaddr', async () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
|
|
||||||
const connection = await dialer.connectToPeer(remoteAddr)
|
const connection = await dialer.connectToPeer(remoteAddr)
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
@ -94,14 +101,22 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to connect to a remote node via its stringified multiaddr', async () => {
|
it('should be able to connect to a remote node via its stringified multiaddr', async () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
const connection = await dialer.connectToPeer(remoteAddr.toString())
|
const connection = await dialer.connectToPeer(remoteAddr.toString())
|
||||||
expect(connection).to.exist()
|
expect(connection).to.exist()
|
||||||
await connection.close()
|
await connection.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to connect to an unsupported multiaddr', async () => {
|
it('should fail to connect to an unsupported multiaddr', async () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
|
|
||||||
await expect(dialer.connectToPeer(unsupportedAddr))
|
await expect(dialer.connectToPeer(unsupportedAddr))
|
||||||
.to.eventually.be.rejectedWith(Error)
|
.to.eventually.be.rejectedWith(Error)
|
||||||
@ -109,7 +124,11 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to connect if peer has no known addresses', async () => {
|
it('should fail to connect if peer has no known addresses', async () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[1])
|
const peerId = await PeerId.createFromJSON(Peers[1])
|
||||||
|
|
||||||
await expect(dialer.connectToPeer(peerId))
|
await expect(dialer.connectToPeer(peerId))
|
||||||
@ -121,11 +140,13 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
const peerStore = new PeerStore({
|
const peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore
|
peerStore,
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
await peerStore.addressBook.set(peerId, remoteTM.getAddrs())
|
await peerStore.addressBook.set(peerId, remoteTM.getAddrs())
|
||||||
@ -143,7 +164,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => [unsupportedAddr]
|
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
|
|
||||||
@ -161,7 +183,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
add: () => { },
|
add: () => { },
|
||||||
getMultiaddrsForPeer: () => [...remoteAddrs, unsupportedAddr]
|
getMultiaddrsForPeer: () => [...remoteAddrs, unsupportedAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
const peerId = await PeerId.createFromJSON(Peers[0])
|
const peerId = await PeerId.createFromJSON(Peers[0])
|
||||||
|
|
||||||
@ -176,7 +199,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
peerStore,
|
peerStore,
|
||||||
dialTimeout: 50
|
dialTimeout: 50,
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
||||||
expect(options.signal).to.exist()
|
expect(options.signal).to.exist()
|
||||||
@ -206,7 +230,8 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => addrs
|
getMultiaddrsForPeer: () => addrs
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(dialer.tokens).to.have.length(2)
|
expect(dialer.tokens).to.have.length(2)
|
||||||
|
@ -21,6 +21,7 @@ const addressSort = require('libp2p-utils/src/address-sort')
|
|||||||
const PeerStore = require('../../src/peer-store')
|
const PeerStore = require('../../src/peer-store')
|
||||||
const TransportManager = require('../../src/transport-manager')
|
const TransportManager = require('../../src/transport-manager')
|
||||||
const Libp2p = require('../../src')
|
const Libp2p = require('../../src')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
|
|
||||||
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||||
const mockUpgrader = require('../utils/mockUpgrader')
|
const mockUpgrader = require('../utils/mockUpgrader')
|
||||||
@ -30,6 +31,7 @@ const unsupportedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1
|
|||||||
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
|
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||||
|
|
||||||
describe('Dialing (direct, WebSockets)', () => {
|
describe('Dialing (direct, WebSockets)', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let localTM
|
let localTM
|
||||||
let peerStore
|
let peerStore
|
||||||
let peerId
|
let peerId
|
||||||
@ -38,7 +40,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
[peerId] = await createPeerId()
|
[peerId] = await createPeerId()
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
localTM = new TransportManager({
|
localTM = new TransportManager({
|
||||||
libp2p: {},
|
libp2p: {},
|
||||||
@ -54,13 +57,21 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should have appropriate defaults', () => {
|
it('should have appropriate defaults', () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
expect(dialer.maxParallelDials).to.equal(Constants.MAX_PARALLEL_DIALS)
|
expect(dialer.maxParallelDials).to.equal(Constants.MAX_PARALLEL_DIALS)
|
||||||
expect(dialer.timeout).to.equal(Constants.DIAL_TIMEOUT)
|
expect(dialer.timeout).to.equal(Constants.DIAL_TIMEOUT)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should limit the number of tokens it provides', () => {
|
it('should limit the number of tokens it provides', () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
const maxPerPeer = Constants.MAX_PER_PEER_DIALS
|
const maxPerPeer = Constants.MAX_PER_PEER_DIALS
|
||||||
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS)
|
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS)
|
||||||
const tokens = dialer.getTokens(maxPerPeer + 1)
|
const tokens = dialer.getTokens(maxPerPeer + 1)
|
||||||
@ -69,14 +80,22 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should not return tokens if non are left', () => {
|
it('should not return tokens if non are left', () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
sinon.stub(dialer, 'tokens').value([])
|
sinon.stub(dialer, 'tokens').value([])
|
||||||
const tokens = dialer.getTokens(1)
|
const tokens = dialer.getTokens(1)
|
||||||
expect(tokens.length).to.equal(0)
|
expect(tokens.length).to.equal(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should NOT be able to return a token twice', () => {
|
it('should NOT be able to return a token twice', () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
const tokens = dialer.getTokens(1)
|
const tokens = dialer.getTokens(1)
|
||||||
expect(tokens).to.have.length(1)
|
expect(tokens).to.have.length(1)
|
||||||
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS - 1)
|
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS - 1)
|
||||||
@ -93,7 +112,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
const connection = await dialer.connectToPeer(remoteAddr)
|
const connection = await dialer.connectToPeer(remoteAddr)
|
||||||
@ -109,7 +129,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
const connection = await dialer.connectToPeer(remoteAddr.toString())
|
const connection = await dialer.connectToPeer(remoteAddr.toString())
|
||||||
@ -118,7 +139,11 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to connect to an unsupported multiaddr', async () => {
|
it('should fail to connect to an unsupported multiaddr', async () => {
|
||||||
const dialer = new Dialer({ transportManager: localTM, peerStore })
|
const dialer = new Dialer({
|
||||||
|
transportManager: localTM,
|
||||||
|
peerStore,
|
||||||
|
connectionGater
|
||||||
|
})
|
||||||
|
|
||||||
await expect(dialer.connectToPeer(unsupportedAddr))
|
await expect(dialer.connectToPeer(unsupportedAddr))
|
||||||
.to.eventually.be.rejectedWith(AggregateError)
|
.to.eventually.be.rejectedWith(AggregateError)
|
||||||
@ -132,7 +157,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
const connection = await dialer.connectToPeer(peerId)
|
const connection = await dialer.connectToPeer(peerId)
|
||||||
@ -148,7 +174,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
set: () => {},
|
set: () => {},
|
||||||
getMultiaddrsForPeer: () => [unsupportedAddr]
|
getMultiaddrsForPeer: () => [unsupportedAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(dialer.connectToPeer(peerId))
|
await expect(dialer.connectToPeer(peerId))
|
||||||
@ -164,7 +191,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
add: () => {},
|
add: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
|
||||||
expect(options.signal).to.exist()
|
expect(options.signal).to.exist()
|
||||||
@ -191,7 +219,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
add: () => { },
|
add: () => { },
|
||||||
getMultiaddrsForPeer: () => Array.from({ length: 11 }, (_, i) => new Multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
|
getMultiaddrsForPeer: () => Array.from({ length: 11 }, (_, i) => new Multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
await expect(dialer.connectToPeer(remoteAddr))
|
await expect(dialer.connectToPeer(remoteAddr))
|
||||||
@ -214,7 +243,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
addressSorter: addressSort.publicAddressesFirst,
|
addressSorter: addressSort.publicAddressesFirst,
|
||||||
maxParallelDials: 3,
|
maxParallelDials: 3,
|
||||||
peerStore
|
peerStore,
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
// Inject data in the AddressBook
|
// Inject data in the AddressBook
|
||||||
@ -240,7 +270,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
set: () => {},
|
set: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(dialer.tokens).to.have.length(2)
|
expect(dialer.tokens).to.have.length(2)
|
||||||
@ -278,7 +309,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
set: () => {},
|
set: () => {},
|
||||||
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
getMultiaddrsForPeer: () => [remoteAddr, remoteAddr, remoteAddr]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(dialer.tokens).to.have.length(2)
|
expect(dialer.tokens).to.have.length(2)
|
||||||
@ -320,7 +352,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
addressBook: {
|
addressBook: {
|
||||||
set: () => { }
|
set: () => { }
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
sinon.stub(dialer, '_createDialTarget').callsFake(() => {
|
sinon.stub(dialer, '_createDialTarget').callsFake(() => {
|
||||||
@ -365,7 +398,8 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
filter: filters.all
|
filter: filters.all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(libp2p.dialer).to.exist()
|
expect(libp2p.dialer).to.exist()
|
||||||
|
@ -23,10 +23,12 @@ const pkg = require('../../package.json')
|
|||||||
const AddressManager = require('../../src/address-manager')
|
const AddressManager = require('../../src/address-manager')
|
||||||
const { MemoryDatastore } = require('datastore-core/memory')
|
const { MemoryDatastore } = require('datastore-core/memory')
|
||||||
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
|
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||||
const listenMaddrs = [new Multiaddr('/ip4/127.0.0.1/tcp/15002/ws')]
|
const listenMaddrs = [new Multiaddr('/ip4/127.0.0.1/tcp/15002/ws')]
|
||||||
|
|
||||||
describe('Identify', () => {
|
describe('Identify', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let localPeer, localPeerStore, localAddressManager
|
let localPeer, localPeerStore, localAddressManager
|
||||||
let remotePeer, remotePeerStore, remoteAddressManager
|
let remotePeer, remotePeerStore, remoteAddressManager
|
||||||
const protocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH]
|
const protocols = [multicodecs.IDENTIFY, multicodecs.IDENTIFY_PUSH]
|
||||||
@ -39,13 +41,15 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
localPeerStore = new PeerStore({
|
localPeerStore = new PeerStore({
|
||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await localPeerStore.protoBook.set(localPeer, protocols)
|
await localPeerStore.protoBook.set(localPeer, protocols)
|
||||||
|
|
||||||
remotePeerStore = new PeerStore({
|
remotePeerStore = new PeerStore({
|
||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await remotePeerStore.protoBook.set(remotePeer, protocols)
|
await remotePeerStore.protoBook.set(remotePeer, protocols)
|
||||||
|
|
||||||
@ -230,7 +234,8 @@ describe('Identify', () => {
|
|||||||
const agentVersion = 'js-project/1.0.0'
|
const agentVersion = 'js-project/1.0.0'
|
||||||
const peerStore = new PeerStore({
|
const peerStore = new PeerStore({
|
||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
|
|
||||||
sinon.spy(peerStore.metadataBook, 'setValue')
|
sinon.spy(peerStore.metadataBook, 'setValue')
|
||||||
@ -272,7 +277,8 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
const localPeerStore = new PeerStore({
|
const localPeerStore = new PeerStore({
|
||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||||
|
|
||||||
@ -290,7 +296,8 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
const remotePeerStore = new PeerStore({
|
const remotePeerStore = new PeerStore({
|
||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
await remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
||||||
|
|
||||||
@ -352,7 +359,8 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
const localPeerStore = new PeerStore({
|
const localPeerStore = new PeerStore({
|
||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
await localPeerStore.protoBook.set(localPeer, storedProtocols)
|
||||||
|
|
||||||
@ -370,7 +378,8 @@ describe('Identify', () => {
|
|||||||
|
|
||||||
const remotePeerStore = new PeerStore({
|
const remotePeerStore = new PeerStore({
|
||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
await remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
await remotePeerStore.protoBook.set(remotePeer, storedProtocols)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const { MemoryDatastore } = require('datastore-core/memory')
|
|||||||
const PeerStore = require('../../src/peer-store')
|
const PeerStore = require('../../src/peer-store')
|
||||||
const Envelope = require('../../src/record/envelope')
|
const Envelope = require('../../src/record/envelope')
|
||||||
const PeerRecord = require('../../src/record/peer-record')
|
const PeerRecord = require('../../src/record/peer-record')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
const {
|
const {
|
||||||
codes: { ERR_INVALID_PARAMETERS }
|
codes: { ERR_INVALID_PARAMETERS }
|
||||||
@ -29,6 +29,7 @@ const addr2 = new Multiaddr('/ip4/20.0.0.1/tcp/8001')
|
|||||||
const addr3 = new Multiaddr('/ip4/127.0.0.1/tcp/8002')
|
const addr3 = new Multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||||
|
|
||||||
describe('addressBook', () => {
|
describe('addressBook', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let peerId
|
let peerId
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -44,7 +45,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -164,7 +166,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -323,7 +326,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -364,7 +368,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -418,7 +423,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -478,7 +484,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
@ -670,7 +677,8 @@ describe('addressBook', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
ab = peerStore.addressBook
|
ab = peerStore.addressBook
|
||||||
})
|
})
|
||||||
|
@ -8,6 +8,7 @@ const { Multiaddr } = require('multiaddr')
|
|||||||
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
const { fromString: uint8ArrayFromString } = require('uint8arrays/from-string')
|
||||||
const { MemoryDatastore } = require('datastore-core/memory')
|
const { MemoryDatastore } = require('datastore-core/memory')
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
|
|
||||||
const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||||
const addr2 = new Multiaddr('/ip4/127.0.0.1/tcp/8001')
|
const addr2 = new Multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||||
@ -23,6 +24,7 @@ const proto3 = '/protocol3'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
describe('peer-store', () => {
|
describe('peer-store', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let peerIds
|
let peerIds
|
||||||
before(async () => {
|
before(async () => {
|
||||||
peerIds = await peerUtils.createPeerId({
|
peerIds = await peerUtils.createPeerId({
|
||||||
@ -37,7 +39,8 @@ describe('peer-store', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId: peerIds[4],
|
peerId: peerIds[4],
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -66,7 +69,8 @@ describe('peer-store', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId: peerIds[4],
|
peerId: peerIds[4],
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add peer0 with { addr1, addr2 } and { proto1 }
|
// Add peer0 with { addr1, addr2 } and { proto1 }
|
||||||
@ -170,7 +174,8 @@ describe('peer-store', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId: peerIds[4],
|
peerId: peerIds[4],
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ const { MemoryDatastore } = require('datastore-core/memory')
|
|||||||
const Topology = require('libp2p-interfaces/src/topology/multicodec-topology')
|
const Topology = require('libp2p-interfaces/src/topology/multicodec-topology')
|
||||||
const PeerStore = require('../../src/peer-store')
|
const PeerStore = require('../../src/peer-store')
|
||||||
const Registrar = require('../../src/registrar')
|
const Registrar = require('../../src/registrar')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const createMockConnection = require('../utils/mockConnection')
|
const createMockConnection = require('../utils/mockConnection')
|
||||||
const peerUtils = require('../utils/creators/peer')
|
const peerUtils = require('../utils/creators/peer')
|
||||||
const baseOptions = require('../utils/base-options.browser')
|
const baseOptions = require('../utils/base-options.browser')
|
||||||
@ -17,6 +17,7 @@ const baseOptions = require('../utils/base-options.browser')
|
|||||||
const multicodec = '/test/1.0.0'
|
const multicodec = '/test/1.0.0'
|
||||||
|
|
||||||
describe('registrar', () => {
|
describe('registrar', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let peerStore
|
let peerStore
|
||||||
let registrar
|
let registrar
|
||||||
let peerId
|
let peerId
|
||||||
@ -29,7 +30,8 @@ describe('registrar', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
peerStore = new PeerStore({
|
peerStore = new PeerStore({
|
||||||
peerId,
|
peerId,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
registrar = new Registrar({ peerStore, connectionManager: new EventEmitter() })
|
registrar = new Registrar({ peerStore, connectionManager: new EventEmitter() })
|
||||||
})
|
})
|
||||||
|
@ -14,12 +14,14 @@ const mockUpgrader = require('../utils/mockUpgrader')
|
|||||||
const sinon = require('sinon')
|
const sinon = require('sinon')
|
||||||
const Peers = require('../fixtures/peers')
|
const Peers = require('../fixtures/peers')
|
||||||
const pWaitFor = require('p-wait-for')
|
const pWaitFor = require('p-wait-for')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const addrs = [
|
const addrs = [
|
||||||
new Multiaddr('/ip4/127.0.0.1/tcp/0'),
|
new Multiaddr('/ip4/127.0.0.1/tcp/0'),
|
||||||
new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||||
]
|
]
|
||||||
|
|
||||||
describe('Transport Manager (TCP)', () => {
|
describe('Transport Manager (TCP)', () => {
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
let tm
|
let tm
|
||||||
let localPeer
|
let localPeer
|
||||||
|
|
||||||
@ -35,7 +37,8 @@ describe('Transport Manager (TCP)', () => {
|
|||||||
addressManager: new AddressManager({ listen: addrs }),
|
addressManager: new AddressManager({ listen: addrs }),
|
||||||
peerStore: new PeerStore({
|
peerStore: new PeerStore({
|
||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
datastore: new MemoryDatastore()
|
datastore: new MemoryDatastore(),
|
||||||
|
addressFilter: connectionGater.filterMultiaddrForPeer
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
upgrader: mockUpgrader,
|
upgrader: mockUpgrader,
|
||||||
|
@ -18,7 +18,7 @@ const swarmKeyBuffer = uint8ArrayFromString(require('../fixtures/swarm.key'))
|
|||||||
const Libp2p = require('../../src')
|
const Libp2p = require('../../src')
|
||||||
const Upgrader = require('../../src/upgrader')
|
const Upgrader = require('../../src/upgrader')
|
||||||
const { codes } = require('../../src/errors')
|
const { codes } = require('../../src/errors')
|
||||||
|
const { mockConnectionGater } = require('../utils/mock-connection-gater')
|
||||||
const mockMultiaddrConnPair = require('../utils/mockMultiaddrConn')
|
const mockMultiaddrConnPair = require('../utils/mockMultiaddrConn')
|
||||||
const Peers = require('../fixtures/peers')
|
const Peers = require('../fixtures/peers')
|
||||||
const addrs = [
|
const addrs = [
|
||||||
@ -31,6 +31,17 @@ describe('Upgrader', () => {
|
|||||||
let remoteUpgrader
|
let remoteUpgrader
|
||||||
let localPeer
|
let localPeer
|
||||||
let remotePeer
|
let remotePeer
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
|
|
||||||
|
const mockConnectionManager = {
|
||||||
|
gater: {
|
||||||
|
allowDialPeer: async () => true,
|
||||||
|
allowDialMultiaddr: async () => true,
|
||||||
|
acceptConnection: async () => true,
|
||||||
|
acceptEncryptedConnection: async () => true,
|
||||||
|
acceptUpgradedConnection: async () => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
([
|
([
|
||||||
@ -42,10 +53,14 @@ describe('Upgrader', () => {
|
|||||||
]))
|
]))
|
||||||
|
|
||||||
localUpgrader = new Upgrader({
|
localUpgrader = new Upgrader({
|
||||||
localPeer
|
connectionManager: mockConnectionManager,
|
||||||
|
localPeer,
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
remoteUpgrader = new Upgrader({
|
remoteUpgrader = new Upgrader({
|
||||||
localPeer: remotePeer
|
connectionManager: mockConnectionManager,
|
||||||
|
localPeer: remotePeer,
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
localUpgrader.protocols.set('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
|
localUpgrader.protocols.set('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
|
||||||
@ -321,6 +336,7 @@ describe('Upgrader', () => {
|
|||||||
describe('libp2p.upgrader', () => {
|
describe('libp2p.upgrader', () => {
|
||||||
let peers
|
let peers
|
||||||
let libp2p
|
let libp2p
|
||||||
|
const connectionGater = mockConnectionGater()
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
peers = await Promise.all([
|
peers = await Promise.all([
|
||||||
@ -392,8 +408,10 @@ describe('libp2p.upgrader', () => {
|
|||||||
|
|
||||||
const remoteUpgrader = new Upgrader({
|
const remoteUpgrader = new Upgrader({
|
||||||
localPeer: remotePeer,
|
localPeer: remotePeer,
|
||||||
|
connectionManager: libp2p.connectionManager,
|
||||||
muxers: new Map([[Muxer.multicodec, Muxer]]),
|
muxers: new Map([[Muxer.multicodec, Muxer]]),
|
||||||
cryptos: new Map([[Crypto.protocol, Crypto]])
|
cryptos: new Map([[Crypto.protocol, Crypto]]),
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
remoteUpgrader.protocols.set('/echo/1.0.0', echoHandler)
|
remoteUpgrader.protocols.set('/echo/1.0.0', echoHandler)
|
||||||
|
|
||||||
@ -424,8 +442,10 @@ describe('libp2p.upgrader', () => {
|
|||||||
|
|
||||||
const remoteUpgrader = new Upgrader({
|
const remoteUpgrader = new Upgrader({
|
||||||
localPeer: remotePeer,
|
localPeer: remotePeer,
|
||||||
|
connectionManager: libp2p.connectionManager,
|
||||||
muxers: new Map([[Muxer.multicodec, Muxer]]),
|
muxers: new Map([[Muxer.multicodec, Muxer]]),
|
||||||
cryptos: new Map([[Crypto.protocol, Crypto]])
|
cryptos: new Map([[Crypto.protocol, Crypto]]),
|
||||||
|
connectionGater
|
||||||
})
|
})
|
||||||
|
|
||||||
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer })
|
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer })
|
||||||
|
19
test/utils/mock-connection-gater.js
Normal file
19
test/utils/mock-connection-gater.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
function mockConnectionGater () {
|
||||||
|
return {
|
||||||
|
denyDialPeer: async () => Promise.resolve(false),
|
||||||
|
denyDialMultiaddr: async () => Promise.resolve(false),
|
||||||
|
denyInboundConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundConnection: async () => Promise.resolve(false),
|
||||||
|
denyInboundEncryptedConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundEncryptedConnection: async () => Promise.resolve(false),
|
||||||
|
denyInboundUpgradedConnection: async () => Promise.resolve(false),
|
||||||
|
denyOutboundUpgradedConnection: async () => Promise.resolve(false),
|
||||||
|
filterMultiaddrForPeer: async () => Promise.resolve(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mockConnectionGater
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user