From 616e741c30cad3f9823fed85fc3c92fcb7b65adc Mon Sep 17 00:00:00 2001 From: Arve Knudsen Date: Wed, 3 Jul 2019 13:06:07 +0200 Subject: [PATCH] Test JS to Go connections with both RSA and ECDSA keys --- package.json | 6 +- src/daemon.js | 32 ++++++--- test/connect/js2go.js | 100 ++++++++++++++++++--------- test/resources/keys/go.rsa.key | Bin 0 -> 1198 bytes test/resources/keys/go.secp256k1.key | 1 + test/resources/keys/js.rsa.key | Bin 0 -> 1196 bytes test/resources/keys/js.secp256k1.key | 1 + test/utils/spawnDaemons.js | 53 ++++++++------ 8 files changed, 126 insertions(+), 67 deletions(-) create mode 100644 test/resources/keys/go.rsa.key create mode 100644 test/resources/keys/go.secp256k1.key create mode 100644 test/resources/keys/js.rsa.key create mode 100644 test/resources/keys/js.secp256k1.key diff --git a/package.json b/package.json index f8e742b..86334e6 100644 --- a/package.json +++ b/package.json @@ -27,15 +27,15 @@ }, "homepage": "https://github.com/libp2p/interop#readme", "devDependencies": { + "@arve.knudsen/libp2p-daemon": "^0.2.6", + "@arve.knudsen/libp2p-daemon-client": "~0.1.10", "aegir": "^19.0.3", "chai": "^4.2.0", "chai-bytes": "~0.1.2", "chai-checkmark": "^1.0.1", "cross-env": "^5.2.0", "dirty-chai": "^2.0.1", - "go-libp2p-dep": "~0.1.0", - "libp2p-daemon": "~0.2.1", - "libp2p-daemon-client": "~0.1.2", + "@arve.knudsen/go-libp2p-dep": "~0.2.2", "multiaddr": "^6.0.6", "rimraf": "^2.6.3" }, diff --git a/src/daemon.js b/src/daemon.js index f83aecd..12a2814 100644 --- a/src/daemon.js +++ b/src/daemon.js @@ -6,7 +6,7 @@ const fs = require('fs') const path = require('path') const rimraf = require('rimraf') -const Client = require('libp2p-daemon-client') +const Client = require('@arve.knudsen/libp2p-daemon-client') const { getMultiaddr, isWindows } = require('./utils') // process path @@ -15,27 +15,29 @@ const processPath = process.cwd() // go-libp2p defaults const goDaemon = { defaultAddr: getMultiaddr('/tmp/p2pd-go.sock'), - bin: path.join('go-libp2p-dep', 'go-libp2p', isWindows ? 'p2pd.exe' : 'p2pd') + bin: path.join('@arve.knudsen/go-libp2p-dep', 'go-libp2p', isWindows ? 'p2pd.exe' : 'p2pd') } // js-libp2p defaults const jsDaemon = { defaultAddr: getMultiaddr('/tmp/p2pd-js.sock'), - bin: path.join('libp2p-daemon', 'src', 'cli', 'bin.js') + bin: path.join('@arve.knudsen/libp2p-daemon', 'src', 'cli', 'bin.js') } class Daemon { /** * @constructor - * @param {String} type daemon implementation type ("go" or "js") + * @param {String} spec daemon implementation spec (type "go" or "js") * @param {Multiaddr} addr multiaddr for the client to connect to * @param {Number} port port for the client to connect to */ - constructor (type, addr, port) { + constructor (spec, addr, port) { + const { type, keyFile } = spec assert(type === 'go' || type === 'js', 'invalid type received. Should be "go" or "js"') this._client = undefined this._type = type + this._keyFile = keyFile this._binPath = this._getBinPath(type) this._addr = addr && getMultiaddr(addr, port) @@ -100,27 +102,37 @@ class Daemon { _startDaemon (options) { return new Promise((resolve, reject) => { let execOptions + const addr = this._addr.toString() // TODO refactor this once we daemon supports a json config if (this._type === 'go') { - execOptions = ['-listen', this._addr] + execOptions = ['-listen', addr, '-enableInlining=false'] options.dht && execOptions.push('-dht') options.pubsub && execOptions.push('-pubsub') } else { - execOptions = ['--listen', this._addr] + execOptions = ['--listen', addr] options.dht && execOptions.push('--dht') options.pubsub && execOptions.push('--pubsub') } + if ((this._keyFile || '') !== '') { + execOptions.push(`--id=${this._keyFile}`) + } const daemon = execa(this._binPath, execOptions) daemon.stdout.once('data', () => { - return resolve() + resolve() }) - daemon.stderr.once('data', (data) => { - return reject(data.toString()) + daemon.on('exit', (code, signal) => { + if (code !== 0) { + reject(new Error(`daemon exited with status code ${code}`)) + } else if ((signal || '') !== '') { + reject(new Error(`daemon exited due to signal ${signal}`)) + } else { + resolve() + } }) }) } diff --git a/test/connect/js2go.js b/test/connect/js2go.js index 2f9e6c7..ff4332f 100644 --- a/test/connect/js2go.js +++ b/test/connect/js2go.js @@ -8,46 +8,84 @@ const expect = chai.expect const spawnDaemons = require('../utils/spawnDaemons') -describe('connect', () => { - let daemons +const beforeConnect = (ctx, keyType) => { + ctx.timeout(20 * 1000) - // Start Daemons - before(async function () { - this.timeout(20 * 1000) + return spawnDaemons(2, [{ type: 'js', keyType }, { type: 'go', keyType }]) +} - daemons = await spawnDaemons(2, ['js', 'go']) - }) +const afterConnect = async (daemons) => { + if (daemons == null) { + return + } - // Stop daemons - after(async function () { - await Promise.all( - daemons.map((daemon) => daemon.stop()) - ) - }) + await Promise.all( + daemons.map(async (daemon) => { + // Ignore errors + try { + await daemon.stop() + } catch (_) { + } + }) + ) +} + +const performTest = async (ctx, daemons) => { + ctx.timeout(10 * 1000) + + const identifyJs = await daemons[0].client.identify() + const identifyGo = await daemons[1].client.identify() + + // verify connected peers + const knownPeersBeforeConnectJs = await daemons[0].client.listPeers() + expect(knownPeersBeforeConnectJs).to.have.lengthOf(0) + + const knownPeersBeforeConnectGo = await daemons[1].client.listPeers() + expect(knownPeersBeforeConnectGo).to.have.lengthOf(0) - it('js peer to go peer', async function () { - this.timeout(10 * 1000) + // connect peers + await daemons[0].client.connect(identifyGo.peerId, identifyGo.addrs) - const identifyJs = await daemons[0].client.identify() - const identifyGo = await daemons[1].client.identify() + // verify connected peers + const knownPeersAfterConnectJs = await daemons[0].client.listPeers() + expect(knownPeersAfterConnectJs).to.have.lengthOf(1) + expect(knownPeersAfterConnectJs[0].toB58String()).to.equal(identifyGo.peerId.toB58String()) - // verify connected peers - const knownPeersBeforeConnectJs = await daemons[0].client.listPeers() - expect(knownPeersBeforeConnectJs).to.have.lengthOf(0) + const knownPeersAfterConnectGo = await daemons[1].client.listPeers() + expect(knownPeersAfterConnectGo).to.have.lengthOf(1) + expect(knownPeersAfterConnectGo[0].toB58String()).to.equal(identifyJs.peerId.toB58String()) +} + +describe('connecting js peer to go peer', () => { + describe('with RSA keys', () => { + let daemons + + before(async function () { + daemons = await beforeConnect(this, 'rsa') + }) + + after(async () => { + await afterConnect(daemons) + }) + + it('should work', async function () { + await performTest(this, daemons) + }) + }) - const knownPeersBeforeConnectGo = await daemons[1].client.listPeers() - expect(knownPeersBeforeConnectGo).to.have.lengthOf(0) + describe('with SECP256k1 keys', () => { + let daemons - // connect peers - await daemons[0].client.connect(identifyGo.peerId, identifyGo.addrs) + before(async function () { + daemons = await beforeConnect(this, 'secp256k1') + }) - // verify connected peers - const knownPeersAfterConnectJs = await daemons[0].client.listPeers() - expect(knownPeersAfterConnectJs).to.have.lengthOf(1) - expect(knownPeersAfterConnectJs[0].toB58String()).to.equal(identifyGo.peerId.toB58String()) + after(async () => { + await afterConnect(daemons) + }) - const knownPeersAfterConnectGo = await daemons[1].client.listPeers() - expect(knownPeersAfterConnectGo).to.have.lengthOf(1) - expect(knownPeersAfterConnectGo[0].toB58String()).to.equal(identifyJs.peerId.toB58String()) + it('should work', async function () { + await performTest(this, daemons) + }) }) }) diff --git a/test/resources/keys/go.rsa.key b/test/resources/keys/go.rsa.key new file mode 100644 index 0000000000000000000000000000000000000000..1ed57044e8afef85b4ee3d9e3b33062592b7976f GIT binary patch literal 1198 zcmV;f1X24401~MQFoFc70s#O5f&l>l&TND+1U=H=n?p~^;jn$f9viDfvaK`K7E+Fs z(k06vkcpvVQd0hi9wFsCA>7@*eb?4`TA?x-lVSk>Sqtr!&qtJvSpjUpMeZ<7z7$H` zH0^;(Sp1LYYBqh;R^&W(xCdcdP%YZrK3Q14`ZZqNi+9?RV_FZed{H40oc0uHL3&r4 zPZka7!ovNfD*9<_S69VjXscedrhvnKhz}vSG)rYA+5w3oAC`Xg$)O>W<9#q$8J^W5 zK7HO})OeTV9cMp^DDpJpO$Fpqt$cLGmz{4td=M@3N#O3kj`*sVfGI8#WIf`KJF80D zmvf2oT=wD1@N_@$BXL1&8Mg)70s{d60Rn;n08S0CYK(0NDG%&|=65o3OKv_6Bii6C zLOj2i)MF+QNzMI?z3!?VKEVza4F}BWI2VJSz@lkmby7-mkQz>{S0X2|-$b#BI|jo` z7K(C5;GY}Qkd{|r-l9d?jENGWUQM;swO@M&PttFkWD;IY@x8<2EeTFbvU5L%9*@{) z+`0|rF;GM&McOlWzJRht*Hsw_mSdHaeb2BwS1fu^lD36C!)kY$wlnsw>>qUM|3{s? zbtQ0aul*~Z&onx|naWC*vqRn?e^a&;zFJSnRJ~V9CTDBwKgWF583XekIfa(>168~m zk2kehA>olW{&GkDc{>BUm7a)vj(+en83KWU0N*5jzotOZNIZ=~lH1|s(TbzOBH+f| zSzQ>vC1!mARFxf*8UO5O8978nZfrhT7*+_hipECzAJi%`ISu$IU!7^KYcBf!`d%<5R4XLYC#CF3Ov%XAYc28BUoakt` zUjl)F0PNAs*KPT&V82DNB1V2DcM-B&@`eLM%aJKm%s%IYlJVdK!y*;^5L}h}&RQP& zx@Df$f1{;;iSzM*g~S+O*S>^bo#AyS{cie4-5I5I^~UIWA1+q!HGq!llCqF;QIVre zD>6O|E~s2u?;Q=Sto9>5x8$iT=+2)n1pcOSNRXR#9L=e`x;=1 z=e?ayNdkd^0LaHW-!7Xk7DhA#@TEymy+mNI65{csg5F4HUtYPCnXJ8=>;PLD8Kf0> z&O>wFXy?5d=ub-l?P$lyiXd(FwG$3euAVkvxGFutZNJZ(Nz35Rpxyn@g3!X+HEdqgo0MD$Yq@OU~{kOr#&&84p z0wI~wz`N#1`t#l_A>O93Je)k}82Z@%rGEv7FR!3Mg0W;9RDzN$3ZP>* MvJkt5lFJ^=URm`;4FCWD literal 0 HcmV?d00001 diff --git a/test/resources/keys/go.secp256k1.key b/test/resources/keys/go.secp256k1.key new file mode 100644 index 0000000..eab1892 --- /dev/null +++ b/test/resources/keys/go.secp256k1.key @@ -0,0 +1 @@ + {ܥg oT+.\L YJbGq7 \ No newline at end of file diff --git a/test/resources/keys/js.rsa.key b/test/resources/keys/js.rsa.key new file mode 100644 index 0000000000000000000000000000000000000000..a428cc568ab336a07c4109324c981afc8135b669 GIT binary patch literal 1196 zcmV;d1XKG601~GOFoFc50s#O5f&l>l$~G9l;p=_2S9j7r-|o=p*Ia0ypNZY1kn?G} zCW4m;0pZhE=4bvjB@?+R4aTsNTPX6^2HD8?m)wqMaLKq+f`roDfRh3@rsLQ?8Dy zBRQ6wznt5jvC%%no0IAB5iKG9M_uJjq~_J=-uqT8Q{2}~m1ZZCtYcLMIQM44F-_67 zaD_Y`0u5Hw*LEYMP!=>V@rNb10s{d60Rn;n00NQsbd)NK8G|_)ss!w#DI$BJG|n+m zXyX#Z_(8u7E@R)j@bweJPG_GzjzI^KeEGemfQKx@dM;*#Ibz?mC|g|MWSV|ivlAIR z;h6+XiNb}Estm!MKJnkr)1Y?YPda_)%+poiQku`@H+3Pj%KGM@)hxg+?bI5`y)mQj z`|ZyTC9MVLprO}U>s{x&J;rKEO`n_*kRsMf*DmIJd zynVVSqAgB?$*aB0Mkls*m_)}#!`ne{dZ0#D>uhEG)ReSv=A?$V#7b67g2D|baGdDo z6dR=7d|?guaanu~?t$Agh17UNENYAs5dwjM0RO0v%ZyN-R@?LtT54gfeFr{fY86ap z*q&PB>5Mwix$8JynSeUC4uh#L1$b|>AN2rlJe>|;xP2}7hwDZFR_{{YeLbQ(3fitD zT0m7jCecSiO)xLa9SKfuesKm)?ACDV%`<67shk%R$5Fsx4P`W=qJBwz{>^cNBpWwd z?*f5=0Lptnn8RUJ4Q4nx@?H0MYfQ$&o6beYHF}v^jGqTF_=a(IL(j=cwjE7S?4$Ha z$=ihi{-HR|;u29=%yKBe-fkG(aST>bZuc0w+JDl59nlHb3t~gk-kMo;wbbWqCNs3m zqVUeCvQ%Jyc=0XHtiek(8HF|uy~>9Ds?QgyxdMTJP+l`OX``k>^WGzk=*Lg|Z`_07 zaa5IvnJ-0JQ^etXu%89a2WxG_SW86)**A0j<;?#o^vq&MT*9c(L3_RXmONa@&M8Bh zL+D;{D6At7BG%p3+5rrYOfRLlh1*ZiP!TI0+PsU@o5uZSxguKN6(X4yDbW0suMDyW z6|XOC0)c@5$8p46H3q1vd?%wAohoPe`87xME~r@I`jQv9FXQ}r+M?uTLqzycWN3x& zvPZ0MBE`=GD|a)2N1e_fEy}9D?jD=*0Kff`nchhoo{*9bAe-8-q3A%%cd6>)Vuo4f z|3h`wf$(nv^G)Ic6+V-BfcUr0)c>hRe@1N1KwRm%}z;w_sXn? z&HBM8G0nzjT`&@&P=2sfqfr6wrQs<^ykS8sOg538)SQcX*ynFp-nO_i`&+V^Zf4}A zG?ALLV(xPDMhxhS>{i1rv \ No newline at end of file diff --git a/test/utils/spawnDaemons.js b/test/utils/spawnDaemons.js index aea96e6..55e7398 100644 --- a/test/utils/spawnDaemons.js +++ b/test/utils/spawnDaemons.js @@ -1,6 +1,7 @@ 'use strict' const assert = require('assert') +const path = require('path') const Daemon = require('../../src/daemon') @@ -8,30 +9,41 @@ const startPortNumber = 9000 /** * @param {number} n number of nodes to spawn - * @param {string|array} type nodes type (default: js) + * @param {string|array} specs node specs (default: 'js') * @param {Object|array} options daemon options */ -async function spawnDaemons (n, type = 'js', options) { +async function spawnDaemons (n, specs = 'js', options) { assert(n, 'spawnDaemons require a number of nodes to start') - assert(validType(n, type), 'spawnDaemons type is not valid') - let types = type - - if (!Array.isArray(types)) { - types = new Array(n).fill(type) + if (!Array.isArray(specs)) { + specs = new Array(n).fill(specs) } + specs = specs.map((spec) => { + if (typeof spec === 'string') { + return { + type: spec + } + } - let daemonOptions = options + return spec + }) + validateSpecs(n, specs) + let daemonOptions = options if (!Array.isArray(daemonOptions)) { daemonOptions = new Array(n).fill(options) } const daemons = [] - let daemon - for (let i = 0; i < n; i++) { - daemon = new Daemon(types[i], `/tmp/p2pd-${i}.sock`, startPortNumber + i) + const spec = specs[i] + const keyFile = spec.keyType != null + ? path.resolve(__dirname, `../resources/keys/${spec.type}.${spec.keyType}.key`) : null + const daemonSpec = { + type: spec.type, + keyFile + } + const daemon = new Daemon(daemonSpec, `/tmp/p2pd-${i}.sock`, startPortNumber + i) daemons.push(daemon) } @@ -40,19 +52,14 @@ async function spawnDaemons (n, type = 'js', options) { return daemons } -function validType (n, type) { - // validate string type - if (typeof type === 'string' && (type === 'js' || type === 'go')) { - return true - } - - // validate array of types - if (Array.isArray(type) && type.length === n && - !type.filter((t) => (t !== 'go' && t !== 'js')).length) { - return true - } +function validateSpecs (n, specs) { + assert(specs.length === n, 'number of specs must be equal to n') - return false + specs.forEach((spec) => { + assert(spec.type === 'js' || spec.type === 'go', `invalid spec type ${spec.type}`) + assert(spec.keyType == null || spec.keyType === 'rsa' || spec.keyType === 'secp256k1', + `invalid spec key type ${spec.keyType}`) + }) } module.exports = spawnDaemons