From 2b7cc55c88e93a34a727d7ae3fc73ebba538230b Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Fri, 8 Jun 2018 00:30:21 +0200 Subject: [PATCH] feat: add check for protector and enforced pnet fix: update protector config and tests docs: add private network info to the readme test: fix an issue with config --- README.md | 12 +++++++ src/config.js | 3 ++ src/index.js | 7 ++++ test/node.js | 1 + test/pnet.node.js | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+) create mode 100644 test/pnet.node.js diff --git a/README.md b/README.md index 54bee873..eb247c96 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ const SECIO = require('libp2p-secio') const MulticastDNS = require('libp2p-mdns') const DHT = require('libp2p-kad-dht') const defaultsDeep = require('@nodeutils/defaults-deep') +const Protector = require('libp2p-pnet') class Node extends libp2p { constructor (_peerInfo, _peerBook, _options) { @@ -135,6 +136,7 @@ class Node extends libp2p { connEncryption: [ SECIO ], + connProtector: new Protector(/*protector specific opts*/), peerDiscovery: [ MulticastDNS ], @@ -431,6 +433,16 @@ Each one of these values is [an exponential moving-average instance](https://git Stats are not updated in real-time. Instead, measurements are buffered and stats are updated at an interval. The maximum interval can be defined through the `Switch` constructor option `stats.computeThrottleTimeout`, defined in miliseconds. +### Private Networks + +#### Enforcement + +Libp2p provides support for connection protection, such as for private networks. You can enforce network protection by setting the environment variable `LIBP2P_FORCE_PNET=1`. When this variable is on, if no protector is set via `options.connProtector`, Libp2p will throw an error upon creation. + +#### Protectors + +Some available network protectors: +* [libp2p-pnet](https://github.com/libp2p/js-libp2p-pnet) ## Development diff --git a/src/config.js b/src/config.js index 03072a57..6eaa7f7e 100644 --- a/src/config.js +++ b/src/config.js @@ -13,6 +13,9 @@ const OptionsSchema = Joi.object({ transport: Joi.array().items(ModuleSchema).min(1).required(), streamMuxer: Joi.array().items(ModuleSchema).allow(null), connEncryption: Joi.array().items(ModuleSchema).allow(null), + connProtector: Joi.object().keys({ + protect: Joi.func().required() + }).unknown(), peerDiscovery: Joi.array().items(ModuleSchema).allow(null), dht: ModuleSchema.allow(null) }).required(), diff --git a/src/index.js b/src/index.js index bdb01bce..893669a5 100644 --- a/src/index.js +++ b/src/index.js @@ -75,6 +75,13 @@ class Node extends EventEmitter { }) } + // Attach private network protector + if (this._modules.connProtector) { + this._switch.protector = this._modules.connProtector + } else if (process.env.LIBP2P_FORCE_PNET) { + throw new Error('Private network is enforced, but no protector was provided') + } + // dht provided components (peerRouting, contentRouting, dht) if (this._config.EXPERIMENTAL.dht) { const DHT = this._modules.dht diff --git a/test/node.js b/test/node.js index 095906a5..e820ddf6 100644 --- a/test/node.js +++ b/test/node.js @@ -1,5 +1,6 @@ 'use strict' +require('./pnet.node') require('./transports.node') require('./stream-muxing.node') require('./peer-discovery.node') diff --git a/test/pnet.node.js b/test/pnet.node.js new file mode 100644 index 00000000..641dde96 --- /dev/null +++ b/test/pnet.node.js @@ -0,0 +1,90 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +chai.use(require('dirty-chai')) +const expect = chai.expect +const PeerInfo = require('peer-info') +const PeerId = require('peer-id') +const waterfall = require('async/waterfall') +const WS = require('libp2p-websockets') +const defaultsDeep = require('@nodeutils/defaults-deep') + +const Libp2p = require('../src') + +describe('private network', () => { + let config + + before((done) => { + waterfall([ + (cb) => PeerId.create({ bits: 512 }, cb), + (peerId, cb) => PeerInfo.create(peerId, cb), + (peerInfo, cb) => { + config = { + peerInfo, + modules: { + transport: [ WS ] + } + } + cb() + } + ], () => done()) + }) + + describe('enforced network protection', () => { + before(() => { + process.env.LIBP2P_FORCE_PNET = 1 + }) + + after(() => { + delete process.env.LIBP2P_FORCE_PNET + }) + + it('should throw an error without a provided protector', () => { + expect(() => { + return new Libp2p(config) + }).to.throw('Private network is enforced, but no protector was provided') + }) + + it('should create a libp2p node with a provided protector', () => { + let node + let protector = { + psk: '123', + tag: '/psk/1.0.0', + protect: () => { } + } + + expect(() => { + let options = defaultsDeep(config, { + modules: { + connProtector: protector + } + }) + + node = new Libp2p(options) + return node + }).to.not.throw() + expect(node._switch.protector).to.deep.equal(protector) + }) + + it('should throw an error if the protector does not have a protect method', () => { + expect(() => { + let options = defaultsDeep(config, { + modules: { + connProtector: { } + } + }) + + return new Libp2p(options) + }).to.throw() + }) + }) + + describe('network protection not enforced', () => { + it('should not throw an error with no provided protector', () => { + expect(() => { + return new Libp2p(config) + }).to.not.throw() + }) + }) +})