From d115119a336b36f84f7de06e076ae09739243cd7 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Mon, 30 Nov 2020 15:22:11 +0100 Subject: [PATCH] chore: add docker setup --- .env | 1 + Dockerfile | 11 ++----- README.md | 31 +++++++++++++++++++- package.json | 4 +-- src/bin.js | 18 +++++++----- src/index.js | 13 ++++----- src/utils.js | 28 +++++++++++------- test/fixtures/peers.js | 27 +++++++++++++++++ test/index.spec.js | 66 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 161 insertions(+), 38 deletions(-) create mode 100644 .env create mode 100644 test/fixtures/peers.js create mode 100644 test/index.spec.js diff --git a/.env b/.env new file mode 100644 index 0000000..a6980aa --- /dev/null +++ b/.env @@ -0,0 +1 @@ +LISTEN_MULTIADDRS='' \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 469dd87..fac0710 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,15 +21,8 @@ RUN npm install --production COPY --chown=node:node ./src ./src COPY --chown=node:node ./README.md ./ -# Environment variables - - -# hop-relay-server defaults to 15003 -EXPOSE 15003 - -# metrics defaults to 8003 -EXPOSE 8003 +ENV DEBUG libp2p* # Available overrides (defaults shown): # Server logging can be enabled via the DEBUG environment variable -CMD [ "/usr/local/bin/dumb-init", "node", "src/server/bin.js"] \ No newline at end of file +CMD [ "/usr/local/bin/dumb-init", "node", "src/bin.js"] \ No newline at end of file diff --git a/README.md b/README.md index 8b60948..7cfd40e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ - [Install](#install) - [CLI](#cli) - [Docker](#docker) + - [SSL](#ssl) + - [Debug](#debug) - [Contribute](#contribute) - [License](#license) @@ -100,7 +102,34 @@ Note: In the future this will leverage libp2p's [DHT](https://github.com/libp2p/ ### Docker -TODO +When running the hop relay server in Docker, you can configure the same parameters via environment variables, as follows: + +```sh +PEER_ID='./id.json' +LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/15002/ws,/ip4/127.0.0.1/tcp/8000' +ANNOUNCE_MULTIADDRS='/dns4/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA,/dns6/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA' +METRICS_MULTIADDR='/ip4/127.0.0.1/tcp/8000' +DISABLE_METRICS='true' +DELEGATE_MULTIADDR='/dns4/node1.delegate.ipfs.io/tcp/443/https' +DISABLE_ADVERTISE='true' +``` + +Please note that you should expose expose the used ports with the docker run command. The default ports used are `8003` for the metrics and `150003` for the websockets listener + +```sh +docker build NAME -t libp2p-hop-relay +docker run -p 8003:8003 -p 15002:15002 -p 8000:8000 -e LISTEN_MULTIADDRS='/ip4/127.0.0.1/tcp/15002/ws,/ip4/127.0.0.1/tcp/8000' -d libp2p-hop-relay +``` + +### SSL + +You should setup an SSL certificate with nginx and proxy to the API. You can use a service that already offers an SSL certificate with the server and configure nginx, or you can create valid certificates with for example [Letsencrypt](https://certbot.eff.org/lets-encrypt/osx-nginx). Letsencrypt won’t give you a cert for an IP address (yet) so you need to connect via SSL to a domain name. + +With this, you should specify in your relay the announce multiaddrs for your listening transports. This is specially important for browser peers that will leverage this relay, as browser nodes can only dial peers behind a `DNS+WSS` multiaddr. + +### Debug + +You can debug the relay by setting the `DEBUG` environment variable. For instance, you can set it to `libp2p*`. ## Contribute diff --git a/package.json b/package.json index 92e9e4f..5c7ff1a 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,8 @@ }, "scripts": { "lint": "aegir lint", - "test": "aegir test", + "test": "aegir test -t node", "test:node": "aegir test -t node", - "test:browser": "aegir test -t browser", - "test:types": "aegir ts -p check", "build": "aegir build", "release": "aegir release", "release-minor": "aegir release --type minor", diff --git a/src/bin.js b/src/bin.js index ed82289..d2d041c 100644 --- a/src/bin.js +++ b/src/bin.js @@ -24,21 +24,24 @@ const createRelay = require('./index') async function main () { // Metrics let metricsServer - const metrics = !(argv.disableMetrics) - const metricsMa = multiaddr(argv.metricsMultiaddr || argv.ma || '/ip4/127.0.0.1/tcp/8003') + const metrics = !(argv.disableMetrics || process.env.DISABLE_METRICS) + const metricsMa = multiaddr(argv.metricsMultiaddr || argv.ma || process.env.METRICS_MULTIADDR || '/ip4/0.0.0.0/tcp/8003') const metricsAddr = metricsMa.nodeAddress() // multiaddrs const listenAddresses = getListenAddresses(argv) const announceAddresses = getAnnounceAddresses(argv) + log(`listenAddresses: ${listenAddresses.map((a) => a)}`) + announceAddresses.length && log(`announceAddresses: ${announceAddresses.map((a) => a)}`) + // Should advertise - const shouldAdvertise = !(argv.disableAdvertise) + const shouldAdvertise = !(argv.disableAdvertise || process.env.DISABLE_ADVERTISE) // Delegate let delegateOptions - if (argv.delegateMultiaddr || argv.dm) { - const delegateAddr = multiaddr(argv.delegateMultiaddr || argv.dm).toOptions() + if (argv.delegateMultiaddr || argv.dm || process.env.DELEGATE_MULTIADDR) { + const delegateAddr = multiaddr(argv.delegateMultiaddr || argv.dm || process.env.DELEGATE_MULTIADDR).toOptions() delegateOptions = { host: delegateAddr.host, protocol: delegateAddr.port === '443' ? 'https' : 'http', @@ -48,9 +51,10 @@ async function main () { // PeerId let peerId - if (argv.peerId) { - const peerData = fs.readFileSync(argv.peerId) + if (argv.peerId || process.env.PEER_ID) { + const peerData = fs.readFileSync(argv.peerId || process.env.PEER_ID) peerId = await PeerId.createFromJSON(JSON.parse(peerData)) + log('PeerId provided was loaded.') } else { peerId = await PeerId.create() log('You are using an automatically generated peer.') diff --git a/src/index.js b/src/index.js index 5e4cfec..68328fa 100644 --- a/src/index.js +++ b/src/index.js @@ -19,11 +19,11 @@ const ipfsHttpClient = require('ipfs-http-client') * @property {number} port */ - const defaulDelegateOptions = { - host: 'node0.delegate.ipfs.io', - protocol: 'https', - port: 443 - } +const defaulDelegateOptions = { + host: 'node0.delegate.ipfs.io', + protocol: 'https', + port: 443 +} /** * @typedef {Object} HopRelayOptions @@ -41,7 +41,7 @@ const ipfsHttpClient = require('ipfs-http-client') * @returns {Promise} */ function create ({ peerId, delegateOptions = defaulDelegateOptions, listenAddresses = [], announceAddresses = [], shouldAdvertise = true }) { - let contentRouting = [] + const contentRouting = [] if (shouldAdvertise) { const httpClient = ipfsHttpClient(delegateOptions) @@ -56,7 +56,6 @@ function create ({ peerId, delegateOptions = defaulDelegateOptions, listenAddres connEncryption: [Crypto], contentRouting }, - peerId, addresses: { listen: listenAddresses, announce: announceAddresses diff --git a/src/utils.js b/src/utils.js index 0e83a75..a380b59 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,19 +1,21 @@ 'use strict' -const multiaddr = require('multiaddr') +function getAnnounceAddresses (argv) { + let announceAddresses = [] + const argvAddr = argv.announceMultiaddrs || argv.am -function getAnnounceAddresses(argv) { - const announceAddr = argv.announceMultiaddrs || argv.am - const announceAddresses = announceAddr ? [multiaddr(announceAddr)] : [] + if (argvAddr) { + announceAddresses = [argvAddr] - if (argv.announceMultiaddrs || argv.am) { const flagIndex = process.argv.findIndex((e) => e === '--announceMultiaddrs' || e === '--am') const tmpEndIndex = process.argv.slice(flagIndex + 1).findIndex((e) => e.startsWith('--')) const endIndex = tmpEndIndex !== -1 ? tmpEndIndex : process.argv.length - flagIndex - 1 for (let i = flagIndex + 1; i < flagIndex + endIndex; i++) { - announceAddresses.push(multiaddr(process.argv[i + 1])) + announceAddresses.push(process.argv[i + 1]) } + } else if (process.env.ANNOUNCE_MULTIADDRS) { + announceAddresses = process.env.ANNOUNCE_MULTIADDRS.split(',') } return announceAddresses @@ -21,18 +23,22 @@ function getAnnounceAddresses(argv) { module.exports.getAnnounceAddresses = getAnnounceAddresses -function getListenAddresses(argv) { - const listenAddr = argv.listenMultiaddrs || argv.lm || '/ip4/127.0.0.1/tcp/15003/ws' - const listenAddresses = [multiaddr(listenAddr)] +function getListenAddresses (argv) { + let listenAddresses = ['/ip4/127.0.0.1/tcp/15003/ws'] + const argvAddr = argv.listenMultiaddrs || argv.lm + + if (argvAddr) { + listenAddresses = [argvAddr] - if (argv.listenMultiaddrs || argv.lm) { const flagIndex = process.argv.findIndex((e) => e === '--listenMultiaddrs' || e === '--lm') const tmpEndIndex = process.argv.slice(flagIndex + 1).findIndex((e) => e.startsWith('--')) const endIndex = tmpEndIndex !== -1 ? tmpEndIndex : process.argv.length - flagIndex - 1 for (let i = flagIndex + 1; i < flagIndex + endIndex; i++) { - listenAddresses.push(multiaddr(process.argv[i + 1])) + listenAddresses.push(process.argv[i + 1]) } + } else if (process.env.LISTEN_MULTIADDRS) { + listenAddresses = process.env.LISTEN_MULTIADDRS.split(',') } return listenAddresses diff --git a/test/fixtures/peers.js b/test/fixtures/peers.js new file mode 100644 index 0000000..27150e5 --- /dev/null +++ b/test/fixtures/peers.js @@ -0,0 +1,27 @@ +'use strict' + +module.exports = [{ + id: '12D3KooWNvSZnPi3RrhrTwEY4LuuBeB6K6facKUCJcyWG1aoDd2p', + privKey: 'CAESYHyCgD+3HtEHm6kzPO6fuwP+BAr/PxfJKlvAOWhc/IqAwrZjCNn0jz93sSl81cP6R6x/g+iVYmR5Wxmn4ZtzJFnCtmMI2fSPP3exKXzVw/pHrH+D6JViZHlbGafhm3MkWQ==', + pubKey: 'CAESIMK2YwjZ9I8/d7EpfNXD+kesf4PolWJkeVsZp+GbcyRZ' +}, { + id: '12D3KooWLV3w42LqUb9MWE7oTzG7vwaFjPw9GvDqmsuDif5chTn9', + privKey: 'CAESYI44p8HiCHtCBhuUcetU9XdIEtWvon15a5ZLsfyssSj9nn3mt4oZI0t6wXTHOvIA0GSFWrYkdKp1338oFIambdKefea3ihkjS3rBdMc68gDQZIVatiR0qnXffygUhqZt0g==', + pubKey: 'CAESIJ595reKGSNLesF0xzryANBkhVq2JHSqdd9/KBSGpm3S' +}, { + id: '12D3KooWDRHe5x3tEQfZi4yirsdhA3zgqhE8awxAjET7zVF23JHB', + privKey: 'CAESYP+GrxgDqKnx79W5l4sgpCEYvNF9bBlCSVu3McENPluhNYVEwxo5KboVuOPnYO6ZOeeTmglqc2vcN8pldRF8lq41hUTDGjkpuhW44+dg7pk555OaCWpza9w3ymV1EXyWrg==', + pubKey: 'CAESIDWFRMMaOSm6Fbjj52DumTnnk5oJanNr3DfKZXURfJau' +}, { + id: '12D3KooWQJMnsoT7js35ZgkboxzUjXpVhfvG8cMqZnBJTP4XPuhU', + privKey: 'CAESYL1Fwm/+layh15V1ITWkK9tEQLuGeJFi16VkNDUU+GFs1y90DFs9vlkRziuJFZ/QtEIlYZWjFTsNRJxFA/etwCvXL3QMWz2+WRHOK4kVn9C0QiVhlaMVOw1EnEUD963AKw==', + pubKey: 'CAESINcvdAxbPb5ZEc4riRWf0LRCJWGVoxU7DUScRQP3rcAr' +}, { + id: '12D3KooWFYyvJysHGbbYiruVY8bgjKn7sYN9axgbnMxrWVkGXABF', + privKey: 'CAESYCtlyHA9SQ9F0yO6frmkrFFmboLCzGt8syr0ix8QkuTcVTVAp9JiBXb2xI1lzK6Fn2mRJUxtQIuuW+3V2mu3DZZVNUCn0mIFdvbEjWXMroWfaZElTG1Ai65b7dXaa7cNlg==', + pubKey: 'CAESIFU1QKfSYgV29sSNZcyuhZ9pkSVMbUCLrlvt1dprtw2W' +}, { + id: '12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5', + privKey: 'CAESYLU/qFxBHsdsQa63w3MrP8VvxJDyAk7rB7gLnIN01CyibmZCtQc7a1gIEDOGb10maUltL8wJxEdmOw3Bpjo7xrpuZkK1BztrWAgQM4ZvXSZpSW0vzAnER2Y7DcGmOjvGug==', + pubKey: 'CAESIG5mQrUHO2tYCBAzhm9dJmlJbS/MCcRHZjsNwaY6O8a6' +}] diff --git a/test/index.spec.js b/test/index.spec.js new file mode 100644 index 0000000..185a111 --- /dev/null +++ b/test/index.spec.js @@ -0,0 +1,66 @@ +'use strict' +/* eslint-env mocha */ + +const { expect } = require('aegir/utils/chai') +const PeerId = require('peer-id') + +const Peers = require('./fixtures/peers') + +const createRelayServer = require('../src') + +describe('Relay Hop Server', () => { + let relay + let peerId + + before(async () => { + peerId = await PeerId.createFromJSON(Peers[0]) + }) + + afterEach(async () => { + relay && await relay.stop() + }) + + it('fails to create a relay if no peerId is provided', async () => { + try { + relay = await createRelayServer({}) + } catch (err) { + expect(err).to.exist() + return + } + throw new Error('should fail to create a relay if no peerId is provided') + }) + + it('can create an start a relay with only a peerId', async () => { + relay = await createRelayServer({ peerId }) + + await relay.start() + }) + + it('can specify listenMultiaddrs for the relay', async () => { + const listenAddresses = ['/ip4/127.0.0.1/tcp/15002/ws', '/ip4/127.0.0.1/tcp/8000'] + + relay = await createRelayServer({ + peerId, + listenAddresses + }) + + await relay.start() + + expect(relay.multiaddrs).to.have.lengthOf(listenAddresses.length) + relay.multiaddrs.forEach((m) => listenAddresses.includes(m.toString())) + }) + + it('can specify announceMultiaddrs for the relay', async () => { + const announceAddresses = ['/dns4/test.io/tcp/443/wss/p2p/12D3KooWAuEpJKhCAfNcHycKcZCv9Qy69utLAJ3MobjKpsoKbrGA'] + + relay = await createRelayServer({ + peerId, + announceAddresses + }) + + await relay.start() + + expect(relay.multiaddrs).to.have.lengthOf(announceAddresses.length) + relay.multiaddrs.forEach((m) => announceAddresses.includes(m.toString())) + }) +})