diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..c33a947d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,43 @@ +language: node_js +cache: npm +stages: + - check + - test + - cov + +node_js: + - '10' + +os: + - linux + - osx + +script: npx nyc -s npm run test:node -- --bail +after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov + +jobs: + include: + - os: windows + cache: false + + - stage: check + script: + - npx aegir commitlint --travis + - npx aegir dep-check + - npm run lint + + - stage: test + name: chrome + addons: + chrome: stable + script: npx aegir test -t browser -t webworker + + - stage: test + name: firefox + addons: + firefox: latest + script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless + +notifications: + email: false + diff --git a/CHANGELOG.md b/CHANGELOG.md index a04e2581..0fd575be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +<a name="6.0.5"></a> +## [6.0.5](https://github.com/multiformats/js-multiaddr/compare/v6.0.4...v6.0.5) (2019-02-25) + + +### Features + +* add unix protocol support and update protocol table ([#84](https://github.com/multiformats/js-multiaddr/issues/84)) ([d4d3d9b](https://github.com/multiformats/js-multiaddr/commit/d4d3d9b)) + + + <a name="6.0.4"></a> ## [6.0.4](https://github.com/multiformats/js-multiaddr/compare/v6.0.3...v6.0.4) (2019-01-25) diff --git a/README.md b/README.md index a10c459a..bb125bef 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ js-multiaddr [](https://david-dm.org/multiformats/js-multiaddr) [](https://github.com/feross/standard) [](https://github.com/RichardLitt/standard-readme) -[](https://ci.ipfs.team/job/multiformats/job/js-multiaddr/job/master) +[](https://travis-ci.com/multiformats/js-multiaddr) [](https://codecov.io/gh/multiformats/js-multiaddr) > JavaScript implementation of [multiaddr](https://github.com/multiformats/multiaddr). ## Lead Maintainer -[Victor Bjelkholm](https://github.com/VictorBjelkholm) +[Jacob Heun](https://github.com/jacobheun) ## Table of Contents @@ -26,12 +26,7 @@ js-multiaddr - [Browser: Browserify, Webpack, other bundlers](#browser-browserify-webpack-other-bundlers) - [Browser: `<script>` Tag](#browser-script-tag) - [Usage](#usage) -- [API](#api) - - [Create](#create) - - [Protocols](#protocols) - - [Node-Friendly Addresses](#node-friendly-addresses) - - [En/decapsulate](#endecapsulate) - - [Tunneling](#tunneling) +- [API](#api) - https://multiformats.github.io/js-multiaddr/ - [Maintainers](#maintainers) - [Contribute](#contribute) - [License](#license) diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile deleted file mode 100644 index a7da2e54..00000000 --- a/ci/Jenkinsfile +++ /dev/null @@ -1,2 +0,0 @@ -// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -javascript() diff --git a/examples/try.js b/examples/try.js index 4d6d1603..7cfd10a9 100644 --- a/examples/try.js +++ b/examples/try.js @@ -15,7 +15,6 @@ log(addr.protos()) log(addr.nodeAddress()) log(multiaddr.fromNodeAddress(addr.nodeAddress(), 'udp')) -// addr = multiaddr.fromStupidString("udp4://127.0.0.1:1234") log(addr.encapsulate('/sctp/5678')) log(addr.decapsulate('/udp')) diff --git a/package.json b/package.json index 1102896f..277675fa 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "multiaddr", - "version": "6.0.4", + "version": "6.0.5", "description": "multiaddr implementation (binary + string representation of network addresses)", - "leadMaintainer": "Victor Bjelkholm <victorbjelkholm@gmail.com>", + "leadMaintainer": "Jacob Heun <jacobheun@gmail.com>", "main": "src/index.js", "scripts": { "lint": "aegir lint", @@ -13,8 +13,6 @@ "release": "aegir release", "release-minor": "aegir release --type minor", "release-major": "aegir release --type major", - "coverage": "aegir coverage", - "coverage-publish": "aegir coverage publish", "docs": "aegir docs", "size": "bundlesize -f dist/index.min.js -s 14kB" }, @@ -39,7 +37,7 @@ "varint": "^5.0.0" }, "devDependencies": { - "aegir": "^18.0.3", + "aegir": "^18.2.0", "bundlesize": "~0.17.0", "chai": "^4.2.0", "dirty-chai": "^2.0.1" @@ -56,6 +54,7 @@ "Lars Gierth <lgierth@users.noreply.github.com>", "Maciej Krüger <mkg20001@gmail.com>", "Marcin Rataj <lidel@lidel.org>", + "Oli Evans <oli@tableflip.io>", "Richard Littauer <richard.littauer@gmail.com>", "Sid Harder <sideharder@gmail.com>", "Stephen Whitmore <stephen.whitmore@gmail.com>", diff --git a/src/codec.js b/src/codec.js index 835bdeeb..0a4a8d6f 100644 --- a/src/codec.js +++ b/src/codec.js @@ -52,6 +52,18 @@ function stringToStringTuples (str) { throw ParseError('invalid address: ' + str) } + // if it's a path proto, take the rest + if (proto.path) { + tuples.push([ + part, + // TODO: should we need to check each path part to see if it's a proto? + // This would allow for other protocols to be added after a unix path, + // however it would have issues if the path had a protocol name in the path + cleanPath(parts.slice(p).join('/')) + ]) + break + } + tuples.push([part, parts[p]]) } @@ -69,7 +81,7 @@ function stringTuplesToString (tuples) { } }) - return '/' + parts.join('/') + return cleanPath(parts.join('/')) } // [[str name, str addr]... ] -> [[int code, Buffer]... ] diff --git a/src/convert.js b/src/convert.js index 4ee56049..4fa5279b 100644 --- a/src/convert.js +++ b/src/convert.js @@ -30,9 +30,11 @@ Convert.toString = function convertToString (proto, buf) { case 132: // sctp return buf2port(buf) + case 53: // dns case 54: // dns4 case 55: // dns6 case 56: // dnsaddr + case 400: // unix return buf2str(buf) case 421: // ipfs @@ -56,9 +58,11 @@ Convert.toBuffer = function convertToBuffer (proto, str) { case 132: // sctp return port2buf(parseInt(str, 10)) + case 53: // dns case 54: // dns4 case 55: // dns6 case 56: // dnsaddr + case 400: // unix return str2buf(str) case 421: // ipfs diff --git a/src/index.js b/src/index.js index d2c1f9c1..9c5772fb 100644 --- a/src/index.js +++ b/src/index.js @@ -6,8 +6,6 @@ const varint = require('varint') const bs58 = require('bs58') const withIs = require('class-is') -const NotImplemented = new Error('Sorry, Not Implemented Yet.') - /** * Creates a [multiaddr](https://github.com/multiformats/multiaddr) from * a Buffer, String or another Multiaddr instance @@ -257,6 +255,33 @@ Multiaddr.prototype.getPeerId = function getPeerId () { return b58str } +/** + * Extract the path if the multiaddr contains one + * + * @return {String|null} path - The path of the multiaddr, or null if no path protocol is present + * @example + * const mh1 = Multiaddr('/ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock') + * // <Multiaddr 0408080808060438 - /ip4/8.8.8.8/tcp/1080/unix/tmp/p2p.sock> + * + * // should return utf8 string or null if the id is missing or invalid + * const path = mh1.getPath() + */ +Multiaddr.prototype.getPath = function getPath () { + let path = null + try { + path = this.stringTuples().filter((tuple) => { + const proto = protocols(tuple[0]) + if (proto.path) { + return true + } + })[0][1] + } catch (e) { + path = null + } + + return path +} + /** * Checks if two Multiaddrs are the same * @@ -371,25 +396,6 @@ Multiaddr.prototype.isThinWaistAddress = function isThinWaistAddress (addr) { return true } -// TODO rename this to something else than "stupid string" -/** - * Converts a "stupid string" into a Multiaddr. - * - * Stupid string format: - * ``` - * <proto><IPv>://<IP Addr>[:<proto port>] - * udp4://1.2.3.4:5678 - * ``` - * - * @param {String} [str] - String in the "stupid" format - * @throws {NotImplemented} - * @returns {undefined} - * @todo Not Implemented yet - */ -Multiaddr.prototype.fromStupidString = function fromStupidString (str) { - throw NotImplemented -} - /** * Object containing table, names and codes of all supported protocols. * To get the protocol values from a Multiaddr, you can use diff --git a/src/protocols-table.js b/src/protocols-table.js index 975ec97c..5eba5d04 100644 --- a/src/protocols-table.js +++ b/src/protocols-table.js @@ -25,32 +25,38 @@ Protocols.V = V Protocols.table = [ [4, 32, 'ip4'], [6, 16, 'tcp'], - [273, 16, 'udp'], [33, 16, 'dccp'], [41, 128, 'ip6'], + [42, V, 'ip6zone'], + [53, V, 'dns', 'resolvable'], [54, V, 'dns4', 'resolvable'], [55, V, 'dns6', 'resolvable'], [56, V, 'dnsaddr', 'resolvable'], [132, 16, 'sctp'], - // all of the below use varint for size + [273, 16, 'udp'], + [275, 0, 'p2p-webrtc-star'], + [276, 0, 'p2p-webrtc-direct'], + [277, 0, 'p2p-stardust'], + [290, 0, 'p2p-circuit'], + [301, 0, 'udt'], [302, 0, 'utp'], + [400, V, 'unix', false, 'path'], // `p2p` is the preferred name for 421 - [421, Protocols.lengthPrefixedVarSize, 'p2p'], + [421, V, 'p2p'], // `ipfs` has been added after `p2p` so that it is used by default. // The reason for this is to provide better backwards support for // code bases that do not yet support the `p2p` proto name. Eventually // `p2p` should become the default. - [421, Protocols.lengthPrefixedVarSize, 'ipfs'], - [480, 0, 'http'], + [421, V, 'ipfs'], [443, 0, 'https'], + [444, 96, 'onion'], + [445, 296, 'onion3'], + [446, V, 'garlic64'], [460, 0, 'quic'], [477, 0, 'ws'], [478, 0, 'wss'], [479, 0, 'p2p-websocket-star'], - [277, 0, 'p2p-stardust'], - [275, 0, 'p2p-webrtc-star'], - [276, 0, 'p2p-webrtc-direct'], - [290, 0, 'p2p-circuit'] + [480, 0, 'http'] ] Protocols.names = {} @@ -65,12 +71,13 @@ Protocols.table.map(row => { Protocols.object = p -function p (code, size, name, resolvable) { +function p (code, size, name, resolvable, path) { return { code: code, size: size, name: name, - resolvable: Boolean(resolvable) + resolvable: Boolean(resolvable), + path: Boolean(path) } } diff --git a/test/index.spec.js b/test/index.spec.js index fa7171c9..e91bd9d4 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -260,6 +260,13 @@ describe('variants', () => { expect(addr.toString()).to.equal(str) }) + it('ip4 + tcp + unix', () => { + const str = '/ip4/127.0.0.1/tcp/80/unix/a/b/c/d/e/f' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + }) + it('ip6 + tcp + http', () => { const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/http' const addr = multiaddr(str) @@ -267,6 +274,13 @@ describe('variants', () => { expect(addr.toString()).to.equal(str) }) + it('ip6 + tcp + unix', () => { + const str = '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/8000/unix/a/b/c/d/e/f' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + }) + it('ip4 + tcp + https', () => { const str = '/ip4/127.0.0.1/tcp/8000/https' const addr = multiaddr(str) @@ -323,6 +337,13 @@ describe('variants', () => { expect(addr.toString()).to.equal(str.replace('/p2p/', '/ipfs/')) }) + it('unix', () => { + const str = '/unix/a/b/c/d/e' + const addr = multiaddr(str) + expect(addr).to.have.property('buffer') + expect(addr.toString()).to.equal(str) + }) + it('p2p', () => { const str = '/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC' const addr = multiaddr(str) @@ -413,11 +434,13 @@ describe('helpers', () => { .to.eql([{ code: 4, name: 'ip4', + path: false, size: 32, resolvable: false }, { code: 302, name: 'utp', + path: false, size: 0, resolvable: false }]) @@ -429,16 +452,19 @@ describe('helpers', () => { ).to.be.eql([{ code: 4, name: 'ip4', + path: false, size: 32, resolvable: false }, { code: 302, name: 'utp', + path: false, size: 0, resolvable: false }, { code: 421, name: 'ipfs', + path: false, size: -1, resolvable: false }]) @@ -450,16 +476,43 @@ describe('helpers', () => { ).to.be.eql([{ code: 4, name: 'ip4', + path: false, size: 32, resolvable: false }, { code: 302, name: 'utp', + path: false, size: 0, resolvable: false }, { code: 421, name: 'ipfs', + path: false, + size: -1, + resolvable: false + }]) + }) + + it('works with unix', () => { + expect( + multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos() + ).to.be.eql([{ + code: 4, + name: 'ip4', + path: false, + size: 32, + resolvable: false + }, { + code: 6, + name: 'tcp', + path: false, + size: 16, + resolvable: false + }, { + code: 400, + name: 'unix', + path: true, size: -1, resolvable: false }]) @@ -642,12 +695,6 @@ describe('helpers', () => { }) }) - describe('.fromStupidString', () => { - it('parses an address in the format <proto><IPv>://<IP Addr>[:<proto port>]', () => { - expect(() => multiaddr('/').fromStupidString()).to.throw(/Not Implemented/) - }) - }) - describe('.getPeerId should parse id from multiaddr', () => { it('parses extracts the peer Id from a multiaddr, p2p', () => { expect( @@ -669,6 +716,26 @@ describe('helpers', () => { }) }) + describe('.getPath', () => { + it('should return a path for unix', () => { + expect( + multiaddr('/unix/tmp/p2p.sock').getPath() + ).to.eql('/tmp/p2p.sock') + }) + + it('should return a path for unix when other protos exist', () => { + expect( + multiaddr('/ip4/0.0.0.0/tcp/1234/unix/tmp/p2p.sock').getPath() + ).to.eql('/tmp/p2p.sock') + }) + + it('should not return a path when no path proto exists', () => { + expect( + multiaddr('/ip4/0.0.0.0/tcp/1234/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').getPath() + ).to.eql(null) + }) + }) + describe('multiaddr.isMultiaddr', () => { it('handles different inputs', () => { expect(multiaddr.isMultiaddr(multiaddr('/'))).to.be.eql(true) @@ -682,6 +749,12 @@ describe('helpers', () => { describe('resolvable multiaddrs', () => { describe('.isName', () => { it('valid name dns', () => { + const str = '/dns/ipfs.io' + const addr = multiaddr(str) + expect(multiaddr.isName(addr)).to.equal(true) + }) + + it('valid name dnsaddr', () => { const str = '/dnsaddr/ipfs.io' const addr = multiaddr(str) expect(multiaddr.isName(addr)).to.equal(true)