diff --git a/src/index.js b/src/index.js index c18a8a0c..95ee29e8 100644 --- a/src/index.js +++ b/src/index.js @@ -37,6 +37,9 @@ const Multiaddr = withIs.proto(function (addr) { */ this.buffer = codec.fromBuffer(addr) } else if (typeof addr === 'string' || addr instanceof String) { + if (addr.length > 0 && addr.charAt(0) !== '/') { + throw new Error(`multiaddr "${addr}" must start with a "/"`) + } this.buffer = codec.fromString(addr) } else if (addr.buffer && addr.protos && addr.protoCodes) { // Multiaddr this.buffer = codec.fromBuffer(addr.buffer) // validate + copy buffer @@ -297,14 +300,20 @@ Multiaddr.prototype.equals = function equals (addr) { * // {family: 'IPv4', address: '127.0.0.1', port: '4001'} */ Multiaddr.prototype.nodeAddress = function nodeAddress () { - if (!this.isThinWaistAddress()) { - throw new Error('Multiaddr must be "thin waist" address for nodeAddress.') - } - const codes = this.protoCodes() + const names = this.protoNames() const parts = this.toString().split('/').slice(1) + + if (parts.length < 4) { + throw new Error('multiaddr must have a valid format: "/{ip4, ip6, dns4, dns6}/{address}/{tcp, udp}/{port}".') + } else if (codes[0] !== 4 && codes[0] !== 41 && codes[0] !== 54 && codes[0] !== 55) { + throw new Error(`no protocol with name: "'${names[0]}'". Must have a valid family name: "{ip4, ip6, dns4, dns6}".`) + } else if (parts[2] !== 'tcp' && parts[2] !== 'udp') { + throw new Error(`no protocol with name: "'${names[1]}'". Must have a valid transport protocol: "{tcp, udp}".`) + } + return { - family: (codes[0] === 41) ? 'IPv6' : 'IPv4', + family: (codes[0] === 41 || codes[0] === 55) ? 6 : 4, address: parts[1], // ip addr port: parts[3] // tcp or udp port } diff --git a/test/index.spec.js b/test/index.spec.js index 14a8014b..8f4772bc 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -443,11 +443,11 @@ describe('helpers', () => { }) describe('.nodeAddress', () => { - it('throws on non thinWaistAddress', () => { + it('throws on an invalid node address', () => { expect( () => multiaddr('/ip4/192.168.0.1/utp').nodeAddress() ).to.throw( - /thin waist/ + /multiaddr must have a valid format/ ) }) @@ -456,10 +456,44 @@ describe('helpers', () => { multiaddr('/ip4/192.168.0.1/tcp/1234').nodeAddress() ).to.be.eql({ address: '192.168.0.1', - family: 'IPv4', + family: 4, port: '1234' }) }) + + it('returns a node friendly address with dns', () => { + expect( + multiaddr('/dns4/wss0.bootstrap.libp2p.io/tcp/443').nodeAddress() + ).to.be.eql({ + address: 'wss0.bootstrap.libp2p.io', + family: 4, + port: '443' + }) + }) + + it('throws on an invalid format address when the addr is not prefixed with a /', () => { + expect( + () => multiaddr('ip4/192.168.0.1/udp').nodeAddress() + ).to.throw( + /must start with a/ + ) + }) + + it('throws on an invalid protocol name when the addr has an invalid one', () => { + expect( + () => multiaddr('/ip5/127.0.0.1/udp/5000') + ).to.throw( + /no protocol with name/ + ) + }) + + it('throws on an invalid protocol name when the transport protocol is not valid', () => { + expect( + () => multiaddr('/ip4/127.0.0.1/utp/5000') + ).to.throw( + /no protocol with name/ + ) + }) }) describe('.fromNodeAddress', () => { @@ -501,10 +535,10 @@ describe('helpers', () => { } families.forEach((family) => { transports.forEach((transport) => { - it(`returns true for ${family}-${transport}`, () => { + it(`returns true for /${family}-${transport}`, () => { expect( multiaddr( - `${family}/${addresses[family]}/${transport}/1234` + `/${family}/${addresses[family]}/${transport}/1234` ).isThinWaistAddress() ).to.equal(true) })