diff --git a/.aegir.js b/.aegir.js index b4eb9b0f11..a787ac4fc7 100644 --- a/.aegir.js +++ b/.aegir.js @@ -1,5 +1,6 @@ 'use strict' +const path = require('path') const Libp2p = require('./src') const { MULTIADDRS_WEBSOCKETS } = require('./test/fixtures/browser') const Peers = require('./test/fixtures/peers') @@ -47,16 +48,23 @@ const after = async () => { await libp2p.stop() } +/** @type {import('aegir').Options["build"]["config"]} */ +const esbuild = { + inject: [path.join(__dirname, './scripts/node-globals.js')] +} + +/** @type {import('aegir').PartialOptions} */ module.exports = { - bundlesize: { maxSize: '223kB' }, - hooks: { - pre: before, - post: after + build: { + bundlesizeMax: '253kB' }, - webpack: { - node: { - // needed by bcrypto - Buffer: true + test: { + before, + after, + browser: { + config: { + buildConfig: esbuild + } } } } diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 0000000000..b2b0aa37f6 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,102 @@ +name: examples +on: + push: + branches: + - master + pull_request: + branches: + - '**' + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: npx aegir lint + - run: npx aegir ts -p check + - run: npx aegir build + test-auto-relay-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- auto-relay + test-chat-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- chat + test-connection-encryption-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- connection-encryption + test-discovery-mechanisms-example: + needs: check + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- discovery-mechanisms + test-echo-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- echo + test-libp2p-in-the-browser-example: + needs: check + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- libp2p-in-the-browser + test-peer-and-content-routing-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- peer-and-content-routing + test-pnet-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- pnet + test-protocol-and-stream-muxing-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- protocol-and-stream-muxing + test-pubsub-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- pubsub + test-transports-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- transports + test-webrtc-direct-example: + needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: npm install + - run: cd examples && yarn && npm run test -- webrtc-direct \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a3a59b81f..50b74aad04 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: yarn - - run: yarn lint + - run: npm install + - run: npx aegir lint - uses: gozala/typescript-error-reporter-action@v1.0.8 - - run: yarn build - - run: yarn aegir dep-check + - run: npx aegir build + - run: npx aegir dep-check - uses: ipfs/aegir/actions/bundle-size@master name: size with: @@ -34,111 +34,34 @@ jobs: - uses: actions/setup-node@v1 with: node-version: ${{ matrix.node }} - - run: yarn - - run: npx nyc --reporter=lcov aegir test -t node -- --bail + - run: npm install + - run: npx aegir test -t node --cov --bail - uses: codecov/codecov-action@v1 test-chrome: needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: yarn + - run: npm install - run: npx aegir test -t browser -t webworker --bail test-firefox: needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: yarn - - run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless - test-interop: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd node_modules/interop-libp2p && yarn && LIBP2P_JS=${GITHUB_WORKSPACE}/src/index.js npx aegir test -t node --bail - test-auto-relay-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- auto-relay - test-chat-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- chat - test-connection-encryption-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- connection-encryption - test-discovery-mechanisms-example: - needs: check - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- discovery-mechanisms - test-echo-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- echo - test-libp2p-in-the-browser-example: - needs: check - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- libp2p-in-the-browser - test-peer-and-content-routing-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- peer-and-content-routing - test-pnet-example: + - run: npm install + - run: npx aegir test -t browser -t webworker --bail -- --browser firefox + test-ts: needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- pnet - test-protocol-and-stream-muxing-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- protocol-and-stream-muxing - test-pubsub-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- pubsub - test-transports-example: - needs: check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- transports - test-webrtc-direct-example: + - run: npm install + - run: npm run test:ts + test-interop: needs: check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: yarn - - run: cd examples && yarn && npm run test -- webrtc-direct + - run: npm install + - run: cd node_modules/interop-libp2p && yarn && LIBP2P_JS=${GITHUB_WORKSPACE}/src/index.js npx aegir test -t node --bail diff --git a/.gitignore b/.gitignore index 61b3b5aa3d..69f5439f9c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ docs test/repo-tests* **/bundle.js .cache +.parcel-cache # Logs logs diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 89c30b3d07..f479cb3210 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -599,7 +599,7 @@ const TCP = require('libp2p-tcp') const MPLEX = require('libp2p-mplex') const { NOISE } = require('libp2p-noise') -const { FaultTolerance } = require('libp2p/src/transport-manager')} +const { FaultTolerance } = require('libp2p/src/transport-manager') const node = await Libp2p.create({ modules: { diff --git a/examples/libp2p-in-the-browser/package.json b/examples/libp2p-in-the-browser/package.json index 5a93afd81a..9b928e8f7b 100644 --- a/examples/libp2p-in-the-browser/package.json +++ b/examples/libp2p-in-the-browser/package.json @@ -2,7 +2,7 @@ "name": "libp2p-in-browser", "version": "1.0.0", "description": "A libp2p node running in the browser", - "main": "index.js", + "main": "dist/index.html", "browserslist": [ "last 2 Chrome versions" ], @@ -20,8 +20,8 @@ "libp2p-bootstrap": "^0.12.1", "libp2p-mplex": "^0.10.0", "libp2p-noise": "^2.0.0", - "libp2p-webrtc-star": "^0.20.0", - "libp2p-websockets": "^0.14.0" + "libp2p-webrtc-star": "^0.22.0", + "libp2p-websockets": "^0.15.0" }, "devDependencies": { "@babel/cli": "^7.13.10", @@ -29,6 +29,6 @@ "babel-plugin-syntax-async-functions": "^6.13.0", "babel-plugin-transform-regenerator": "^6.26.0", "babel-polyfill": "^6.26.0", - "parcel-bundler": "1.12.3" + "parcel": "next" } } diff --git a/examples/libp2p-in-the-browser/test.js b/examples/libp2p-in-the-browser/test.js index c0e67fe7bf..574e5739b2 100644 --- a/examples/libp2p-in-the-browser/test.js +++ b/examples/libp2p-in-the-browser/test.js @@ -17,10 +17,10 @@ async function run() { const out = chunk.toString() if (out.includes('Server running at')) { - url = out.replace('Server running at ', '') + url = out.split('Server running at ')[1] } - if (out.includes('✨ Built in ')) { + if (out.includes('Built in')) { try { const browser = await chromium.launch(); const page = await browser.newPage(); diff --git a/examples/webrtc-direct/package.json b/examples/webrtc-direct/package.json index f5491c7ba0..d96c2aed5e 100644 --- a/examples/webrtc-direct/package.json +++ b/examples/webrtc-direct/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "private": true, "description": "", + "main": "dist/index.html", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "parcel build index.html", @@ -15,14 +16,15 @@ "babel-plugin-syntax-async-functions": "^6.13.0", "babel-plugin-transform-regenerator": "^6.26.0", "babel-polyfill": "^6.26.0", - "parcel-bundler": "1.12.3" + "parcel-bundler": "1.12.3", + "util": "^0.12.3" }, "dependencies": { "libp2p": "../../", "libp2p-bootstrap": "^0.12.1", "libp2p-mplex": "^0.10.1", "libp2p-noise": "^2.0.1", - "libp2p-webrtc-direct": "^0.5.0", + "libp2p-webrtc-direct": "^0.6.0", "peer-id": "^0.14.3" }, "browser": { diff --git a/examples/webrtc-direct/test.js b/examples/webrtc-direct/test.js index 1768e1a082..a6a976a2df 100644 --- a/examples/webrtc-direct/test.js +++ b/examples/webrtc-direct/test.js @@ -50,10 +50,12 @@ async function test () { const out = chunk.toString() if (out.includes('Server running at')) { - dialerUrl = out.replace('Server running at ', '') + dialerUrl = out.split('Server running at ')[1] } - if (out.includes('✨ Built in ')) { + + if (out.includes('Built in ')) { + try { const browser = await chromium.launch(); const page = await browser.newPage(); diff --git a/package.json b/package.json index 1e6eaf2096..668e840c3e 100644 --- a/package.json +++ b/package.json @@ -20,10 +20,28 @@ "scripts": { "lint": "aegir lint", "build": "aegir build", - "test": "npm run test:node && npm run test:browser", + "build:proto": "npm run build:proto:circuit && npm run build:proto:identify && npm run build:proto:plaintext && npm run build:proto:address-book && npm run build:proto:proto-book && npm run build:proto:peer-record && npm run build:proto:envelope", + "build:proto:circuit": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/circuit/protocol/index.js ./src/circuit/protocol/index.proto", + "build:proto:identify": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/identify/message.js ./src/identify/message.proto", + "build:proto:plaintext": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/insecure/proto.js ./src/insecure/proto.proto", + "build:proto:address-book": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/peer-store/persistent/pb/address-book.js ./src/peer-store/persistent/pb/address-book.proto", + "build:proto:proto-book": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/peer-store/persistent/pb/proto-book.js ./src/peer-store/persistent/pb/proto-book.proto", + "build:proto:peer-record": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/record/peer-record/peer-record.js ./src/record/peer-record/peer-record.proto", + "build:proto:envelope": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/record/envelope/envelope.js ./src/record/envelope/envelope.proto", + "build:proto-types": "npm run build:proto-types:circuit && npm run build:proto-types:identify && npm run build:proto-types:plaintext && npm run build:proto-types:address-book && npm run build:proto-types:proto-book && npm run build:proto-types:peer-record && npm run build:proto-types:envelope", + "build:proto-types:circuit": "pbts -o src/circuit/protocol/index.d.ts src/circuit/protocol/index.js", + "build:proto-types:identify": "pbts -o src/identify/message.d.ts src/identify/message.js", + "build:proto-types:plaintext": "pbts -o src/insecure/proto.d.ts src/insecure/proto.js", + "build:proto-types:address-book": "pbts -o src/peer-store/persistent/pb/address-book.d.ts src/peer-store/persistent/pb/address-book.js", + "build:proto-types:proto-book": "pbts -o src/peer-store/persistent/pb/proto-book.d.ts src/peer-store/persistent/pb/proto-book.js", + "build:proto-types:peer-record": "pbts -o src/record/peer-record/peer-record.d.ts src/record/peer-record/peer-record.js", + "build:proto-types:envelope": "pbts -o src/record/envelope/envelope.d.ts src/record/envelope/envelope.js", + "test": "aegir test", + "test:ts": "aegir build --no-bundle && npm run test --prefix test/ts-use", "test:node": "aegir test -t node -f \"./test/**/*.{node,spec}.js\"", "test:browser": "aegir test -t browser", "test:examples": "cd examples && npm run test:all", + "prepare": "aegir build --no-bundle", "release": "aegir release -t node -t browser", "release-minor": "aegir release --type minor -t node -t browser", "release-major": "aegir release --type major -t node -t browser", @@ -47,12 +65,18 @@ "homepage": "https://libp2p.io", "license": "MIT", "engines": { - "node": ">=12.0.0", - "npm": ">=6.0.0" + "node": ">=14.0.0" }, "browser": { "@motrix/nat-api": false }, + "eslintConfig": { + "extends": "ipfs", + "ignorePatterns": [ + "!.aegir.js", + "test/ts-use" + ] + }, "dependencies": { "@motrix/nat-api": "^0.3.1", "abort-controller": "^3.0.0", @@ -62,9 +86,9 @@ "cids": "^1.1.5", "class-is": "^1.1.0", "debug": "^4.3.1", - "err-code": "^2.0.0", + "err-code": "^3.0.0", "es6-promisify": "^6.1.1", - "events": "^3.2.0", + "events": "^3.3.0", "hashlru": "^2.3.0", "interface-datastore": "^3.0.3", "ipfs-utils": "^6.0.0", @@ -73,76 +97,78 @@ "it-drain": "^1.0.3", "it-filter": "^1.0.1", "it-first": "^1.0.4", - "it-handshake": "^1.0.2", - "it-length-prefixed": "^3.1.0", + "it-handshake": "^2.0.0", + "it-length-prefixed": "^5.0.2", "it-map": "^1.0.4", "it-merge": "1.0.0", "it-pipe": "^1.1.0", - "it-protocol-buffers": "^0.2.0", "it-take": "1.0.0", "libp2p-crypto": "^0.19.0", - "libp2p-interfaces": "^0.8.1", - "libp2p-utils": "^0.2.2", - "mafmt": "^8.0.0", + "libp2p-interfaces": "^0.10.0", + "libp2p-utils": "^0.3.1", + "mafmt": "^9.0.0", "merge-options": "^3.0.4", "moving-average": "^1.0.0", - "multiaddr": "^8.1.0", - "multicodec": "^2.1.0", - "multihashing-async": "^2.0.1", - "multistream-select": "^1.0.0", + "multiaddr": "^9.0.1", + "multicodec": "^3.0.1", + "multihashing-async": "^2.1.2", + "multistream-select": "^2.0.0", "mutable-proxy": "^1.0.0", "node-forge": "^0.10.0", "p-any": "^3.0.0", "p-fifo": "^1.0.0", - "p-retry": "^4.2.0", - "p-settle": "^4.0.1", + "p-retry": "^4.4.0", + "p-settle": "^4.1.1", "peer-id": "^0.14.2", - "private-ip": "^2.0.0", - "protons": "^2.0.0", - "retimer": "^2.0.0", + "private-ip": "^2.1.0", + "protobufjs": "^6.10.2", + "retimer": "^3.0.0", "sanitize-filename": "^1.6.3", "set-delayed-interval": "^1.0.0", "streaming-iterables": "^5.0.2", "timeout-abort-controller": "^1.1.1", "varint": "^6.0.0", - "xsalsa20": "^1.0.2" + "xsalsa20": "^1.1.0" }, "devDependencies": { "@nodeutils/defaults-deep": "^1.1.0", "@types/es6-promisify": "^6.0.0", + "@types/node-forge": "^0.9.7", + "@types/varint": "^6.0.0", "abortable-iterator": "^3.0.0", - "aegir": "^29.2.0", + "aegir": "^33.0.0", + "buffer": "^6.0.3", "chai-bytes": "^0.1.2", "chai-string": "^1.5.0", - "delay": "^4.4.0", + "delay": "^5.0.0", "interop-libp2p": "^0.3.0", "into-stream": "^6.0.0", - "ipfs-http-client": "^48.2.2", + "ipfs-http-client": "^49.0.4", "it-concat": "^1.0.0", "it-pair": "^1.0.0", "it-pushable": "^1.4.0", "libp2p": ".", - "libp2p-bootstrap": "^0.12.0", - "libp2p-delegated-content-routing": "^0.9.0", - "libp2p-delegated-peer-routing": "^0.8.0", - "libp2p-floodsub": "^0.24.0", + "libp2p-bootstrap": "^0.12.3", + "libp2p-delegated-content-routing": "^0.10.0", + "libp2p-delegated-peer-routing": "^0.9.0", + "libp2p-floodsub": "^0.25.0", "libp2p-gossipsub": "^0.8.0", - "libp2p-kad-dht": "^0.20.5", - "libp2p-mdns": "^0.15.0", + "libp2p-kad-dht": "^0.21.0", + "libp2p-mdns": "^0.16.0", "libp2p-mplex": "^0.10.1", "libp2p-noise": "^2.0.0", - "libp2p-secio": "^0.13.1", "libp2p-tcp": "^0.15.1", - "libp2p-webrtc-star": "^0.20.0", + "libp2p-webrtc-star": "^0.22.0", "libp2p-websockets": "^0.15.0", - "multihashes": "^3.0.1", + "multihashes": "^4.0.2", "nock": "^13.0.3", "p-defer": "^3.0.0", "p-times": "^3.0.0", "p-wait-for": "^3.2.0", "rimraf": "^3.0.2", - "sinon": "^9.2.4", - "uint8arrays": "^2.0.5" + "sinon": "^10.0.0", + "uint8arrays": "^2.1.3", + "util": "^0.12.3" }, "contributors": [ "David Dias ", diff --git a/scripts/node-globals.js b/scripts/node-globals.js new file mode 100644 index 0000000000..cc0a4c9e9c --- /dev/null +++ b/scripts/node-globals.js @@ -0,0 +1,2 @@ +// @ts-nocheck +export const { Buffer } = require('buffer') diff --git a/src/address-manager/index.js b/src/address-manager/index.js index 625432252e..bc4024c4be 100644 --- a/src/address-manager/index.js +++ b/src/address-manager/index.js @@ -1,15 +1,9 @@ 'use strict' -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') -/** - * @typedef {import('multiaddr')} Multiaddr - */ - /** * @typedef {Object} AddressManagerOptions * @property {string[]} [listen = []] - list of multiaddrs string representation to listen. @@ -47,7 +41,7 @@ class AddressManager extends EventEmitter { * @returns {Multiaddr[]} */ getListenAddrs () { - return Array.from(this.listen).map((a) => multiaddr(a)) + return Array.from(this.listen).map((a) => new Multiaddr(a)) } /** @@ -56,7 +50,7 @@ class AddressManager extends EventEmitter { * @returns {Multiaddr[]} */ getAnnounceAddrs () { - return Array.from(this.announce).map((a) => multiaddr(a)) + return Array.from(this.announce).map((a) => new Multiaddr(a)) } /** @@ -65,7 +59,7 @@ class AddressManager extends EventEmitter { * @returns {Array} */ getObservedAddrs () { - return Array.from(this.observed).map((a) => multiaddr(a)) + return Array.from(this.observed).map((a) => new Multiaddr(a)) } /** @@ -74,7 +68,7 @@ class AddressManager extends EventEmitter { * @param {string | Multiaddr} addr */ addObservedAddr (addr) { - let ma = multiaddr(addr) + let ma = new Multiaddr(addr) const remotePeer = ma.getPeerId() // strip our peer id if it has been passed @@ -83,7 +77,7 @@ class AddressManager extends EventEmitter { // use same encoding for comparison if (remotePeerId.equals(this.peerId)) { - ma = ma.decapsulate(multiaddr(`/p2p/${this.peerId}`)) + ma = ma.decapsulate(new Multiaddr(`/p2p/${this.peerId}`)) } } diff --git a/src/circuit/README.md b/src/circuit/README.md index e2dd5018b9..680a76c204 100644 --- a/src/circuit/README.md +++ b/src/circuit/README.md @@ -37,7 +37,7 @@ Libp2p circuit configuration can be seen at [Setup with Relay](../../doc/CONFIGU Once you have a circuit relay node running, you can configure other nodes to use it as a relay as follows: ```js -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const Libp2p = require('libp2p') const TCP = require('libp2p-tcp') const MPLEX = require('libp2p-mplex') @@ -47,7 +47,7 @@ const relayAddr = ... const node = await Libp2p.create({ addresses: { - listen: [multiaddr(`${relayAddr}/p2p-circuit`)] + listen: [new Multiaddr(`${relayAddr}/p2p-circuit`)] }, modules: { transport: [TCP], diff --git a/src/circuit/auto-relay.js b/src/circuit/auto-relay.js index 122ac979fb..a99bb14d32 100644 --- a/src/circuit/auto-relay.js +++ b/src/circuit/auto-relay.js @@ -7,7 +7,7 @@ const log = Object.assign(debug('libp2p:auto-relay'), { const uint8ArrayFromString = require('uint8arrays/from-string') const uint8ArrayToString = require('uint8arrays/to-string') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const { relay: multicodec } = require('./multicodec') @@ -157,7 +157,7 @@ class AutoRelay { // Attempt to listen on relay try { - await this._transportManager.listen([multiaddr(listenAddr)]) + await this._transportManager.listen([new Multiaddr(listenAddr)]) // Announce multiaddrs will update on listen success by TransportManager event being triggered } catch (err) { log.error(err) diff --git a/src/circuit/circuit/hop.js b/src/circuit/circuit/hop.js index 8e23e6a894..b2ce72de0a 100644 --- a/src/circuit/circuit/hop.js +++ b/src/circuit/circuit/hop.js @@ -18,17 +18,17 @@ const { stop } = require('./stop') const multicodec = require('./../multicodec') /** - * @typedef {import('../../types').CircuitRequest} CircuitRequest + * @typedef {import('../protocol').ICircuitRelay} ICircuitRelay * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection - * @typedef {import('./stream-handler')} StreamHandlerT + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream * @typedef {import('../transport')} Transport */ /** * @typedef {Object} HopRequest * @property {Connection} connection - * @property {CircuitRequest} request - * @property {StreamHandlerT} streamHandler + * @property {ICircuitRelay} request + * @property {StreamHandler} streamHandler * @property {Transport} circuit */ @@ -58,6 +58,11 @@ async function handleHop ({ return log.error('invalid hop request via peer %s', connection.remotePeer.toB58String(), err) } + if (!request.dstPeer) { + log('HOP request received but we do not receive a dstPeer') + return + } + // Get the connection to the destination (stop) peer const destinationPeer = new PeerId(request.dstPeer.id) @@ -113,8 +118,8 @@ async function handleHop ({ * * @param {object} options * @param {Connection} options.connection - Connection to the relay - * @param {CircuitRequest} options.request - * @returns {Promise} + * @param {ICircuitRelay} options.request + * @returns {Promise} */ async function hop ({ connection, @@ -128,6 +133,10 @@ async function hop ({ const response = await streamHandler.read() + if (!response) { + throw errCode(new Error('HOP request had no response'), Errors.ERR_HOP_REQUEST_FAILED) + } + if (response.code === CircuitPB.Status.SUCCESS) { log('hop request was successful') return streamHandler.rest() @@ -159,7 +168,7 @@ async function canHop ({ const response = await streamHandler.read() await streamHandler.close() - if (response.code !== CircuitPB.Status.SUCCESS) { + if (!response || response.code !== CircuitPB.Status.SUCCESS) { return false } @@ -171,7 +180,7 @@ async function canHop ({ * * @param {Object} options * @param {Connection} options.connection - * @param {StreamHandlerT} options.streamHandler + * @param {StreamHandler} options.streamHandler * @param {Transport} options.circuit * @private */ diff --git a/src/circuit/circuit/stop.js b/src/circuit/circuit/stop.js index 111b811dc2..6fa92a07c0 100644 --- a/src/circuit/circuit/stop.js +++ b/src/circuit/circuit/stop.js @@ -13,8 +13,7 @@ const { validateAddrs } = require('./utils') /** * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream - * @typedef {import('../../types').CircuitRequest} CircuitRequest - * @typedef {import('./stream-handler')} StreamHandlerT + * @typedef {import('../protocol').ICircuitRelay} ICircuitRelay */ /** @@ -23,8 +22,8 @@ const { validateAddrs } = require('./utils') * @private * @param {Object} options * @param {Connection} options.connection - * @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded) - * @param {StreamHandlerT} options.streamHandler + * @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded) + * @param {StreamHandler} options.streamHandler * @returns {Promise|void} Resolves a duplex iterable */ module.exports.handleStop = function handleStop ({ @@ -54,7 +53,7 @@ module.exports.handleStop = function handleStop ({ * @private * @param {Object} options * @param {Connection} options.connection - * @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded) + * @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded) * @returns {Promise} Resolves a duplex iterable */ module.exports.stop = async function stop ({ @@ -68,6 +67,10 @@ module.exports.stop = async function stop ({ streamHandler.write(request) const response = await streamHandler.read() + if (!response) { + return streamHandler.close() + } + if (response.code === CircuitPB.Status.SUCCESS) { log('stop request to %s was successful', connection.remotePeer.toB58String()) return streamHandler.rest() diff --git a/src/circuit/circuit/stream-handler.js b/src/circuit/circuit/stream-handler.js index 5be2c6edf5..bbae7d6825 100644 --- a/src/circuit/circuit/stream-handler.js +++ b/src/circuit/circuit/stream-handler.js @@ -6,16 +6,15 @@ const log = Object.assign(debug('libp2p:circuit:stream-handler'), { }) const lp = require('it-length-prefixed') +// @ts-ignore it-handshake does not export types const handshake = require('it-handshake') -const { CircuitRelay: CircuitPB } = require('../protocol') +const { CircuitRelay } = require('../protocol') /** * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream + * @typedef {import('../protocol').ICircuitRelay} ICircuitRelay */ -/** - * @template T - */ class StreamHandler { /** * Create a stream handler for connection @@ -29,6 +28,7 @@ class StreamHandler { this.stream = stream this.shake = handshake(this.stream) + // @ts-ignore options are not optional this.decoder = lp.decode.fromReader(this.shake.reader, { maxDataLength: maxLength }) } @@ -36,12 +36,11 @@ class StreamHandler { * Read and decode message * * @async - * @returns {Promise} */ async read () { const msg = await this.decoder.next() if (msg.value) { - const value = CircuitPB.decode(msg.value.slice()) + const value = CircuitRelay.decode(msg.value.slice()) log('read message type', value.type) return value } @@ -54,13 +53,13 @@ class StreamHandler { /** * Encode and write array of buffers * - * @param {CircuitPB} msg - An unencoded CircuitRelay protobuf message + * @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message * @returns {void} */ write (msg) { log('write message type %s', msg.type) // @ts-ignore lp.encode expects type type 'Buffer | BufferList', not 'Uint8Array' - this.shake.write(lp.encode.single(CircuitPB.encode(msg))) + this.shake.write(lp.encode.single(CircuitRelay.encode(msg).finish())) } /** @@ -73,6 +72,9 @@ class StreamHandler { return this.shake.stream } + /** + * @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message + */ end (msg) { this.write(msg) this.close() diff --git a/src/circuit/circuit/utils.js b/src/circuit/circuit/utils.js index 65c5afe47d..a69dcb50ba 100644 --- a/src/circuit/circuit/utils.js +++ b/src/circuit/circuit/utils.js @@ -1,18 +1,18 @@ 'use strict' -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const { CircuitRelay } = require('../protocol') /** * @typedef {import('./stream-handler')} StreamHandler - * @typedef {import('../../types').CircuitStatus} CircuitStatus + * @typedef {import('../protocol').ICircuitRelay} ICircuitRelay */ /** * Write a response * * @param {StreamHandler} streamHandler - * @param {CircuitStatus} status + * @param {import('../protocol').CircuitRelay.Status} status */ function writeResponse (streamHandler, status) { streamHandler.write({ @@ -24,14 +24,16 @@ function writeResponse (streamHandler, status) { /** * Validate incomming HOP/STOP message * - * @param {*} msg - A CircuitRelay unencoded protobuf message + * @param {ICircuitRelay} msg - A CircuitRelay unencoded protobuf message * @param {StreamHandler} streamHandler */ function validateAddrs (msg, streamHandler) { try { - msg.dstPeer.addrs.forEach((addr) => { - return multiaddr(addr) - }) + if (msg.dstPeer && msg.dstPeer.addrs) { + msg.dstPeer.addrs.forEach((addr) => { + return new Multiaddr(addr) + }) + } } catch (err) { writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP ? CircuitRelay.Status.HOP_DST_MULTIADDR_INVALID @@ -40,9 +42,11 @@ function validateAddrs (msg, streamHandler) { } try { - msg.srcPeer.addrs.forEach((addr) => { - return multiaddr(addr) - }) + if (msg.srcPeer && msg.srcPeer.addrs) { + msg.srcPeer.addrs.forEach((addr) => { + return new Multiaddr(addr) + }) + } } catch (err) { writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP ? CircuitRelay.Status.HOP_SRC_MULTIADDR_INVALID diff --git a/src/circuit/index.js b/src/circuit/index.js index 447d829ac5..da8e879e52 100644 --- a/src/circuit/index.js +++ b/src/circuit/index.js @@ -8,13 +8,12 @@ const log = Object.assign(debug('libp2p:relay'), { const { setDelayedInterval, clearDelayedInterval +// @ts-ignore set-delayed-interval does not export types } = require('set-delayed-interval') const AutoRelay = require('./auto-relay') const { namespaceToCid } = require('./utils') const { - ADVERTISE_BOOT_DELAY, - ADVERTISE_TTL, RELAY_RENDEZVOUS_NS } = require('./constants') @@ -45,12 +44,6 @@ class Relay { constructor (libp2p) { this._libp2p = libp2p this._options = { - advertise: { - bootDelay: ADVERTISE_BOOT_DELAY, - enabled: true, - ttl: ADVERTISE_TTL, - ...libp2p._config.relay.advertise - }, ...libp2p._config.relay } diff --git a/src/circuit/listener.js b/src/circuit/listener.js index d19cca5e46..a3f11dc7d4 100644 --- a/src/circuit/listener.js +++ b/src/circuit/listener.js @@ -1,10 +1,9 @@ 'use strict' const { EventEmitter } = require('events') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') /** - * @typedef {import('multiaddr')} Multiaddr * @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener */ @@ -24,7 +23,7 @@ module.exports = (libp2p) => { async function listen (addr) { const addrString = String(addr).split('/p2p-circuit').find(a => a !== '') - const relayConn = await libp2p.dial(multiaddr(addrString)) + const relayConn = await libp2p.dial(new Multiaddr(addrString)) const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit') listeningAddrs.set(relayConn.remotePeer.toB58String(), relayedAddr) diff --git a/src/circuit/protocol/index.d.ts b/src/circuit/protocol/index.d.ts new file mode 100644 index 0000000000..68e4880b95 --- /dev/null +++ b/src/circuit/protocol/index.d.ts @@ -0,0 +1,173 @@ +import * as $protobuf from "protobufjs"; +/** Properties of a CircuitRelay. */ +export interface ICircuitRelay { + + /** CircuitRelay type */ + type?: (CircuitRelay.Type|null); + + /** CircuitRelay srcPeer */ + srcPeer?: (CircuitRelay.IPeer|null); + + /** CircuitRelay dstPeer */ + dstPeer?: (CircuitRelay.IPeer|null); + + /** CircuitRelay code */ + code?: (CircuitRelay.Status|null); +} + +/** Represents a CircuitRelay. */ +export class CircuitRelay implements ICircuitRelay { + + /** + * Constructs a new CircuitRelay. + * @param [p] Properties to set + */ + constructor(p?: ICircuitRelay); + + /** CircuitRelay type. */ + public type: CircuitRelay.Type; + + /** CircuitRelay srcPeer. */ + public srcPeer?: (CircuitRelay.IPeer|null); + + /** CircuitRelay dstPeer. */ + public dstPeer?: (CircuitRelay.IPeer|null); + + /** CircuitRelay code. */ + public code: CircuitRelay.Status; + + /** + * Encodes the specified CircuitRelay message. Does not implicitly {@link CircuitRelay.verify|verify} messages. + * @param m CircuitRelay message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: ICircuitRelay, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a CircuitRelay message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns CircuitRelay + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): CircuitRelay; + + /** + * Creates a CircuitRelay message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns CircuitRelay + */ + public static fromObject(d: { [k: string]: any }): CircuitRelay; + + /** + * Creates a plain object from a CircuitRelay message. Also converts values to other types if specified. + * @param m CircuitRelay + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: CircuitRelay, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this CircuitRelay to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +export namespace CircuitRelay { + + /** Status enum. */ + enum Status { + SUCCESS = 100, + HOP_SRC_ADDR_TOO_LONG = 220, + HOP_DST_ADDR_TOO_LONG = 221, + HOP_SRC_MULTIADDR_INVALID = 250, + HOP_DST_MULTIADDR_INVALID = 251, + HOP_NO_CONN_TO_DST = 260, + HOP_CANT_DIAL_DST = 261, + HOP_CANT_OPEN_DST_STREAM = 262, + HOP_CANT_SPEAK_RELAY = 270, + HOP_CANT_RELAY_TO_SELF = 280, + STOP_SRC_ADDR_TOO_LONG = 320, + STOP_DST_ADDR_TOO_LONG = 321, + STOP_SRC_MULTIADDR_INVALID = 350, + STOP_DST_MULTIADDR_INVALID = 351, + STOP_RELAY_REFUSED = 390, + MALFORMED_MESSAGE = 400 + } + + /** Type enum. */ + enum Type { + HOP = 1, + STOP = 2, + STATUS = 3, + CAN_HOP = 4 + } + + /** Properties of a Peer. */ + interface IPeer { + + /** Peer id */ + id: Uint8Array; + + /** Peer addrs */ + addrs?: (Uint8Array[]|null); + } + + /** Represents a Peer. */ + class Peer implements IPeer { + + /** + * Constructs a new Peer. + * @param [p] Properties to set + */ + constructor(p?: CircuitRelay.IPeer); + + /** Peer id. */ + public id: Uint8Array; + + /** Peer addrs. */ + public addrs: Uint8Array[]; + + /** + * Encodes the specified Peer message. Does not implicitly {@link CircuitRelay.Peer.verify|verify} messages. + * @param m Peer message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: CircuitRelay.IPeer, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Peer message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Peer + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): CircuitRelay.Peer; + + /** + * Creates a Peer message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Peer + */ + public static fromObject(d: { [k: string]: any }): CircuitRelay.Peer; + + /** + * Creates a plain object from a Peer message. Also converts values to other types if specified. + * @param m Peer + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: CircuitRelay.Peer, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Peer to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } +} diff --git a/src/circuit/protocol/index.js b/src/circuit/protocol/index.js index a9d3e31a6f..be12eb9b37 100644 --- a/src/circuit/protocol/index.js +++ b/src/circuit/protocol/index.js @@ -1,46 +1,530 @@ -'use strict' -const protobuf = require('protons') - -/** @type {{CircuitRelay: import('../../types').CircuitMessageProto}} */ -module.exports = protobuf(` -message CircuitRelay { - - enum Status { - SUCCESS = 100; - HOP_SRC_ADDR_TOO_LONG = 220; - HOP_DST_ADDR_TOO_LONG = 221; - HOP_SRC_MULTIADDR_INVALID = 250; - HOP_DST_MULTIADDR_INVALID = 251; - HOP_NO_CONN_TO_DST = 260; - HOP_CANT_DIAL_DST = 261; - HOP_CANT_OPEN_DST_STREAM = 262; - HOP_CANT_SPEAK_RELAY = 270; - HOP_CANT_RELAY_TO_SELF = 280; - STOP_SRC_ADDR_TOO_LONG = 320; - STOP_DST_ADDR_TOO_LONG = 321; - STOP_SRC_MULTIADDR_INVALID = 350; - STOP_DST_MULTIADDR_INVALID = 351; - STOP_RELAY_REFUSED = 390; - MALFORMED_MESSAGE = 400; - } - - enum Type { // RPC identifier, either HOP, STOP or STATUS - HOP = 1; - STOP = 2; - STATUS = 3; - CAN_HOP = 4; - } - - message Peer { - required bytes id = 1; // peer id - repeated bytes addrs = 2; // peer's known addresses - } - - optional Type type = 1; // Type of the message - - optional Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STATUS - optional Peer dstPeer = 3; - - optional Status code = 4; // Status code, used when Type is STATUS -} -`) +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.CircuitRelay = (function() { + + /** + * Properties of a CircuitRelay. + * @exports ICircuitRelay + * @interface ICircuitRelay + * @property {CircuitRelay.Type|null} [type] CircuitRelay type + * @property {CircuitRelay.IPeer|null} [srcPeer] CircuitRelay srcPeer + * @property {CircuitRelay.IPeer|null} [dstPeer] CircuitRelay dstPeer + * @property {CircuitRelay.Status|null} [code] CircuitRelay code + */ + + /** + * Constructs a new CircuitRelay. + * @exports CircuitRelay + * @classdesc Represents a CircuitRelay. + * @implements ICircuitRelay + * @constructor + * @param {ICircuitRelay=} [p] Properties to set + */ + function CircuitRelay(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * CircuitRelay type. + * @member {CircuitRelay.Type} type + * @memberof CircuitRelay + * @instance + */ + CircuitRelay.prototype.type = 1; + + /** + * CircuitRelay srcPeer. + * @member {CircuitRelay.IPeer|null|undefined} srcPeer + * @memberof CircuitRelay + * @instance + */ + CircuitRelay.prototype.srcPeer = null; + + /** + * CircuitRelay dstPeer. + * @member {CircuitRelay.IPeer|null|undefined} dstPeer + * @memberof CircuitRelay + * @instance + */ + CircuitRelay.prototype.dstPeer = null; + + /** + * CircuitRelay code. + * @member {CircuitRelay.Status} code + * @memberof CircuitRelay + * @instance + */ + CircuitRelay.prototype.code = 100; + + /** + * Encodes the specified CircuitRelay message. Does not implicitly {@link CircuitRelay.verify|verify} messages. + * @function encode + * @memberof CircuitRelay + * @static + * @param {ICircuitRelay} m CircuitRelay message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CircuitRelay.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.type != null && Object.hasOwnProperty.call(m, "type")) + w.uint32(8).int32(m.type); + if (m.srcPeer != null && Object.hasOwnProperty.call(m, "srcPeer")) + $root.CircuitRelay.Peer.encode(m.srcPeer, w.uint32(18).fork()).ldelim(); + if (m.dstPeer != null && Object.hasOwnProperty.call(m, "dstPeer")) + $root.CircuitRelay.Peer.encode(m.dstPeer, w.uint32(26).fork()).ldelim(); + if (m.code != null && Object.hasOwnProperty.call(m, "code")) + w.uint32(32).int32(m.code); + return w; + }; + + /** + * Decodes a CircuitRelay message from the specified reader or buffer. + * @function decode + * @memberof CircuitRelay + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {CircuitRelay} CircuitRelay + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CircuitRelay.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.CircuitRelay(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.type = r.int32(); + break; + case 2: + m.srcPeer = $root.CircuitRelay.Peer.decode(r, r.uint32()); + break; + case 3: + m.dstPeer = $root.CircuitRelay.Peer.decode(r, r.uint32()); + break; + case 4: + m.code = r.int32(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates a CircuitRelay message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof CircuitRelay + * @static + * @param {Object.} d Plain object + * @returns {CircuitRelay} CircuitRelay + */ + CircuitRelay.fromObject = function fromObject(d) { + if (d instanceof $root.CircuitRelay) + return d; + var m = new $root.CircuitRelay(); + switch (d.type) { + case "HOP": + case 1: + m.type = 1; + break; + case "STOP": + case 2: + m.type = 2; + break; + case "STATUS": + case 3: + m.type = 3; + break; + case "CAN_HOP": + case 4: + m.type = 4; + break; + } + if (d.srcPeer != null) { + if (typeof d.srcPeer !== "object") + throw TypeError(".CircuitRelay.srcPeer: object expected"); + m.srcPeer = $root.CircuitRelay.Peer.fromObject(d.srcPeer); + } + if (d.dstPeer != null) { + if (typeof d.dstPeer !== "object") + throw TypeError(".CircuitRelay.dstPeer: object expected"); + m.dstPeer = $root.CircuitRelay.Peer.fromObject(d.dstPeer); + } + switch (d.code) { + case "SUCCESS": + case 100: + m.code = 100; + break; + case "HOP_SRC_ADDR_TOO_LONG": + case 220: + m.code = 220; + break; + case "HOP_DST_ADDR_TOO_LONG": + case 221: + m.code = 221; + break; + case "HOP_SRC_MULTIADDR_INVALID": + case 250: + m.code = 250; + break; + case "HOP_DST_MULTIADDR_INVALID": + case 251: + m.code = 251; + break; + case "HOP_NO_CONN_TO_DST": + case 260: + m.code = 260; + break; + case "HOP_CANT_DIAL_DST": + case 261: + m.code = 261; + break; + case "HOP_CANT_OPEN_DST_STREAM": + case 262: + m.code = 262; + break; + case "HOP_CANT_SPEAK_RELAY": + case 270: + m.code = 270; + break; + case "HOP_CANT_RELAY_TO_SELF": + case 280: + m.code = 280; + break; + case "STOP_SRC_ADDR_TOO_LONG": + case 320: + m.code = 320; + break; + case "STOP_DST_ADDR_TOO_LONG": + case 321: + m.code = 321; + break; + case "STOP_SRC_MULTIADDR_INVALID": + case 350: + m.code = 350; + break; + case "STOP_DST_MULTIADDR_INVALID": + case 351: + m.code = 351; + break; + case "STOP_RELAY_REFUSED": + case 390: + m.code = 390; + break; + case "MALFORMED_MESSAGE": + case 400: + m.code = 400; + break; + } + return m; + }; + + /** + * Creates a plain object from a CircuitRelay message. Also converts values to other types if specified. + * @function toObject + * @memberof CircuitRelay + * @static + * @param {CircuitRelay} m CircuitRelay + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + CircuitRelay.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + d.type = o.enums === String ? "HOP" : 1; + d.srcPeer = null; + d.dstPeer = null; + d.code = o.enums === String ? "SUCCESS" : 100; + } + if (m.type != null && m.hasOwnProperty("type")) { + d.type = o.enums === String ? $root.CircuitRelay.Type[m.type] : m.type; + } + if (m.srcPeer != null && m.hasOwnProperty("srcPeer")) { + d.srcPeer = $root.CircuitRelay.Peer.toObject(m.srcPeer, o); + } + if (m.dstPeer != null && m.hasOwnProperty("dstPeer")) { + d.dstPeer = $root.CircuitRelay.Peer.toObject(m.dstPeer, o); + } + if (m.code != null && m.hasOwnProperty("code")) { + d.code = o.enums === String ? $root.CircuitRelay.Status[m.code] : m.code; + } + return d; + }; + + /** + * Converts this CircuitRelay to JSON. + * @function toJSON + * @memberof CircuitRelay + * @instance + * @returns {Object.} JSON object + */ + CircuitRelay.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Status enum. + * @name CircuitRelay.Status + * @enum {number} + * @property {number} SUCCESS=100 SUCCESS value + * @property {number} HOP_SRC_ADDR_TOO_LONG=220 HOP_SRC_ADDR_TOO_LONG value + * @property {number} HOP_DST_ADDR_TOO_LONG=221 HOP_DST_ADDR_TOO_LONG value + * @property {number} HOP_SRC_MULTIADDR_INVALID=250 HOP_SRC_MULTIADDR_INVALID value + * @property {number} HOP_DST_MULTIADDR_INVALID=251 HOP_DST_MULTIADDR_INVALID value + * @property {number} HOP_NO_CONN_TO_DST=260 HOP_NO_CONN_TO_DST value + * @property {number} HOP_CANT_DIAL_DST=261 HOP_CANT_DIAL_DST value + * @property {number} HOP_CANT_OPEN_DST_STREAM=262 HOP_CANT_OPEN_DST_STREAM value + * @property {number} HOP_CANT_SPEAK_RELAY=270 HOP_CANT_SPEAK_RELAY value + * @property {number} HOP_CANT_RELAY_TO_SELF=280 HOP_CANT_RELAY_TO_SELF value + * @property {number} STOP_SRC_ADDR_TOO_LONG=320 STOP_SRC_ADDR_TOO_LONG value + * @property {number} STOP_DST_ADDR_TOO_LONG=321 STOP_DST_ADDR_TOO_LONG value + * @property {number} STOP_SRC_MULTIADDR_INVALID=350 STOP_SRC_MULTIADDR_INVALID value + * @property {number} STOP_DST_MULTIADDR_INVALID=351 STOP_DST_MULTIADDR_INVALID value + * @property {number} STOP_RELAY_REFUSED=390 STOP_RELAY_REFUSED value + * @property {number} MALFORMED_MESSAGE=400 MALFORMED_MESSAGE value + */ + CircuitRelay.Status = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[100] = "SUCCESS"] = 100; + values[valuesById[220] = "HOP_SRC_ADDR_TOO_LONG"] = 220; + values[valuesById[221] = "HOP_DST_ADDR_TOO_LONG"] = 221; + values[valuesById[250] = "HOP_SRC_MULTIADDR_INVALID"] = 250; + values[valuesById[251] = "HOP_DST_MULTIADDR_INVALID"] = 251; + values[valuesById[260] = "HOP_NO_CONN_TO_DST"] = 260; + values[valuesById[261] = "HOP_CANT_DIAL_DST"] = 261; + values[valuesById[262] = "HOP_CANT_OPEN_DST_STREAM"] = 262; + values[valuesById[270] = "HOP_CANT_SPEAK_RELAY"] = 270; + values[valuesById[280] = "HOP_CANT_RELAY_TO_SELF"] = 280; + values[valuesById[320] = "STOP_SRC_ADDR_TOO_LONG"] = 320; + values[valuesById[321] = "STOP_DST_ADDR_TOO_LONG"] = 321; + values[valuesById[350] = "STOP_SRC_MULTIADDR_INVALID"] = 350; + values[valuesById[351] = "STOP_DST_MULTIADDR_INVALID"] = 351; + values[valuesById[390] = "STOP_RELAY_REFUSED"] = 390; + values[valuesById[400] = "MALFORMED_MESSAGE"] = 400; + return values; + })(); + + /** + * Type enum. + * @name CircuitRelay.Type + * @enum {number} + * @property {number} HOP=1 HOP value + * @property {number} STOP=2 STOP value + * @property {number} STATUS=3 STATUS value + * @property {number} CAN_HOP=4 CAN_HOP value + */ + CircuitRelay.Type = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[1] = "HOP"] = 1; + values[valuesById[2] = "STOP"] = 2; + values[valuesById[3] = "STATUS"] = 3; + values[valuesById[4] = "CAN_HOP"] = 4; + return values; + })(); + + CircuitRelay.Peer = (function() { + + /** + * Properties of a Peer. + * @memberof CircuitRelay + * @interface IPeer + * @property {Uint8Array} id Peer id + * @property {Array.|null} [addrs] Peer addrs + */ + + /** + * Constructs a new Peer. + * @memberof CircuitRelay + * @classdesc Represents a Peer. + * @implements IPeer + * @constructor + * @param {CircuitRelay.IPeer=} [p] Properties to set + */ + function Peer(p) { + this.addrs = []; + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Peer id. + * @member {Uint8Array} id + * @memberof CircuitRelay.Peer + * @instance + */ + Peer.prototype.id = $util.newBuffer([]); + + /** + * Peer addrs. + * @member {Array.} addrs + * @memberof CircuitRelay.Peer + * @instance + */ + Peer.prototype.addrs = $util.emptyArray; + + /** + * Encodes the specified Peer message. Does not implicitly {@link CircuitRelay.Peer.verify|verify} messages. + * @function encode + * @memberof CircuitRelay.Peer + * @static + * @param {CircuitRelay.IPeer} m Peer message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Peer.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + w.uint32(10).bytes(m.id); + if (m.addrs != null && m.addrs.length) { + for (var i = 0; i < m.addrs.length; ++i) + w.uint32(18).bytes(m.addrs[i]); + } + return w; + }; + + /** + * Decodes a Peer message from the specified reader or buffer. + * @function decode + * @memberof CircuitRelay.Peer + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {CircuitRelay.Peer} Peer + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Peer.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.CircuitRelay.Peer(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.id = r.bytes(); + break; + case 2: + if (!(m.addrs && m.addrs.length)) + m.addrs = []; + m.addrs.push(r.bytes()); + break; + default: + r.skipType(t & 7); + break; + } + } + if (!m.hasOwnProperty("id")) + throw $util.ProtocolError("missing required 'id'", { instance: m }); + return m; + }; + + /** + * Creates a Peer message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof CircuitRelay.Peer + * @static + * @param {Object.} d Plain object + * @returns {CircuitRelay.Peer} Peer + */ + Peer.fromObject = function fromObject(d) { + if (d instanceof $root.CircuitRelay.Peer) + return d; + var m = new $root.CircuitRelay.Peer(); + if (d.id != null) { + if (typeof d.id === "string") + $util.base64.decode(d.id, m.id = $util.newBuffer($util.base64.length(d.id)), 0); + else if (d.id.length) + m.id = d.id; + } + if (d.addrs) { + if (!Array.isArray(d.addrs)) + throw TypeError(".CircuitRelay.Peer.addrs: array expected"); + m.addrs = []; + for (var i = 0; i < d.addrs.length; ++i) { + if (typeof d.addrs[i] === "string") + $util.base64.decode(d.addrs[i], m.addrs[i] = $util.newBuffer($util.base64.length(d.addrs[i])), 0); + else if (d.addrs[i].length) + m.addrs[i] = d.addrs[i]; + } + } + return m; + }; + + /** + * Creates a plain object from a Peer message. Also converts values to other types if specified. + * @function toObject + * @memberof CircuitRelay.Peer + * @static + * @param {CircuitRelay.Peer} m Peer + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Peer.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.arrays || o.defaults) { + d.addrs = []; + } + if (o.defaults) { + if (o.bytes === String) + d.id = ""; + else { + d.id = []; + if (o.bytes !== Array) + d.id = $util.newBuffer(d.id); + } + } + if (m.id != null && m.hasOwnProperty("id")) { + d.id = o.bytes === String ? $util.base64.encode(m.id, 0, m.id.length) : o.bytes === Array ? Array.prototype.slice.call(m.id) : m.id; + } + if (m.addrs && m.addrs.length) { + d.addrs = []; + for (var j = 0; j < m.addrs.length; ++j) { + d.addrs[j] = o.bytes === String ? $util.base64.encode(m.addrs[j], 0, m.addrs[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.addrs[j]) : m.addrs[j]; + } + } + return d; + }; + + /** + * Converts this Peer to JSON. + * @function toJSON + * @memberof CircuitRelay.Peer + * @instance + * @returns {Object.} JSON object + */ + Peer.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Peer; + })(); + + return CircuitRelay; +})(); + +module.exports = $root; diff --git a/src/circuit/protocol/index.proto b/src/circuit/protocol/index.proto new file mode 100644 index 0000000000..259ad2835a --- /dev/null +++ b/src/circuit/protocol/index.proto @@ -0,0 +1,42 @@ +syntax = "proto2"; + +message CircuitRelay { + + enum Status { + SUCCESS = 100; + HOP_SRC_ADDR_TOO_LONG = 220; + HOP_DST_ADDR_TOO_LONG = 221; + HOP_SRC_MULTIADDR_INVALID = 250; + HOP_DST_MULTIADDR_INVALID = 251; + HOP_NO_CONN_TO_DST = 260; + HOP_CANT_DIAL_DST = 261; + HOP_CANT_OPEN_DST_STREAM = 262; + HOP_CANT_SPEAK_RELAY = 270; + HOP_CANT_RELAY_TO_SELF = 280; + STOP_SRC_ADDR_TOO_LONG = 320; + STOP_DST_ADDR_TOO_LONG = 321; + STOP_SRC_MULTIADDR_INVALID = 350; + STOP_DST_MULTIADDR_INVALID = 351; + STOP_RELAY_REFUSED = 390; + MALFORMED_MESSAGE = 400; + } + + enum Type { // RPC identifier, either HOP, STOP or STATUS + HOP = 1; + STOP = 2; + STATUS = 3; + CAN_HOP = 4; + } + + message Peer { + required bytes id = 1; // peer id + repeated bytes addrs = 2; // peer's known addresses + } + + optional Type type = 1; // Type of the message + + optional Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STATUS + optional Peer dstPeer = 3; + + optional Status code = 4; // Status code, used when Type is STATUS +} diff --git a/src/circuit/transport.js b/src/circuit/transport.js index fc2ddad4f0..b220620398 100644 --- a/src/circuit/transport.js +++ b/src/circuit/transport.js @@ -5,10 +5,12 @@ const log = Object.assign(debug('libp2p:circuit'), { error: debug('libp2p:circuit:err') }) +const errCode = require('err-code') const mafmt = require('mafmt') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const { CircuitRelay: CircuitPB } = require('./protocol') +const { codes } = require('../errors') const toConnection = require('libp2p-utils/src/stream-to-ma-conn') @@ -21,10 +23,8 @@ const StreamHandler = require('./circuit/stream-handler') const transportSymbol = Symbol.for('@libp2p/js-libp2p-circuit/circuit') /** - * @typedef {import('multiaddr')} Multiaddr * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream - * @typedef {import('../types').CircuitRequest} CircuitRequest */ class Circuit { @@ -54,7 +54,7 @@ class Circuit { * @param {MuxedStream} props.stream */ async _onProtocol ({ connection, stream }) { - /** @type {import('./circuit/stream-handler')} */ + /** @type {import('./circuit/stream-handler')} */ const streamHandler = new StreamHandler({ stream }) const request = await streamHandler.read() @@ -96,8 +96,10 @@ class Circuit { } if (virtualConnection) { - const remoteAddr = multiaddr(request.dstPeer.addrs[0]) - const localAddr = multiaddr(request.srcPeer.addrs[0]) + // @ts-ignore dst peer will not be undefined + const remoteAddr = new Multiaddr(request.dstPeer.addrs[0]) + // @ts-ignore src peer will not be undefined + const localAddr = new Multiaddr(request.srcPeer.addrs[0]) const maConn = toConnection({ stream: virtualConnection, remoteAddr, @@ -123,10 +125,19 @@ class Circuit { async dial (ma, options) { // Check the multiaddr to see if it contains a relay and a destination peer const addrs = ma.toString().split('/p2p-circuit') - const relayAddr = multiaddr(addrs[0]) - const destinationAddr = multiaddr(addrs[addrs.length - 1]) - const relayPeer = PeerId.createFromCID(relayAddr.getPeerId()) - const destinationPeer = PeerId.createFromCID(destinationAddr.getPeerId()) + const relayAddr = new Multiaddr(addrs[0]) + const destinationAddr = new Multiaddr(addrs[addrs.length - 1]) + const relayId = relayAddr.getPeerId() + const destinationId = destinationAddr.getPeerId() + + if (!relayId || !destinationId) { + const errMsg = 'Circuit relay dial failed as addresses did not have peer id' + log.error(errMsg) + throw errCode(new Error(errMsg), codes.ERR_RELAYED_DIAL) + } + + const relayPeer = PeerId.createFromCID(relayId) + const destinationPeer = PeerId.createFromCID(destinationId) let disconnectOnFailure = false let relayConnection = this._connectionManager.get(relayPeer) @@ -146,7 +157,7 @@ class Circuit { }, dstPeer: { id: destinationPeer.toBytes(), - addrs: [multiaddr(destinationAddr).bytes] + addrs: [new Multiaddr(destinationAddr).bytes] } } }) diff --git a/src/config.js b/src/config.js index 6eefa42556..bbcc6dab47 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,7 @@ 'use strict' const mergeOptions = require('merge-options') +// @ts-ignore no types in multiaddr path const { dnsaddrResolver } = require('multiaddr/src/resolvers') const Constants = require('./constants') @@ -10,11 +11,18 @@ const RelayConstants = require('./circuit/constants') const { publicAddressesFirst } = require('libp2p-utils/src/address-sort') const { FaultTolerance } = require('./transport-manager') +/** + * @typedef {import('multiaddr').Multiaddr} Multiaddr + * @typedef {import('.').Libp2pOptions} Libp2pOptions + * @typedef {import('.').constructorOptions} constructorOptions + */ + const DefaultConfig = { addresses: { listen: [], announce: [], - noAnnounce: [] + noAnnounce: [], + announceFilter: (/** @type {Multiaddr[]} */ multiaddrs) => multiaddrs }, connectionManager: { minConnections: 25 @@ -95,10 +103,15 @@ const DefaultConfig = { } } +/** + * @param {Libp2pOptions} opts + * @returns {DefaultConfig & Libp2pOptions & constructorOptions} + */ module.exports.validate = (opts) => { - opts = mergeOptions(DefaultConfig, opts) + /** @type {DefaultConfig & Libp2pOptions & constructorOptions} */ + const resultingOptions = mergeOptions(DefaultConfig, opts) - if (opts.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport") + if (resultingOptions.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport") - return opts + return resultingOptions } diff --git a/src/connection-manager/index.js b/src/connection-manager/index.js index 1bdef27af9..985d26f145 100644 --- a/src/connection-manager/index.js +++ b/src/connection-manager/index.js @@ -8,10 +8,9 @@ const log = Object.assign(debug('libp2p:connection-manager'), { const errcode = require('err-code') const mergeOptions = require('merge-options') const LatencyMonitor = require('./latency-monitor') +// @ts-ignore retimer does not have types const retimer = require('retimer') -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const PeerId = require('peer-id') @@ -188,8 +187,10 @@ class ConnectionManager extends EventEmitter { _checkMetrics () { if (this._libp2p.metrics) { const movingAverages = this._libp2p.metrics.global.movingAverages + // @ts-ignore moving averages object types const received = movingAverages.dataReceived[this._options.movingAverageInterval].movingAverage() this._checkMaxLimit('maxReceivedData', received) + // @ts-ignore moving averages object types const sent = movingAverages.dataSent[this._options.movingAverageInterval].movingAverage() this._checkMaxLimit('maxSentData', sent) const total = received + sent @@ -362,7 +363,7 @@ class ConnectionManager extends EventEmitter { */ _maybeDisconnectOne () { if (this._options.minConnections < this.connections.size) { - const peerValues = Array.from(this._peerValues).sort(byPeerValue) + const peerValues = Array.from(new Map([...this._peerValues.entries()].sort((a, b) => a[1] - b[1]))) log('%s: sorted peer values: %j', this._peerId, peerValues) const disconnectPeer = peerValues[0] if (disconnectPeer) { @@ -381,7 +382,3 @@ class ConnectionManager extends EventEmitter { } module.exports = ConnectionManager - -function byPeerValue (peerValueEntryA, peerValueEntryB) { - return peerValueEntryA[1] - peerValueEntryB[1] -} diff --git a/src/connection-manager/latency-monitor.js b/src/connection-manager/latency-monitor.js index d5b44e9ab4..5253c2ae71 100644 --- a/src/connection-manager/latency-monitor.js +++ b/src/connection-manager/latency-monitor.js @@ -5,8 +5,6 @@ * This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE) */ -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const VisibilityChangeEmitter = require('./visibility-change-emitter') const debug = require('debug')('latency-monitor:LatencyMonitor') @@ -59,7 +57,8 @@ class LatencyMonitor extends EventEmitter { that._latecyCheckMultiply = 2 * (that.latencyRandomPercentage / 100.0) * that.latencyCheckIntervalMs that._latecyCheckSubtract = that._latecyCheckMultiply / 2 - that.dataEmitIntervalMs = (dataEmitIntervalMs === null || dataEmitIntervalMs === 0) ? undefined + that.dataEmitIntervalMs = (dataEmitIntervalMs === null || dataEmitIntervalMs === 0) + ? undefined : dataEmitIntervalMs || 5 * 1000 // 5s debug('latencyCheckIntervalMs: %s dataEmitIntervalMs: %s', that.latencyCheckIntervalMs, that.dataEmitIntervalMs) @@ -174,7 +173,8 @@ class LatencyMonitor extends EventEmitter { events: this._latencyData.events, minMs: this._latencyData.minMs, maxMs: this._latencyData.maxMs, - avgMs: this._latencyData.events ? this._latencyData.totalMs / this._latencyData.events + avgMs: this._latencyData.events + ? this._latencyData.totalMs / this._latencyData.events : Number.POSITIVE_INFINITY, lengthMs: this.getDeltaMS(this._latencyData.startTime) } diff --git a/src/connection-manager/visibility-change-emitter.js b/src/connection-manager/visibility-change-emitter.js index bf7da71b82..9efb6ffb33 100644 --- a/src/connection-manager/visibility-change-emitter.js +++ b/src/connection-manager/visibility-change-emitter.js @@ -6,8 +6,6 @@ */ 'use strict' -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const debug = require('debug')('latency-monitor:VisibilityChangeEmitter') diff --git a/src/content-routing/index.js b/src/content-routing/index.js index f409daa3c4..44f1d9c580 100644 --- a/src/content-routing/index.js +++ b/src/content-routing/index.js @@ -14,8 +14,9 @@ const { pipe } = require('it-pipe') /** * @typedef {import('peer-id')} PeerId - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('multiaddr').Multiaddr} Multiaddr * @typedef {import('cids')} CID + * @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule */ /** @@ -31,6 +32,7 @@ class ContentRouting { */ constructor (libp2p) { this.libp2p = libp2p + /** @type {ContentRoutingModule[]} */ this.routers = libp2p._modules.contentRouting || [] this.dht = libp2p._dht diff --git a/src/content-routing/utils.js b/src/content-routing/utils.js index 55ba3a7516..c43ec9a98e 100644 --- a/src/content-routing/utils.js +++ b/src/content-routing/utils.js @@ -7,7 +7,7 @@ const take = require('it-take') /** * @typedef {import('peer-id')} PeerId - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('multiaddr').Multiaddr} Multiaddr */ /** diff --git a/src/dialer/dial-request.js b/src/dialer/dial-request.js index 8027bacc76..3f6fc18ae1 100644 --- a/src/dialer/dial-request.js +++ b/src/dialer/dial-request.js @@ -3,13 +3,14 @@ const errCode = require('err-code') const AbortController = require('abort-controller').default const { anySignal } = require('any-signal') +// @ts-ignore p-fifo does not export types const FIFO = require('p-fifo') const pAny = require('p-any') /** * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('./')} Dialer - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('multiaddr').Multiaddr} Multiaddr */ /** diff --git a/src/dialer/index.js b/src/dialer/index.js index 17b96e82b9..1225e1cc28 100644 --- a/src/dialer/index.js +++ b/src/dialer/index.js @@ -5,7 +5,8 @@ const log = Object.assign(debug('libp2p:dialer'), { error: debug('libp2p:dialer:err') }) const errCode = require('err-code') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') +// @ts-ignore timeout-abourt-controles does not export types const TimeoutController = require('timeout-abort-controller') const { anySignal } = require('any-signal') @@ -22,7 +23,6 @@ const { /** * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection - * @typedef {import('multiaddr')} Multiaddr * @typedef {import('peer-id')} PeerId * @typedef {import('../peer-store')} PeerStore * @typedef {import('../peer-store/address-book').Address} Address @@ -38,9 +38,9 @@ const { * * @typedef {Object} DialerOptions * @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial. - * @property {number} [concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials. - * @property {number} [perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer. - * @property {number} [timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take. + * @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials. + * @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer. + * @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take. * @property {Record} [resolvers = {}] - multiaddr resolvers to use when dialing * * @typedef DialTarget @@ -50,7 +50,7 @@ const { * @typedef PendingDial * @property {DialRequest} dialRequest * @property {TimeoutController} controller - * @property {Promise} promise + * @property {Promise} promise * @property {function():void} destroy */ @@ -63,22 +63,22 @@ class Dialer { transportManager, peerStore, addressSorter = publicAddressesFirst, - concurrency = MAX_PARALLEL_DIALS, - timeout = DIAL_TIMEOUT, - perPeerLimit = MAX_PER_PEER_DIALS, + maxParallelDials = MAX_PARALLEL_DIALS, + dialTimeout = DIAL_TIMEOUT, + maxDialsPerPeer = MAX_PER_PEER_DIALS, resolvers = {} }) { this.transportManager = transportManager this.peerStore = peerStore this.addressSorter = addressSorter - this.concurrency = concurrency - this.timeout = timeout - this.perPeerLimit = perPeerLimit - this.tokens = [...new Array(concurrency)].map((_, index) => index) + this.maxParallelDials = maxParallelDials + this.timeout = dialTimeout + this.maxDialsPerPeer = maxDialsPerPeer + this.tokens = [...new Array(maxParallelDials)].map((_, index) => index) this._pendingDials = new Map() for (const [key, value] of Object.entries(resolvers)) { - multiaddr.resolvers.set(key, value) + Multiaddr.resolvers.set(key, value) } } @@ -150,11 +150,12 @@ class Dialer { // If received a multiaddr to dial, it should be the first to use // But, if we know other multiaddrs for the peer, we should try them too. - if (multiaddr.isMultiaddr(peer)) { + if (Multiaddr.isMultiaddr(peer)) { knownAddrs = knownAddrs.filter((addr) => !peer.equals(addr)) knownAddrs.unshift(peer) } + /** @type {Multiaddr[]} */ const addrs = [] for (const a of knownAddrs) { const resolvedAddrs = await this._resolve(a) @@ -177,6 +178,10 @@ class Dialer { * @returns {PendingDial} */ _createPendingDial (dialTarget, options = {}) { + /** + * @param {Multiaddr} addr + * @param {{ signal: { aborted: any; }; }} options + */ const dialAction = (addr, options) => { if (options.signal.aborted) throw errCode(new Error('already aborted'), codes.ERR_ALREADY_ABORTED) return this.transportManager.dial(addr, options) @@ -207,13 +212,19 @@ class Dialer { return pendingDial } + /** + * @param {number} num + */ getTokens (num) { - const total = Math.min(num, this.perPeerLimit, this.tokens.length) + const total = Math.min(num, this.maxDialsPerPeer, this.tokens.length) const tokens = this.tokens.splice(0, total) log('%d tokens request, returning %d, %d remaining', num, total, this.tokens.length) return tokens } + /** + * @param {number} token + */ releaseToken (token) { // Guard against duplicate releases if (this.tokens.indexOf(token) > -1) return @@ -259,7 +270,7 @@ class Dialer { */ async _resolveRecord (ma) { try { - ma = multiaddr(ma.toString()) // Use current multiaddr module + ma = new Multiaddr(ma.toString()) // Use current multiaddr module const multiaddrs = await ma.resolve() return multiaddrs } catch (_) { diff --git a/src/errors.js b/src/errors.js index cbff9aa82e..14752b2706 100644 --- a/src/errors.js +++ b/src/errors.js @@ -16,6 +16,7 @@ exports.codes = { ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED', ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED', ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES', + ERR_RELAYED_DIAL: 'ERR_RELAYED_DIAL', ERR_DIALED_SELF: 'ERR_DIALED_SELF', ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF', ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT', diff --git a/src/get-peer.js b/src/get-peer.js index 807c333384..a0de9ef8b6 100644 --- a/src/get-peer.js +++ b/src/get-peer.js @@ -1,15 +1,11 @@ 'use strict' const PeerId = require('peer-id') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const errCode = require('err-code') const { codes } = require('./errors') -/** - * @typedef {import('multiaddr')} Multiaddr - */ - /** * Converts the given `peer` to a `Peer` object. * If a multiaddr is received, the addressBook is updated. @@ -19,14 +15,23 @@ const { codes } = require('./errors') */ function getPeer (peer) { if (typeof peer === 'string') { - peer = multiaddr(peer) + peer = new Multiaddr(peer) } let addr - if (multiaddr.isMultiaddr(peer)) { + if (Multiaddr.isMultiaddr(peer)) { addr = peer + const idStr = peer.getPeerId() + + if (!idStr) { + throw errCode( + new Error(`${peer} does not have a valid peer type`), + codes.ERR_INVALID_MULTIADDR + ) + } + try { - peer = PeerId.createFromB58String(peer.getPeerId()) + peer = PeerId.createFromB58String(idStr) } catch (err) { throw errCode( new Error(`${peer} is not a valid peer type`), diff --git a/src/identify/index.js b/src/identify/index.js index 127891e845..498ea0e1f3 100644 --- a/src/identify/index.js +++ b/src/identify/index.js @@ -5,14 +5,14 @@ const log = Object.assign(debug('libp2p:identify'), { error: debug('libp2p:identify:err') }) const errCode = require('err-code') -const pb = require('it-protocol-buffers') const lp = require('it-length-prefixed') const { pipe } = require('it-pipe') const { collect, take, consume } = require('streaming-iterables') const uint8ArrayFromString = require('uint8arrays/from-string') const PeerId = require('peer-id') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') +// @ts-ignore it-buffer does not have types const { toBuffer } = require('it-buffer') const Message = require('./message') @@ -23,7 +23,6 @@ const PeerRecord = require('../record/peer-record') const { MULTICODEC_IDENTIFY, MULTICODEC_IDENTIFY_PUSH, - AGENT_VERSION, PROTOCOL_VERSION } = require('./consts') @@ -34,6 +33,11 @@ const { codes } = require('../errors') * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream */ +/** + * @typedef {Object} HostProperties + * @property {string} agentVersion + */ + class IdentifyService { /** * @class @@ -51,7 +55,6 @@ class IdentifyService { // Store self host metadata this._host = { - agentVersion: AGENT_VERSION, protocolVersion: PROTOCOL_VERSION, ...libp2p._options.host } @@ -94,12 +97,12 @@ class IdentifyService { const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH) await pipe( - [{ + [Message.Identify.encode({ listenAddrs, signedPeerRecord, protocols - }], - pb.encode(Message), + }).finish()], + lp.encode(), stream, consume ) @@ -160,12 +163,12 @@ class IdentifyService { let message try { - message = Message.decode(data) + message = Message.Identify.decode(data) } catch (err) { throw errCode(err, codes.ERR_INVALID_MESSAGE) } - let { + const { publicKey, listenAddrs, protocols, @@ -180,7 +183,7 @@ class IdentifyService { } // Get the observedAddr if there is one - observedAddr = IdentifyService.getCleanMultiaddr(observedAddr) + const cleanObservedAddr = IdentifyService.getCleanMultiaddr(observedAddr) try { const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN) @@ -194,7 +197,7 @@ class IdentifyService { // LEGACY: Update peers data in PeerStore try { - this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr))) + this.peerStore.addressBook.set(id, listenAddrs.map((addr) => new Multiaddr(addr))) } catch (err) { log.error('received invalid addrs', err) } @@ -203,7 +206,7 @@ class IdentifyService { this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion)) // TODO: Add and score our observed addr - log('received observed address of %s', observedAddr) + log('received observed address of %s', cleanObservedAddr) // this.addressManager.addObservedAddr(observedAddr) } @@ -246,7 +249,7 @@ class IdentifyService { const signedPeerRecord = await this.peerStore.addressBook.getRawEnvelope(this.peerId) const protocols = this.peerStore.protoBook.get(this.peerId) || [] - const message = Message.encode({ + const message = Message.Identify.encode({ protocolVersion: this._host.protocolVersion, agentVersion: this._host.agentVersion, publicKey, @@ -254,7 +257,7 @@ class IdentifyService { signedPeerRecord, observedAddr: connection.remoteAddr.bytes, protocols - }) + }).finish() try { await pipe( @@ -288,7 +291,7 @@ class IdentifyService { toBuffer, collect ) - message = Message.decode(data) + message = Message.Identify.decode(data) } catch (err) { return log.error('received invalid message', err) } @@ -307,7 +310,8 @@ class IdentifyService { // LEGACY: Update peers data in PeerStore try { - this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr))) + this.peerStore.addressBook.set(id, + message.listenAddrs.map((addr) => new Multiaddr(addr))) } catch (err) { log.error('received invalid addrs', err) } @@ -320,12 +324,12 @@ class IdentifyService { * Takes the `addr` and converts it to a Multiaddr if possible * * @param {Uint8Array | string} addr - * @returns {multiaddr|null} + * @returns {Multiaddr|null} */ static getCleanMultiaddr (addr) { if (addr && addr.length > 0) { try { - return multiaddr(addr) + return new Multiaddr(addr) } catch (_) { return null } diff --git a/src/identify/message.d.ts b/src/identify/message.d.ts new file mode 100644 index 0000000000..ba49c586aa --- /dev/null +++ b/src/identify/message.d.ts @@ -0,0 +1,95 @@ +import * as $protobuf from "protobufjs"; +/** Properties of an Identify. */ +export interface IIdentify { + + /** Identify protocolVersion */ + protocolVersion?: (string|null); + + /** Identify agentVersion */ + agentVersion?: (string|null); + + /** Identify publicKey */ + publicKey?: (Uint8Array|null); + + /** Identify listenAddrs */ + listenAddrs?: (Uint8Array[]|null); + + /** Identify observedAddr */ + observedAddr?: (Uint8Array|null); + + /** Identify protocols */ + protocols?: (string[]|null); + + /** Identify signedPeerRecord */ + signedPeerRecord?: (Uint8Array|null); +} + +/** Represents an Identify. */ +export class Identify implements IIdentify { + + /** + * Constructs a new Identify. + * @param [p] Properties to set + */ + constructor(p?: IIdentify); + + /** Identify protocolVersion. */ + public protocolVersion: string; + + /** Identify agentVersion. */ + public agentVersion: string; + + /** Identify publicKey. */ + public publicKey: Uint8Array; + + /** Identify listenAddrs. */ + public listenAddrs: Uint8Array[]; + + /** Identify observedAddr. */ + public observedAddr: Uint8Array; + + /** Identify protocols. */ + public protocols: string[]; + + /** Identify signedPeerRecord. */ + public signedPeerRecord: Uint8Array; + + /** + * Encodes the specified Identify message. Does not implicitly {@link Identify.verify|verify} messages. + * @param m Identify message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IIdentify, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Identify message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Identify + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Identify; + + /** + * Creates an Identify message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Identify + */ + public static fromObject(d: { [k: string]: any }): Identify; + + /** + * Creates a plain object from an Identify message. Also converts values to other types if specified. + * @param m Identify + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Identify, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Identify to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} diff --git a/src/identify/message.js b/src/identify/message.js index 25b003f5c0..9f4d6e4ec2 100644 --- a/src/identify/message.js +++ b/src/identify/message.js @@ -1,35 +1,328 @@ -'use strict' +/*eslint-disable*/ +"use strict"; -const protons = require('protons') -const schema = ` -message Identify { - // protocolVersion determines compatibility between peers - optional string protocolVersion = 5; // e.g. ipfs/1.0.0 +var $protobuf = require("protobufjs/minimal"); - // agentVersion is like a UserAgent string in browsers, or client version in bittorrent - // includes the client name and client. - optional string agentVersion = 6; // e.g. go-ipfs/0.1.0 +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; - // publicKey is this node's public key (which also gives its node.ID) - // - may not need to be sent, as secure channel implies it has been sent. - // - then again, if we change / disable secure channel, may still want it. - optional bytes publicKey = 1; +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); - // listenAddrs are the multiaddrs the sender node listens for open connections on - repeated bytes listenAddrs = 2; +$root.Identify = (function() { - // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives - // this is useful information to convey to the other side, as it helps the remote endpoint - // determine whether its connection to the local peer goes through NAT. - optional bytes observedAddr = 4; + /** + * Properties of an Identify. + * @exports IIdentify + * @interface IIdentify + * @property {string|null} [protocolVersion] Identify protocolVersion + * @property {string|null} [agentVersion] Identify agentVersion + * @property {Uint8Array|null} [publicKey] Identify publicKey + * @property {Array.|null} [listenAddrs] Identify listenAddrs + * @property {Uint8Array|null} [observedAddr] Identify observedAddr + * @property {Array.|null} [protocols] Identify protocols + * @property {Uint8Array|null} [signedPeerRecord] Identify signedPeerRecord + */ - repeated string protocols = 3; + /** + * Constructs a new Identify. + * @exports Identify + * @classdesc Represents an Identify. + * @implements IIdentify + * @constructor + * @param {IIdentify=} [p] Properties to set + */ + function Identify(p) { + this.listenAddrs = []; + this.protocols = []; + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } - // signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord, - // signed by the sending node. It contains the same addresses as the listenAddrs field, but - // in a form that lets us share authenticated addrs with other peers. - optional bytes signedPeerRecord = 8; -} -` + /** + * Identify protocolVersion. + * @member {string} protocolVersion + * @memberof Identify + * @instance + */ + Identify.prototype.protocolVersion = ""; -module.exports = protons(schema).Identify + /** + * Identify agentVersion. + * @member {string} agentVersion + * @memberof Identify + * @instance + */ + Identify.prototype.agentVersion = ""; + + /** + * Identify publicKey. + * @member {Uint8Array} publicKey + * @memberof Identify + * @instance + */ + Identify.prototype.publicKey = $util.newBuffer([]); + + /** + * Identify listenAddrs. + * @member {Array.} listenAddrs + * @memberof Identify + * @instance + */ + Identify.prototype.listenAddrs = $util.emptyArray; + + /** + * Identify observedAddr. + * @member {Uint8Array} observedAddr + * @memberof Identify + * @instance + */ + Identify.prototype.observedAddr = $util.newBuffer([]); + + /** + * Identify protocols. + * @member {Array.} protocols + * @memberof Identify + * @instance + */ + Identify.prototype.protocols = $util.emptyArray; + + /** + * Identify signedPeerRecord. + * @member {Uint8Array} signedPeerRecord + * @memberof Identify + * @instance + */ + Identify.prototype.signedPeerRecord = $util.newBuffer([]); + + /** + * Encodes the specified Identify message. Does not implicitly {@link Identify.verify|verify} messages. + * @function encode + * @memberof Identify + * @static + * @param {IIdentify} m Identify message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Identify.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.publicKey != null && Object.hasOwnProperty.call(m, "publicKey")) + w.uint32(10).bytes(m.publicKey); + if (m.listenAddrs != null && m.listenAddrs.length) { + for (var i = 0; i < m.listenAddrs.length; ++i) + w.uint32(18).bytes(m.listenAddrs[i]); + } + if (m.protocols != null && m.protocols.length) { + for (var i = 0; i < m.protocols.length; ++i) + w.uint32(26).string(m.protocols[i]); + } + if (m.observedAddr != null && Object.hasOwnProperty.call(m, "observedAddr")) + w.uint32(34).bytes(m.observedAddr); + if (m.protocolVersion != null && Object.hasOwnProperty.call(m, "protocolVersion")) + w.uint32(42).string(m.protocolVersion); + if (m.agentVersion != null && Object.hasOwnProperty.call(m, "agentVersion")) + w.uint32(50).string(m.agentVersion); + if (m.signedPeerRecord != null && Object.hasOwnProperty.call(m, "signedPeerRecord")) + w.uint32(66).bytes(m.signedPeerRecord); + return w; + }; + + /** + * Decodes an Identify message from the specified reader or buffer. + * @function decode + * @memberof Identify + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Identify} Identify + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Identify.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Identify(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 5: + m.protocolVersion = r.string(); + break; + case 6: + m.agentVersion = r.string(); + break; + case 1: + m.publicKey = r.bytes(); + break; + case 2: + if (!(m.listenAddrs && m.listenAddrs.length)) + m.listenAddrs = []; + m.listenAddrs.push(r.bytes()); + break; + case 4: + m.observedAddr = r.bytes(); + break; + case 3: + if (!(m.protocols && m.protocols.length)) + m.protocols = []; + m.protocols.push(r.string()); + break; + case 8: + m.signedPeerRecord = r.bytes(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an Identify message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Identify + * @static + * @param {Object.} d Plain object + * @returns {Identify} Identify + */ + Identify.fromObject = function fromObject(d) { + if (d instanceof $root.Identify) + return d; + var m = new $root.Identify(); + if (d.protocolVersion != null) { + m.protocolVersion = String(d.protocolVersion); + } + if (d.agentVersion != null) { + m.agentVersion = String(d.agentVersion); + } + if (d.publicKey != null) { + if (typeof d.publicKey === "string") + $util.base64.decode(d.publicKey, m.publicKey = $util.newBuffer($util.base64.length(d.publicKey)), 0); + else if (d.publicKey.length) + m.publicKey = d.publicKey; + } + if (d.listenAddrs) { + if (!Array.isArray(d.listenAddrs)) + throw TypeError(".Identify.listenAddrs: array expected"); + m.listenAddrs = []; + for (var i = 0; i < d.listenAddrs.length; ++i) { + if (typeof d.listenAddrs[i] === "string") + $util.base64.decode(d.listenAddrs[i], m.listenAddrs[i] = $util.newBuffer($util.base64.length(d.listenAddrs[i])), 0); + else if (d.listenAddrs[i].length) + m.listenAddrs[i] = d.listenAddrs[i]; + } + } + if (d.observedAddr != null) { + if (typeof d.observedAddr === "string") + $util.base64.decode(d.observedAddr, m.observedAddr = $util.newBuffer($util.base64.length(d.observedAddr)), 0); + else if (d.observedAddr.length) + m.observedAddr = d.observedAddr; + } + if (d.protocols) { + if (!Array.isArray(d.protocols)) + throw TypeError(".Identify.protocols: array expected"); + m.protocols = []; + for (var i = 0; i < d.protocols.length; ++i) { + m.protocols[i] = String(d.protocols[i]); + } + } + if (d.signedPeerRecord != null) { + if (typeof d.signedPeerRecord === "string") + $util.base64.decode(d.signedPeerRecord, m.signedPeerRecord = $util.newBuffer($util.base64.length(d.signedPeerRecord)), 0); + else if (d.signedPeerRecord.length) + m.signedPeerRecord = d.signedPeerRecord; + } + return m; + }; + + /** + * Creates a plain object from an Identify message. Also converts values to other types if specified. + * @function toObject + * @memberof Identify + * @static + * @param {Identify} m Identify + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Identify.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.arrays || o.defaults) { + d.listenAddrs = []; + d.protocols = []; + } + if (o.defaults) { + if (o.bytes === String) + d.publicKey = ""; + else { + d.publicKey = []; + if (o.bytes !== Array) + d.publicKey = $util.newBuffer(d.publicKey); + } + if (o.bytes === String) + d.observedAddr = ""; + else { + d.observedAddr = []; + if (o.bytes !== Array) + d.observedAddr = $util.newBuffer(d.observedAddr); + } + d.protocolVersion = ""; + d.agentVersion = ""; + if (o.bytes === String) + d.signedPeerRecord = ""; + else { + d.signedPeerRecord = []; + if (o.bytes !== Array) + d.signedPeerRecord = $util.newBuffer(d.signedPeerRecord); + } + } + if (m.publicKey != null && m.hasOwnProperty("publicKey")) { + d.publicKey = o.bytes === String ? $util.base64.encode(m.publicKey, 0, m.publicKey.length) : o.bytes === Array ? Array.prototype.slice.call(m.publicKey) : m.publicKey; + } + if (m.listenAddrs && m.listenAddrs.length) { + d.listenAddrs = []; + for (var j = 0; j < m.listenAddrs.length; ++j) { + d.listenAddrs[j] = o.bytes === String ? $util.base64.encode(m.listenAddrs[j], 0, m.listenAddrs[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.listenAddrs[j]) : m.listenAddrs[j]; + } + } + if (m.protocols && m.protocols.length) { + d.protocols = []; + for (var j = 0; j < m.protocols.length; ++j) { + d.protocols[j] = m.protocols[j]; + } + } + if (m.observedAddr != null && m.hasOwnProperty("observedAddr")) { + d.observedAddr = o.bytes === String ? $util.base64.encode(m.observedAddr, 0, m.observedAddr.length) : o.bytes === Array ? Array.prototype.slice.call(m.observedAddr) : m.observedAddr; + } + if (m.protocolVersion != null && m.hasOwnProperty("protocolVersion")) { + d.protocolVersion = m.protocolVersion; + } + if (m.agentVersion != null && m.hasOwnProperty("agentVersion")) { + d.agentVersion = m.agentVersion; + } + if (m.signedPeerRecord != null && m.hasOwnProperty("signedPeerRecord")) { + d.signedPeerRecord = o.bytes === String ? $util.base64.encode(m.signedPeerRecord, 0, m.signedPeerRecord.length) : o.bytes === Array ? Array.prototype.slice.call(m.signedPeerRecord) : m.signedPeerRecord; + } + return d; + }; + + /** + * Converts this Identify to JSON. + * @function toJSON + * @memberof Identify + * @instance + * @returns {Object.} JSON object + */ + Identify.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Identify; +})(); + +module.exports = $root; diff --git a/src/identify/message.proto b/src/identify/message.proto new file mode 100644 index 0000000000..63f25561cc --- /dev/null +++ b/src/identify/message.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +message Identify { + // protocolVersion determines compatibility between peers + optional string protocolVersion = 5; // e.g. ipfs/1.0.0 + + // agentVersion is like a UserAgent string in browsers, or client version in bittorrent + // includes the client name and client. + optional string agentVersion = 6; // e.g. go-ipfs/0.1.0 + + // publicKey is this node's public key (which also gives its node.ID) + // - may not need to be sent, as secure channel implies it has been sent. + // - then again, if we change / disable secure channel, may still want it. + optional bytes publicKey = 1; + + // listenAddrs are the multiaddrs the sender node listens for open connections on + repeated bytes listenAddrs = 2; + + // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives + // this is useful information to convey to the other side, as it helps the remote endpoint + // determine whether its connection to the local peer goes through NAT. + optional bytes observedAddr = 4; + + repeated string protocols = 3; + + // signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord, + // signed by the sending node. It contains the same addresses as the listenAddrs field, but + // in a form that lets us share authenticated addrs with other peers. + optional bytes signedPeerRecord = 8; +} diff --git a/src/index.js b/src/index.js index 034aaa5006..02fa4f4ed5 100644 --- a/src/index.js +++ b/src/index.js @@ -4,13 +4,11 @@ const debug = require('debug') const log = Object.assign(debug('libp2p'), { error: debug('libp2p:err') }) -/** @typedef {import('./types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const errCode = require('err-code') const PeerId = require('peer-id') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerRouting = require('./peer-routing') const ContentRouting = require('./content-routing') @@ -38,29 +36,60 @@ const NatManager = require('./nat-manager') const { updateSelfPeerRecord } = require('./record/utils') /** - * @typedef {import('multiaddr')} Multiaddr * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream - * @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory + * @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxerFactory} MuxerFactory + * @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule + * @typedef {import('libp2p-interfaces/src/peer-discovery/types')} PeerDiscoveryModule + * @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule * @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto * @typedef {import('libp2p-interfaces/src/pubsub')} Pubsub + * @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions + * @typedef {import('interface-datastore').Datastore} Datastore + * @typedef {import('./pnet')} Protector */ /** + * @typedef {Object} HandlerProps + * @property {Connection} connection + * @property {MuxedStream} stream + * @property {string} protocol + * + * @typedef {Object} RandomWalkOptions + * @property {boolean} [enabled = false] + * @property {number} [queriesPerPeriod = 1] + * @property {number} [interval = 300e3] + * @property {number} [timeout = 10e3] + * + * @typedef {Object} DhtOptions + * @property {boolean} [enabled = false] + * @property {number} [kBucketSize = 20] + * @property {RandomWalkOptions} [randomWalk] + * + * @typedef {Object} KeychainOptions + * @property {Datastore} [datastore] + * * @typedef {Object} PeerStoreOptions * @property {boolean} persistence * - * @typedef {Object} RelayOptions + * @typedef {Object} PubsubLocalOptions + * @property {boolean} enabled + * + * @typedef {Object} MetricsOptions * @property {boolean} enabled - * @property {import('./circuit').RelayAdvertiseOptions} advertise - * @property {import('./circuit').HopOptions} hop - * @property {import('./circuit').AutoRelayOptions} autoRelay + * + * @typedef {Object} RelayOptions + * @property {boolean} [enabled = true] + * @property {import('./circuit').RelayAdvertiseOptions} [advertise] + * @property {import('./circuit').HopOptions} [hop] + * @property {import('./circuit').AutoRelayOptions} [autoRelay] * * @typedef {Object} Libp2pConfig - * @property {Object} [dht] dht module options - * @property {Object} [peerDiscovery] - * @property {Pubsub} [pubsub] pubsub module options + * @property {DhtOptions} [dht] dht module options + * @property {import('./nat-manager').NatManagerOptions} [nat] + * @property {Record} [peerDiscovery] + * @property {PubsubLocalOptions & PubsubOptions} [pubsub] pubsub module options * @property {RelayOptions} [relay] * @property {Record} [transport] transport options indexed by transport key * @@ -68,16 +97,25 @@ const { updateSelfPeerRecord } = require('./record/utils') * @property {TransportFactory[]} transport * @property {MuxerFactory[]} streamMuxer * @property {Crypto[]} connEncryption + * @property {PeerDiscoveryModule[]} [peerDiscovery] + * @property {PeerRoutingModule[]} [peerRouting] + * @property {ContentRoutingModule[]} [contentRouting] + * @property {Object} [dht] + * @property {Pubsub} [pubsub] + * @property {Protector} [connProtector] * * @typedef {Object} Libp2pOptions * @property {Libp2pModules} modules libp2p modules to use * @property {import('./address-manager').AddressManagerOptions} [addresses] * @property {import('./connection-manager').ConnectionManagerOptions} [connectionManager] + * @property {Datastore} [datastore] * @property {import('./dialer').DialerOptions} [dialer] - * @property {import('./metrics').MetricsOptions} [metrics] - * @property {Object} [keychain] - * @property {import('./transport-manager').TransportManagerOptions} [transportManager] + * @property {import('./identify/index').HostProperties} [host] libp2p host + * @property {KeychainOptions & import('./keychain/index').KeychainOptions} [keychain] + * @property {MetricsOptions & import('./metrics').MetricsOptions} [metrics] + * @property {import('./peer-routing').PeerRoutingOptions} [peerRouting] * @property {PeerStoreOptions & import('./peer-store/persistent').PersistentPeerStoreOptions} [peerStore] + * @property {import('./transport-manager').TransportManagerOptions} [transportManager] * @property {Libp2pConfig} [config] * * @typedef {Object} constructorOptions @@ -152,9 +190,6 @@ class Libp2p extends EventEmitter { this._discovery = new Map() // Discovery service instances/references // Create the Connection Manager - if (this._options.connectionManager.minPeers) { // Remove in 0.29 - this._options.connectionManager.minConnections = this._options.connectionManager.minPeers - } this.connectionManager = new ConnectionManager(this, { autoDial: this._config.peerDiscovery.autoDial, ...this._options.connectionManager @@ -175,7 +210,6 @@ class Libp2p extends EventEmitter { const keychainOpts = Keychain.generateOptions() this.keychain = new Keychain(this._options.keychain.datastore, { - passPhrase: this._options.keychain.pass, ...keychainOpts, ...this._options.keychain }) @@ -203,6 +237,7 @@ class Libp2p extends EventEmitter { peerId: this.peerId, addressManager: this.addressManager, transportManager: this.transportManager, + // @ts-ignore Nat typedef is not understood as Object ...this._options.config.nat }) @@ -227,11 +262,7 @@ class Libp2p extends EventEmitter { this.dialer = new Dialer({ transportManager: this.transportManager, peerStore: this.peerStore, - concurrency: this._options.dialer.maxParallelDials, - perPeerLimit: this._options.dialer.maxDialsPerPeer, - timeout: this._options.dialer.dialTimeout, - resolvers: this._options.dialer.resolvers, - addressSorter: this._options.dialer.addressSorter + ...this._options.dialer }) this._modules.transport.forEach((Transport) => { @@ -268,6 +299,7 @@ class Libp2p extends EventEmitter { // dht provided components (peerRouting, contentRouting, dht) if (this._modules.dht) { const DHT = this._modules.dht + // @ts-ignore Object is not constructable this._dht = new DHT({ libp2p: this, dialer: this.dialer, @@ -426,7 +458,7 @@ class Libp2p extends EventEmitter { * @returns {Promise} */ dial (peer, options) { - return this.dialProtocol(peer, [], options) + return this._dial(peer, options) } /** @@ -439,9 +471,26 @@ class Libp2p extends EventEmitter { * @param {string[]|string} protocols * @param {object} [options] * @param {AbortSignal} [options.signal] - * @returns {Promise} + * @returns {Promise} */ async dialProtocol (peer, protocols, options) { + const connection = await this._dial(peer, options) + + // If a protocol was provided, create a new stream + if (protocols && protocols.length) { + return connection.newStream(protocols) + } + + return connection + } + + /** + * @async + * @param {PeerId|Multiaddr|string} peer - The peer to dial + * @param {object} [options] + * @returns {Promise} + */ + async _dial (peer, options) { const { id, multiaddrs } = getPeer(peer) if (id.equals(this.peerId)) { @@ -456,11 +505,6 @@ class Libp2p extends EventEmitter { this.peerStore.addressBook.add(id, multiaddrs) } - // If a protocol was provided, create a new stream - if (protocols && protocols.length) { - return connection.newStream(protocols) - } - return connection } @@ -484,13 +528,13 @@ class Libp2p extends EventEmitter { addrs = addrs.concat(this.addressManager.getObservedAddrs().map(ma => ma.toString())) - const announceFilter = this._options.addresses.announceFilter || ((multiaddrs) => multiaddrs) + const announceFilter = this._options.addresses.announceFilter // dedupe multiaddrs const addrSet = new Set(addrs) // Create advertising list - return announceFilter(Array.from(addrSet).map(str => multiaddr(str))) + return announceFilter(Array.from(addrSet).map(str => new Multiaddr(str))) } /** @@ -536,7 +580,7 @@ class Libp2p extends EventEmitter { * Registers the `handler` for each protocol * * @param {string[]|string} protocols - * @param {({ connection: Connection, stream: MuxedStream, protocol: string }) => void} handler + * @param {(props: HandlerProps) => void} handler */ handle (protocols, handler) { protocols = Array.isArray(protocols) ? protocols : [protocols] @@ -669,6 +713,9 @@ class Libp2p extends EventEmitter { * @private */ async _setupPeerDiscovery () { + /** + * @param {PeerDiscoveryModule} DiscoveryService + */ const setupService = (DiscoveryService) => { let config = { enabled: true // on by default @@ -677,6 +724,7 @@ class Libp2p extends EventEmitter { if (DiscoveryService.tag && this._config.peerDiscovery && this._config.peerDiscovery[DiscoveryService.tag]) { + // @ts-ignore PeerDiscovery not understood as an Object for spread config = { ...config, ...this._config.peerDiscovery[DiscoveryService.tag] } } @@ -685,6 +733,7 @@ class Libp2p extends EventEmitter { let discoveryService if (typeof DiscoveryService === 'function') { + // @ts-ignore DiscoveryService has no constructor type inferred discoveryService = new DiscoveryService(Object.assign({}, config, { peerId: this.peerId, libp2p: this diff --git a/src/insecure/plaintext.js b/src/insecure/plaintext.js index 07efe9f758..2ea0458315 100644 --- a/src/insecure/plaintext.js +++ b/src/insecure/plaintext.js @@ -4,6 +4,7 @@ const debug = require('debug') const log = Object.assign(debug('libp2p:plaintext'), { error: debug('libp2p:plaintext:err') }) +// @ts-ignore it-handshake do not export types const handshake = require('it-handshake') const lp = require('it-length-prefixed') const PeerId = require('peer-id') @@ -16,8 +17,12 @@ const protocol = '/plaintext/2.0.0' * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection */ +/** + * @param {import('./proto').IExchange} exchange + */ function lpEncodeExchange (exchange) { - const pb = Exchange.encode(exchange) + const pb = Exchange.encode(exchange).finish() + // @ts-ignore TODO: Uint8Array not assignable to Buffer return lp.encode.single(pb) } @@ -68,12 +73,23 @@ async function encrypt (localId, conn, remoteId) { } } -module.exports = { - protocol, - secureInbound: (localId, conn, remoteId) => { - return encrypt(localId, conn, remoteId) - }, - secureOutbound: (localId, conn, remoteId) => { - return encrypt(localId, conn, remoteId) - } -} +module.exports = + { + protocol, + /** + * @param {PeerId} localId + * @param {Connection} conn + * @param {PeerId | undefined} remoteId + */ + secureInbound: (localId, conn, remoteId) => { + return encrypt(localId, conn, remoteId) + }, + /** + * @param {PeerId} localId + * @param {Connection} conn + * @param {PeerId | undefined} remoteId + */ + secureOutbound: (localId, conn, remoteId) => { + return encrypt(localId, conn, remoteId) + } + } diff --git a/src/insecure/proto.d.ts b/src/insecure/proto.d.ts new file mode 100644 index 0000000000..a4fbac0610 --- /dev/null +++ b/src/insecure/proto.d.ts @@ -0,0 +1,128 @@ +import * as $protobuf from "protobufjs"; +/** Properties of an Exchange. */ +export interface IExchange { + + /** Exchange id */ + id?: (Uint8Array|null); + + /** Exchange pubkey */ + pubkey?: (IPublicKey|null); +} + +/** Represents an Exchange. */ +export class Exchange implements IExchange { + + /** + * Constructs a new Exchange. + * @param [p] Properties to set + */ + constructor(p?: IExchange); + + /** Exchange id. */ + public id: Uint8Array; + + /** Exchange pubkey. */ + public pubkey?: (IPublicKey|null); + + /** + * Encodes the specified Exchange message. Does not implicitly {@link Exchange.verify|verify} messages. + * @param m Exchange message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IExchange, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Exchange message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Exchange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Exchange; + + /** + * Creates an Exchange message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Exchange + */ + public static fromObject(d: { [k: string]: any }): Exchange; + + /** + * Creates a plain object from an Exchange message. Also converts values to other types if specified. + * @param m Exchange + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Exchange, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Exchange to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** KeyType enum. */ +export enum KeyType { + RSA = 0, + Ed25519 = 1, + Secp256k1 = 2, + ECDSA = 3 +} + +/** Represents a PublicKey. */ +export class PublicKey implements IPublicKey { + + /** + * Constructs a new PublicKey. + * @param [p] Properties to set + */ + constructor(p?: IPublicKey); + + /** PublicKey Type. */ + public Type: KeyType; + + /** PublicKey Data. */ + public Data: Uint8Array; + + /** + * Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages. + * @param m PublicKey message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IPublicKey, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a PublicKey message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns PublicKey + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): PublicKey; + + /** + * Creates a PublicKey message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns PublicKey + */ + public static fromObject(d: { [k: string]: any }): PublicKey; + + /** + * Creates a plain object from a PublicKey message. Also converts values to other types if specified. + * @param m PublicKey + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: PublicKey, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this PublicKey to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} diff --git a/src/insecure/proto.js b/src/insecure/proto.js index 2c7d7e89a6..7c0161f60d 100644 --- a/src/insecure/proto.js +++ b/src/insecure/proto.js @@ -1,22 +1,371 @@ -'use strict' - -const protobuf = require('protons') - -module.exports = protobuf(` -message Exchange { - optional bytes id = 1; - optional PublicKey pubkey = 2; -} - -enum KeyType { - RSA = 0; - Ed25519 = 1; - Secp256k1 = 2; - ECDSA = 3; -} - -message PublicKey { - required KeyType Type = 1; - required bytes Data = 2; -} -`) +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.Exchange = (function() { + + /** + * Properties of an Exchange. + * @exports IExchange + * @interface IExchange + * @property {Uint8Array|null} [id] Exchange id + * @property {IPublicKey|null} [pubkey] Exchange pubkey + */ + + /** + * Constructs a new Exchange. + * @exports Exchange + * @classdesc Represents an Exchange. + * @implements IExchange + * @constructor + * @param {IExchange=} [p] Properties to set + */ + function Exchange(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Exchange id. + * @member {Uint8Array} id + * @memberof Exchange + * @instance + */ + Exchange.prototype.id = $util.newBuffer([]); + + /** + * Exchange pubkey. + * @member {IPublicKey|null|undefined} pubkey + * @memberof Exchange + * @instance + */ + Exchange.prototype.pubkey = null; + + /** + * Encodes the specified Exchange message. Does not implicitly {@link Exchange.verify|verify} messages. + * @function encode + * @memberof Exchange + * @static + * @param {IExchange} m Exchange message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Exchange.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.id != null && Object.hasOwnProperty.call(m, "id")) + w.uint32(10).bytes(m.id); + if (m.pubkey != null && Object.hasOwnProperty.call(m, "pubkey")) + $root.PublicKey.encode(m.pubkey, w.uint32(18).fork()).ldelim(); + return w; + }; + + /** + * Decodes an Exchange message from the specified reader or buffer. + * @function decode + * @memberof Exchange + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Exchange} Exchange + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Exchange.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Exchange(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.id = r.bytes(); + break; + case 2: + m.pubkey = $root.PublicKey.decode(r, r.uint32()); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an Exchange message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Exchange + * @static + * @param {Object.} d Plain object + * @returns {Exchange} Exchange + */ + Exchange.fromObject = function fromObject(d) { + if (d instanceof $root.Exchange) + return d; + var m = new $root.Exchange(); + if (d.id != null) { + if (typeof d.id === "string") + $util.base64.decode(d.id, m.id = $util.newBuffer($util.base64.length(d.id)), 0); + else if (d.id.length) + m.id = d.id; + } + if (d.pubkey != null) { + if (typeof d.pubkey !== "object") + throw TypeError(".Exchange.pubkey: object expected"); + m.pubkey = $root.PublicKey.fromObject(d.pubkey); + } + return m; + }; + + /** + * Creates a plain object from an Exchange message. Also converts values to other types if specified. + * @function toObject + * @memberof Exchange + * @static + * @param {Exchange} m Exchange + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Exchange.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + if (o.bytes === String) + d.id = ""; + else { + d.id = []; + if (o.bytes !== Array) + d.id = $util.newBuffer(d.id); + } + d.pubkey = null; + } + if (m.id != null && m.hasOwnProperty("id")) { + d.id = o.bytes === String ? $util.base64.encode(m.id, 0, m.id.length) : o.bytes === Array ? Array.prototype.slice.call(m.id) : m.id; + } + if (m.pubkey != null && m.hasOwnProperty("pubkey")) { + d.pubkey = $root.PublicKey.toObject(m.pubkey, o); + } + return d; + }; + + /** + * Converts this Exchange to JSON. + * @function toJSON + * @memberof Exchange + * @instance + * @returns {Object.} JSON object + */ + Exchange.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Exchange; +})(); + +/** + * KeyType enum. + * @exports KeyType + * @enum {number} + * @property {number} RSA=0 RSA value + * @property {number} Ed25519=1 Ed25519 value + * @property {number} Secp256k1=2 Secp256k1 value + * @property {number} ECDSA=3 ECDSA value + */ +$root.KeyType = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "RSA"] = 0; + values[valuesById[1] = "Ed25519"] = 1; + values[valuesById[2] = "Secp256k1"] = 2; + values[valuesById[3] = "ECDSA"] = 3; + return values; +})(); + +$root.PublicKey = (function() { + + /** + * Properties of a PublicKey. + * @exports IPublicKey + * @interface IPublicKey + * @property {KeyType|null} [Type] PublicKey Type + * @property {Uint8Array|null} [Data] PublicKey Data + */ + + /** + * Constructs a new PublicKey. + * @exports PublicKey + * @classdesc Represents a PublicKey. + * @implements IPublicKey + * @constructor + * @param {IPublicKey=} [p] Properties to set + */ + function PublicKey(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * PublicKey Type. + * @member {KeyType} Type + * @memberof PublicKey + * @instance + */ + PublicKey.prototype.Type = 0; + + /** + * PublicKey Data. + * @member {Uint8Array} Data + * @memberof PublicKey + * @instance + */ + PublicKey.prototype.Data = $util.newBuffer([]); + + /** + * Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages. + * @function encode + * @memberof PublicKey + * @static + * @param {IPublicKey} m PublicKey message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + PublicKey.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.Type != null && Object.hasOwnProperty.call(m, "Type")) + w.uint32(8).int32(m.Type); + if (m.Data != null && Object.hasOwnProperty.call(m, "Data")) + w.uint32(18).bytes(m.Data); + return w; + }; + + /** + * Decodes a PublicKey message from the specified reader or buffer. + * @function decode + * @memberof PublicKey + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {PublicKey} PublicKey + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + PublicKey.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.PublicKey(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.Type = r.int32(); + break; + case 2: + m.Data = r.bytes(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates a PublicKey message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof PublicKey + * @static + * @param {Object.} d Plain object + * @returns {PublicKey} PublicKey + */ + PublicKey.fromObject = function fromObject(d) { + if (d instanceof $root.PublicKey) + return d; + var m = new $root.PublicKey(); + switch (d.Type) { + case "RSA": + case 0: + m.Type = 0; + break; + case "Ed25519": + case 1: + m.Type = 1; + break; + case "Secp256k1": + case 2: + m.Type = 2; + break; + case "ECDSA": + case 3: + m.Type = 3; + break; + } + if (d.Data != null) { + if (typeof d.Data === "string") + $util.base64.decode(d.Data, m.Data = $util.newBuffer($util.base64.length(d.Data)), 0); + else if (d.Data.length) + m.Data = d.Data; + } + return m; + }; + + /** + * Creates a plain object from a PublicKey message. Also converts values to other types if specified. + * @function toObject + * @memberof PublicKey + * @static + * @param {PublicKey} m PublicKey + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + PublicKey.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + d.Type = o.enums === String ? "RSA" : 0; + if (o.bytes === String) + d.Data = ""; + else { + d.Data = []; + if (o.bytes !== Array) + d.Data = $util.newBuffer(d.Data); + } + } + if (m.Type != null && m.hasOwnProperty("Type")) { + d.Type = o.enums === String ? $root.KeyType[m.Type] : m.Type; + } + if (m.Data != null && m.hasOwnProperty("Data")) { + d.Data = o.bytes === String ? $util.base64.encode(m.Data, 0, m.Data.length) : o.bytes === Array ? Array.prototype.slice.call(m.Data) : m.Data; + } + return d; + }; + + /** + * Converts this PublicKey to JSON. + * @function toJSON + * @memberof PublicKey + * @instance + * @returns {Object.} JSON object + */ + PublicKey.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return PublicKey; +})(); + +module.exports = $root; diff --git a/src/insecure/proto.proto b/src/insecure/proto.proto new file mode 100644 index 0000000000..9d174a898c --- /dev/null +++ b/src/insecure/proto.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +message Exchange { + optional bytes id = 1; + optional PublicKey pubkey = 2; +} + +enum KeyType { + RSA = 0; + Ed25519 = 1; + Secp256k1 = 2; + ECDSA = 3; +} + +message PublicKey { + KeyType Type = 1; + bytes Data = 2; +} \ No newline at end of file diff --git a/src/keychain/cms.js b/src/keychain/cms.js index bcd5c36506..92a1932a09 100644 --- a/src/keychain/cms.js +++ b/src/keychain/cms.js @@ -1,7 +1,10 @@ 'use strict' +// @ts-ignore node-forge types not exported require('node-forge/lib/pkcs7') +// @ts-ignore node-forge types not exported require('node-forge/lib/pbe') +// @ts-ignore node-forge types not exported const forge = require('node-forge/lib/forge') const { certificateForKey, findAsync } = require('./util') const errcode = require('err-code') @@ -85,6 +88,7 @@ class CMS { try { const buf = forge.util.createBuffer(uint8ArrayToString(cmsData, 'ascii')) const obj = forge.asn1.fromDer(buf) + // @ts-ignore not defined cms = forge.pkcs7.messageFromAsn1(obj) } catch (err) { throw errcode(new Error('Invalid CMS: ' + err.message), 'ERR_INVALID_CMS') @@ -93,11 +97,15 @@ class CMS { // Find a recipient whose key we hold. We only deal with recipient certs // issued by ipfs (O=ipfs). const recipients = cms.recipients + // @ts-ignore cms types not defined .filter(r => r.issuer.find(a => a.shortName === 'O' && a.value === 'ipfs')) + // @ts-ignore cms types not defined .filter(r => r.issuer.find(a => a.shortName === 'CN')) + // @ts-ignore cms types not defined .map(r => { return { recipient: r, + // @ts-ignore cms types not defined keyId: r.issuer.find(a => a.shortName === 'CN').value } }) @@ -113,6 +121,7 @@ class CMS { }) if (!r) { + // @ts-ignore cms types not defined const missingKeys = recipients.map(r => r.keyId) throw errcode(new Error('Decryption needs one of the key(s): ' + missingKeys.join(', ')), 'ERR_MISSING_KEYS', { missingKeys diff --git a/src/keychain/index.js b/src/keychain/index.js index eaff31b5c3..0cf13d0515 100644 --- a/src/keychain/index.js +++ b/src/keychain/index.js @@ -10,6 +10,7 @@ const errcode = require('err-code') const uint8ArrayToString = require('uint8arrays/to-string') const uint8ArrayFromString = require('uint8arrays/from-string') +// @ts-ignore node-forge sha512 types not exported require('node-forge/lib/sha512') /** @@ -17,6 +18,26 @@ require('node-forge/lib/sha512') * @typedef {import('interface-datastore').Datastore} Datastore */ +/** + * @typedef {Object} DekOptions + * @property {string} hash + * @property {string} salt + * @property {number} iterationCount + * @property {number} keyLength + * + * @typedef {Object} KeychainOptions + * @property {string} pass + * @property {DekOptions} [dek] + */ + +/** + * Information about a key. + * + * @typedef {Object} KeyInfo + * @property {string} id - The universally unique key id. + * @property {string} name - The local key name. + */ + const keyPrefix = '/pkcs8/' const infoPrefix = '/info/' const privates = new WeakMap() @@ -38,6 +59,9 @@ const defaultOptions = { } } +/** + * @param {string} name + */ function validateKeyName (name) { if (!name) return false if (typeof name !== 'string') return false @@ -85,14 +109,6 @@ function DsInfoName (name) { return new Key(infoPrefix + name) } -/** - * Information about a key. - * - * @typedef {Object} KeyInfo - * @property {string} id - The universally unique key id. - * @property {string} name - The local key name. - */ - /** * Manages the lifecycle of a key. Keys are encrypted at rest using PKCS #8. * @@ -106,7 +122,7 @@ class Keychain { * Creates a new instance of a key chain. * * @param {Datastore} store - where the key are. - * @param {object} options + * @param {KeychainOptions} options * @class */ constructor (store, options) { @@ -118,8 +134,8 @@ class Keychain { this.opts = mergeOptions(defaultOptions, options) // Enforce NIST SP 800-132 - if (this.opts.passPhrase && this.opts.passPhrase.length < 20) { - throw new Error('passPhrase must be least 20 characters') + if (this.opts.pass && this.opts.pass.length < 20) { + throw new Error('pass must be least 20 characters') } if (this.opts.dek.keyLength < NIST.minKeyLength) { throw new Error(`dek.keyLength must be least ${NIST.minKeyLength} bytes`) @@ -131,12 +147,14 @@ class Keychain { throw new Error(`dek.iterationCount must be least ${NIST.minIterationCount}`) } - const dek = this.opts.passPhrase ? crypto.pbkdf2( - this.opts.passPhrase, - this.opts.dek.salt, - this.opts.dek.iterationCount, - this.opts.dek.keyLength, - this.opts.dek.hash) : '' + const dek = this.opts.pass + ? crypto.pbkdf2( + this.opts.pass, + this.opts.dek.salt, + this.opts.dek.iterationCount, + this.opts.dek.keyLength, + this.opts.dek.hash) + : '' privates.set(this, { dek }) } diff --git a/src/keychain/util.js b/src/keychain/util.js index 6a332c9ceb..a84c3f1081 100644 --- a/src/keychain/util.js +++ b/src/keychain/util.js @@ -4,7 +4,6 @@ require('node-forge/lib/x509') const forge = require('node-forge/lib/forge') const pki = forge.pki -exports = module.exports /** * Gets a self-signed X.509 certificate for the key. @@ -17,7 +16,7 @@ exports = module.exports * @param {RsaPrivateKey} privateKey - The naked key * @returns {Uint8Array} */ -exports.certificateForKey = (key, privateKey) => { +const certificateForKey = (key, privateKey) => { const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e) const cert = pki.createCertificate() cert.publicKey = publicKey @@ -87,4 +86,7 @@ async function findAsync (array, asyncCompare) { return array[index] } -module.exports.findAsync = findAsync +module.exports = { + certificateForKey, + findAsync +} diff --git a/src/metrics/stats.js b/src/metrics/stats.js index a445a705f2..0153624154 100644 --- a/src/metrics/stats.js +++ b/src/metrics/stats.js @@ -1,8 +1,6 @@ // @ts-nocheck 'use strict' -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const Big = require('bignumber.js') const MovingAverage = require('moving-average') @@ -32,13 +30,13 @@ class Stats extends EventEmitter { const intervals = this._options.movingAverageIntervals - for (var i = 0; i < initialCounters.length; i++) { - var key = initialCounters[i] + for (let i = 0; i < initialCounters.length; i++) { + const key = initialCounters[i] this._stats[key] = Big(0) this._movingAverages[key] = {} - for (var k = 0; k < intervals.length; k++) { - var interval = intervals[k] - var ma = this._movingAverages[key][interval] = MovingAverage(interval) + for (let k = 0; k < intervals.length; k++) { + const interval = intervals[k] + const ma = this._movingAverages[key][interval] = MovingAverage(interval) ma.push(this._frequencyLastTime, 0) } } @@ -72,8 +70,6 @@ class Stats extends EventEmitter { /** * Returns a clone of the current stats. - * - * @returns {Object} */ get snapshot () { return Object.assign({}, this._stats) @@ -81,8 +77,6 @@ class Stats extends EventEmitter { /** * Returns a clone of the internal movingAverages - * - * @returns {Object} */ get movingAverages () { return Object.assign({}, this._movingAverages) @@ -219,9 +213,9 @@ class Stats extends EventEmitter { const intervals = this._options.movingAverageIntervals - for (var i = 0; i < intervals.length; i++) { - var movingAverageInterval = intervals[i] - var movingAverage = movingAverages[movingAverageInterval] + for (let i = 0; i < intervals.length; i++) { + const movingAverageInterval = intervals[i] + let movingAverage = movingAverages[movingAverageInterval] if (!movingAverage) { movingAverage = movingAverages[movingAverageInterval] = MovingAverage(movingAverageInterval) } diff --git a/src/nat-manager.js b/src/nat-manager.js index 887f3d81fb..478db81104 100644 --- a/src/nat-manager.js +++ b/src/nat-manager.js @@ -1,14 +1,16 @@ 'use strict' +// @ts-ignore nat-api does not export types const NatAPI = require('@motrix/nat-api') const debug = require('debug') const { promisify } = require('es6-promisify') -const Multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const log = Object.assign(debug('libp2p:nat'), { error: debug('libp2p:nat:err') }) const { isBrowser } = require('ipfs-utils/src/env') const retry = require('p-retry') +// @ts-ignore private-api does not export types const isPrivateIp = require('private-ip') const pkg = require('../package.json') const errcode = require('err-code') @@ -17,33 +19,39 @@ const { } = require('./errors') const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback') +const DEFAULT_TTL = 7200 + /** * @typedef {import('peer-id')} PeerId * @typedef {import('./transport-manager')} TransportManager * @typedef {import('./address-manager')} AddressManager */ +/** + * @typedef {Object} NatManagerProperties + * @property {PeerId} peerId - The peer ID of the current node + * @property {TransportManager} transportManager - A transport manager + * @property {AddressManager} addressManager - An address manager + * + * @typedef {Object} NatManagerOptions + * @property {boolean} enabled - Whether to enable the NAT manager + * @property {string} [externalIp] - Pass a value to use instead of auto-detection + * @property {string} [description] - A string value to use for the port mapping description on the gateway + * @property {number} [ttl = DEFAULT_TTL] - How long UPnP port mappings should last for in seconds (minimum 1200) + * @property {boolean} [keepAlive] - Whether to automatically refresh UPnP port mappings when their TTL is reached + * @property {string} [gateway] - Pass a value to use instead of auto-detection + * @property {object} [pmp] - PMP options + * @property {boolean} [pmp.enabled] - Whether to enable PMP as well as UPnP + */ + function highPort (min = 1024, max = 65535) { return Math.floor(Math.random() * (max - min + 1) + min) } -const DEFAULT_TTL = 7200 - class NatManager { /** * @class - * @param {object} options - * @param {PeerId} options.peerId - The peer ID of the current node - * @param {TransportManager} options.transportManager - A transport manager - * @param {AddressManager} options.addressManager - An address manager - * @param {boolean} options.enabled - Whether to enable the NAT manager - * @param {string} [options.externalIp] - Pass a value to use instead of auto-detection - * @param {string} [options.description] - A string value to use for the port mapping description on the gateway - * @param {number} [options.ttl] - How long UPnP port mappings should last for in seconds (minimum 1200) - * @param {boolean} [options.keepAlive] - Whether to automatically refresh UPnP port mappings when their TTL is reached - * @param {string} [options.gateway] - Pass a value to use instead of auto-detection - * @param {object} [options.pmp] - PMP options - * @param {boolean} [options.pmp.enabled] - Whether to enable PMP as well as UPnP + * @param {NatManagerProperties & NatManagerOptions} options */ constructor ({ peerId, addressManager, transportManager, ...options }) { this._peerId = peerId @@ -89,15 +97,18 @@ class NatManager { if (!addr.isThinWaistAddress() || transport !== 'tcp') { // only bare tcp addresses + // eslint-disable-next-line no-continue continue } if (isLoopback(addr)) { + // eslint-disable-next-line no-continue continue } - if (family !== 'ipv4') { + if (family !== 4) { // ignore ipv6 + // eslint-disable-next-line no-continue continue } @@ -119,9 +130,9 @@ class NatManager { }) this._addressManager.addObservedAddr(Multiaddr.fromNodeAddress({ - family: 'IPv4', + family: 4, address: publicIp, - port: `${publicPort}` + port: publicPort }, transport)) } } @@ -133,11 +144,11 @@ class NatManager { const client = new NatAPI(this._options) - /** @type {(...any) => any} */ + /** @type {(...any: any) => any} */ const map = promisify(client.map.bind(client)) - /** @type {(...any) => any} */ + /** @type {(...any: any) => any} */ const destroy = promisify(client.destroy.bind(client)) - /** @type {(...any) => any} */ + /** @type {(...any: any) => any} */ const externalIp = promisify(client.externalIp.bind(client)) // these are all network operations so add a retry diff --git a/src/peer-routing.js b/src/peer-routing.js index 32c9cc20e8..e280936182 100644 --- a/src/peer-routing.js +++ b/src/peer-routing.js @@ -19,12 +19,25 @@ const filter = require('it-filter') const { setDelayedInterval, clearDelayedInterval +// @ts-ignore module with no types } = require('set-delayed-interval') -const PeerId = require('peer-id') /** - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('peer-id')} PeerId + * @typedef {import('multiaddr').Multiaddr} Multiaddr + * @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule */ + +/** + * @typedef {Object} RefreshManagerOptions + * @property {boolean} [enabled = true] - Whether to enable the Refresh manager + * @property {number} [bootDelay = 6e5] - Boot delay to start the Refresh Manager (in ms) + * @property {number} [interval = 10e3] - Interval between each Refresh Manager run (in ms) + * + * @typedef {Object} PeerRoutingOptions + * @property {RefreshManagerOptions} [refreshManager] + */ + class PeerRouting { /** * @class @@ -33,6 +46,7 @@ class PeerRouting { constructor (libp2p) { this._peerId = libp2p.peerId this._peerStore = libp2p.peerStore + /** @type {PeerRoutingModule[]} */ this._routers = libp2p._modules.peerRouting || [] // If we have the dht, add it to the available peer routers @@ -95,6 +109,7 @@ class PeerRouting { ...this._routers.map(router => [router.findPeer(id, options)]) ), (source) => filter(source, Boolean), + // @ts-ignore findPeer resolves a Promise (source) => storeAddresses(source, this._peerStore), (source) => first(source) ) diff --git a/src/peer-store/address-book.js b/src/peer-store/address-book.js index 74b6049a5c..595781c068 100644 --- a/src/peer-store/address-book.js +++ b/src/peer-store/address-book.js @@ -6,7 +6,7 @@ const log = Object.assign(debug('libp2p:peer-store:address-book'), { }) const errcode = require('err-code') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const Book = require('./book') @@ -18,7 +18,6 @@ const { const Envelope = require('../record/envelope') /** - * @typedef {import('multiaddr')} Multiaddr * @typedef {import('./')} PeerStore */ @@ -60,7 +59,7 @@ class AddressBook extends Book { if (!data.addresses) { return [] } - return data.addresses.map((address) => address.multiaddr) + return data.addresses.map((/** @type {Address} */ address) => address.multiaddr) } }) @@ -295,9 +294,10 @@ class AddressBook extends Book { } // create Address for each address + /** @type {Address[]} */ const addresses = [] multiaddrs.forEach((addr) => { - if (!multiaddr.isMultiaddr(addr)) { + if (!Multiaddr.isMultiaddr(addr)) { log.error(`multiaddr ${addr} must be an instance of multiaddr`) throw errcode(new Error(`multiaddr ${addr} must be an instance of multiaddr`), ERR_INVALID_PARAMETERS) } diff --git a/src/peer-store/book.js b/src/peer-store/book.js index 48855c157b..9b6d561b1e 100644 --- a/src/peer-store/book.js +++ b/src/peer-store/book.js @@ -7,6 +7,9 @@ const { codes: { ERR_INVALID_PARAMETERS } } = require('../errors') +/** + * @param {any} data + */ const passthrough = data => data /** diff --git a/src/peer-store/index.js b/src/peer-store/index.js index 0741229057..0f2f989f79 100644 --- a/src/peer-store/index.js +++ b/src/peer-store/index.js @@ -2,8 +2,6 @@ const errcode = require('err-code') -/** @typedef {import('../types').EventEmitterFactory} Events */ -/** @type Events */ const EventEmitter = require('events') const PeerId = require('peer-id') diff --git a/src/peer-store/metadata-book.js b/src/peer-store/metadata-book.js index d497bb2f04..50b227da91 100644 --- a/src/peer-store/metadata-book.js +++ b/src/peer-store/metadata-book.js @@ -81,6 +81,9 @@ class MetadataBook extends Book { * Set data into the datastructure * * @override + * @param {PeerId} peerId + * @param {string} key + * @param {Uint8Array} value */ _setValue (peerId, key, value, { emit = true } = {}) { const id = peerId.toB58String() diff --git a/src/peer-store/persistent/index.js b/src/peer-store/persistent/index.js index bbab49657e..8d7d50ea9a 100644 --- a/src/peer-store/persistent/index.js +++ b/src/peer-store/persistent/index.js @@ -5,7 +5,7 @@ const log = Object.assign(debug('libp2p:persistent-peer-store'), { error: debug('libp2p:persistent-peer-store:err') }) const { Key } = require('interface-datastore') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const PeerStore = require('..') @@ -18,13 +18,18 @@ const { NAMESPACE_PROTOCOL } = require('./consts') -const Addresses = require('./pb/address-book.proto') -const Protocols = require('./pb/proto-book.proto') +const { Addresses } = require('./pb/address-book') +const { Protocols } = require('./pb/proto-book') + +/** + * @typedef {import('interface-datastore').Batch} Batch + * @typedef {import('../address-book.js').Address} Address + */ /** * @typedef {Object} PersistentPeerStoreProperties * @property {PeerId} peerId - * @property {any} datastore + * @property {import('interface-datastore').Datastore} datastore * * @typedef {Object} PersistentPeerStoreOptions * @property {number} [threshold = 5] - Number of dirty peers allowed before commit data. @@ -214,7 +219,7 @@ class PersistentPeerStore extends PeerStore { * * @private * @param {PeerId} peerId - * @param {Object} batch + * @param {Batch} batch */ _batchAddressBook (peerId, batch) { const b32key = peerId.toString() @@ -234,11 +239,13 @@ class PersistentPeerStore extends PeerStore { multiaddr: address.multiaddr.bytes, isCertified: address.isCertified })), - certified_record: entry.record ? { - seq: entry.record.seqNumber, - raw: entry.record.raw - } : undefined - }) + certifiedRecord: entry.record + ? { + seq: entry.record.seqNumber, + raw: entry.record.raw + } + : undefined + }).finish() batch.put(key, encodedData) } catch (err) { @@ -251,7 +258,7 @@ class PersistentPeerStore extends PeerStore { * * @private * @param {PeerId} peerId - * @param {Object} batch + * @param {Batch} batch */ _batchKeyBook (peerId, batch) { const b32key = peerId.toString() @@ -277,14 +284,14 @@ class PersistentPeerStore extends PeerStore { * * @private * @param {PeerId} peerId - * @param {Object} batch + * @param {Batch} batch */ _batchMetadataBook (peerId, batch) { const b32key = peerId.toString() const dirtyMetada = this._dirtyMetadata.get(peerId.toB58String()) || [] try { - dirtyMetada.forEach((dirtyKey) => { + dirtyMetada.forEach((/** @type {string} */ dirtyKey) => { const key = new Key(`${NAMESPACE_METADATA}${b32key}/${dirtyKey}`) const dirtyValue = this.metadataBook.getValue(peerId, dirtyKey) @@ -304,7 +311,7 @@ class PersistentPeerStore extends PeerStore { * * @private * @param {PeerId} peerId - * @param {Object} batch + * @param {Batch} batch */ _batchProtoBook (peerId, batch) { const b32key = peerId.toString() @@ -319,7 +326,7 @@ class PersistentPeerStore extends PeerStore { return } - const encodedData = Protocols.encode({ protocols }) + const encodedData = Protocols.encode({ protocols }).finish() batch.put(key, encodedData) } catch (err) { @@ -351,13 +358,15 @@ class PersistentPeerStore extends PeerStore { peerId, { addresses: decoded.addrs.map((address) => ({ - multiaddr: multiaddr(address.multiaddr), + multiaddr: new Multiaddr(address.multiaddr), isCertified: Boolean(address.isCertified) })), - record: decoded.certified_record ? { - raw: decoded.certified_record.raw, - seqNumber: decoded.certified_record.seq - } : undefined + record: decoded.certifiedRecord + ? { + raw: decoded.certifiedRecord.raw, + seqNumber: decoded.certifiedRecord.seq + } + : undefined }, { emit: false }) break diff --git a/src/peer-store/persistent/pb/address-book.d.ts b/src/peer-store/persistent/pb/address-book.d.ts new file mode 100644 index 0000000000..0080a6390c --- /dev/null +++ b/src/peer-store/persistent/pb/address-book.d.ts @@ -0,0 +1,198 @@ +import * as $protobuf from "protobufjs"; +/** Properties of an Addresses. */ +export interface IAddresses { + + /** Addresses addrs */ + addrs?: (Addresses.IAddress[]|null); + + /** Addresses certifiedRecord */ + certifiedRecord?: (Addresses.ICertifiedRecord|null); +} + +/** Represents an Addresses. */ +export class Addresses implements IAddresses { + + /** + * Constructs a new Addresses. + * @param [p] Properties to set + */ + constructor(p?: IAddresses); + + /** Addresses addrs. */ + public addrs: Addresses.IAddress[]; + + /** Addresses certifiedRecord. */ + public certifiedRecord?: (Addresses.ICertifiedRecord|null); + + /** + * Encodes the specified Addresses message. Does not implicitly {@link Addresses.verify|verify} messages. + * @param m Addresses message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IAddresses, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Addresses message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Addresses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses; + + /** + * Creates an Addresses message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Addresses + */ + public static fromObject(d: { [k: string]: any }): Addresses; + + /** + * Creates a plain object from an Addresses message. Also converts values to other types if specified. + * @param m Addresses + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Addresses, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Addresses to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +export namespace Addresses { + + /** Properties of an Address. */ + interface IAddress { + + /** Address multiaddr */ + multiaddr?: (Uint8Array|null); + + /** Address isCertified */ + isCertified?: (boolean|null); + } + + /** Represents an Address. */ + class Address implements IAddress { + + /** + * Constructs a new Address. + * @param [p] Properties to set + */ + constructor(p?: Addresses.IAddress); + + /** Address multiaddr. */ + public multiaddr: Uint8Array; + + /** Address isCertified. */ + public isCertified: boolean; + + /** + * Encodes the specified Address message. Does not implicitly {@link Addresses.Address.verify|verify} messages. + * @param m Address message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: Addresses.IAddress, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Address message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Address + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses.Address; + + /** + * Creates an Address message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Address + */ + public static fromObject(d: { [k: string]: any }): Addresses.Address; + + /** + * Creates a plain object from an Address message. Also converts values to other types if specified. + * @param m Address + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Addresses.Address, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Address to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + + /** Properties of a CertifiedRecord. */ + interface ICertifiedRecord { + + /** CertifiedRecord seq */ + seq?: (number|null); + + /** CertifiedRecord raw */ + raw?: (Uint8Array|null); + } + + /** Represents a CertifiedRecord. */ + class CertifiedRecord implements ICertifiedRecord { + + /** + * Constructs a new CertifiedRecord. + * @param [p] Properties to set + */ + constructor(p?: Addresses.ICertifiedRecord); + + /** CertifiedRecord seq. */ + public seq: number; + + /** CertifiedRecord raw. */ + public raw: Uint8Array; + + /** + * Encodes the specified CertifiedRecord message. Does not implicitly {@link Addresses.CertifiedRecord.verify|verify} messages. + * @param m CertifiedRecord message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: Addresses.ICertifiedRecord, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a CertifiedRecord message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns CertifiedRecord + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses.CertifiedRecord; + + /** + * Creates a CertifiedRecord message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns CertifiedRecord + */ + public static fromObject(d: { [k: string]: any }): Addresses.CertifiedRecord; + + /** + * Creates a plain object from a CertifiedRecord message. Also converts values to other types if specified. + * @param m CertifiedRecord + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Addresses.CertifiedRecord, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this CertifiedRecord to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } +} diff --git a/src/peer-store/persistent/pb/address-book.js b/src/peer-store/persistent/pb/address-book.js new file mode 100644 index 0000000000..489a36ca4d --- /dev/null +++ b/src/peer-store/persistent/pb/address-book.js @@ -0,0 +1,522 @@ +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.Addresses = (function() { + + /** + * Properties of an Addresses. + * @exports IAddresses + * @interface IAddresses + * @property {Array.|null} [addrs] Addresses addrs + * @property {Addresses.ICertifiedRecord|null} [certifiedRecord] Addresses certifiedRecord + */ + + /** + * Constructs a new Addresses. + * @exports Addresses + * @classdesc Represents an Addresses. + * @implements IAddresses + * @constructor + * @param {IAddresses=} [p] Properties to set + */ + function Addresses(p) { + this.addrs = []; + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Addresses addrs. + * @member {Array.} addrs + * @memberof Addresses + * @instance + */ + Addresses.prototype.addrs = $util.emptyArray; + + /** + * Addresses certifiedRecord. + * @member {Addresses.ICertifiedRecord|null|undefined} certifiedRecord + * @memberof Addresses + * @instance + */ + Addresses.prototype.certifiedRecord = null; + + /** + * Encodes the specified Addresses message. Does not implicitly {@link Addresses.verify|verify} messages. + * @function encode + * @memberof Addresses + * @static + * @param {IAddresses} m Addresses message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Addresses.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.addrs != null && m.addrs.length) { + for (var i = 0; i < m.addrs.length; ++i) + $root.Addresses.Address.encode(m.addrs[i], w.uint32(10).fork()).ldelim(); + } + if (m.certifiedRecord != null && Object.hasOwnProperty.call(m, "certifiedRecord")) + $root.Addresses.CertifiedRecord.encode(m.certifiedRecord, w.uint32(18).fork()).ldelim(); + return w; + }; + + /** + * Decodes an Addresses message from the specified reader or buffer. + * @function decode + * @memberof Addresses + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Addresses} Addresses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Addresses.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + if (!(m.addrs && m.addrs.length)) + m.addrs = []; + m.addrs.push($root.Addresses.Address.decode(r, r.uint32())); + break; + case 2: + m.certifiedRecord = $root.Addresses.CertifiedRecord.decode(r, r.uint32()); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an Addresses message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Addresses + * @static + * @param {Object.} d Plain object + * @returns {Addresses} Addresses + */ + Addresses.fromObject = function fromObject(d) { + if (d instanceof $root.Addresses) + return d; + var m = new $root.Addresses(); + if (d.addrs) { + if (!Array.isArray(d.addrs)) + throw TypeError(".Addresses.addrs: array expected"); + m.addrs = []; + for (var i = 0; i < d.addrs.length; ++i) { + if (typeof d.addrs[i] !== "object") + throw TypeError(".Addresses.addrs: object expected"); + m.addrs[i] = $root.Addresses.Address.fromObject(d.addrs[i]); + } + } + if (d.certifiedRecord != null) { + if (typeof d.certifiedRecord !== "object") + throw TypeError(".Addresses.certifiedRecord: object expected"); + m.certifiedRecord = $root.Addresses.CertifiedRecord.fromObject(d.certifiedRecord); + } + return m; + }; + + /** + * Creates a plain object from an Addresses message. Also converts values to other types if specified. + * @function toObject + * @memberof Addresses + * @static + * @param {Addresses} m Addresses + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Addresses.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.arrays || o.defaults) { + d.addrs = []; + } + if (o.defaults) { + d.certifiedRecord = null; + } + if (m.addrs && m.addrs.length) { + d.addrs = []; + for (var j = 0; j < m.addrs.length; ++j) { + d.addrs[j] = $root.Addresses.Address.toObject(m.addrs[j], o); + } + } + if (m.certifiedRecord != null && m.hasOwnProperty("certifiedRecord")) { + d.certifiedRecord = $root.Addresses.CertifiedRecord.toObject(m.certifiedRecord, o); + } + return d; + }; + + /** + * Converts this Addresses to JSON. + * @function toJSON + * @memberof Addresses + * @instance + * @returns {Object.} JSON object + */ + Addresses.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + Addresses.Address = (function() { + + /** + * Properties of an Address. + * @memberof Addresses + * @interface IAddress + * @property {Uint8Array|null} [multiaddr] Address multiaddr + * @property {boolean|null} [isCertified] Address isCertified + */ + + /** + * Constructs a new Address. + * @memberof Addresses + * @classdesc Represents an Address. + * @implements IAddress + * @constructor + * @param {Addresses.IAddress=} [p] Properties to set + */ + function Address(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Address multiaddr. + * @member {Uint8Array} multiaddr + * @memberof Addresses.Address + * @instance + */ + Address.prototype.multiaddr = $util.newBuffer([]); + + /** + * Address isCertified. + * @member {boolean} isCertified + * @memberof Addresses.Address + * @instance + */ + Address.prototype.isCertified = false; + + /** + * Encodes the specified Address message. Does not implicitly {@link Addresses.Address.verify|verify} messages. + * @function encode + * @memberof Addresses.Address + * @static + * @param {Addresses.IAddress} m Address message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Address.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.multiaddr != null && Object.hasOwnProperty.call(m, "multiaddr")) + w.uint32(10).bytes(m.multiaddr); + if (m.isCertified != null && Object.hasOwnProperty.call(m, "isCertified")) + w.uint32(16).bool(m.isCertified); + return w; + }; + + /** + * Decodes an Address message from the specified reader or buffer. + * @function decode + * @memberof Addresses.Address + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Addresses.Address} Address + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Address.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses.Address(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.multiaddr = r.bytes(); + break; + case 2: + m.isCertified = r.bool(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an Address message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Addresses.Address + * @static + * @param {Object.} d Plain object + * @returns {Addresses.Address} Address + */ + Address.fromObject = function fromObject(d) { + if (d instanceof $root.Addresses.Address) + return d; + var m = new $root.Addresses.Address(); + if (d.multiaddr != null) { + if (typeof d.multiaddr === "string") + $util.base64.decode(d.multiaddr, m.multiaddr = $util.newBuffer($util.base64.length(d.multiaddr)), 0); + else if (d.multiaddr.length) + m.multiaddr = d.multiaddr; + } + if (d.isCertified != null) { + m.isCertified = Boolean(d.isCertified); + } + return m; + }; + + /** + * Creates a plain object from an Address message. Also converts values to other types if specified. + * @function toObject + * @memberof Addresses.Address + * @static + * @param {Addresses.Address} m Address + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Address.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + if (o.bytes === String) + d.multiaddr = ""; + else { + d.multiaddr = []; + if (o.bytes !== Array) + d.multiaddr = $util.newBuffer(d.multiaddr); + } + d.isCertified = false; + } + if (m.multiaddr != null && m.hasOwnProperty("multiaddr")) { + d.multiaddr = o.bytes === String ? $util.base64.encode(m.multiaddr, 0, m.multiaddr.length) : o.bytes === Array ? Array.prototype.slice.call(m.multiaddr) : m.multiaddr; + } + if (m.isCertified != null && m.hasOwnProperty("isCertified")) { + d.isCertified = m.isCertified; + } + return d; + }; + + /** + * Converts this Address to JSON. + * @function toJSON + * @memberof Addresses.Address + * @instance + * @returns {Object.} JSON object + */ + Address.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Address; + })(); + + Addresses.CertifiedRecord = (function() { + + /** + * Properties of a CertifiedRecord. + * @memberof Addresses + * @interface ICertifiedRecord + * @property {number|null} [seq] CertifiedRecord seq + * @property {Uint8Array|null} [raw] CertifiedRecord raw + */ + + /** + * Constructs a new CertifiedRecord. + * @memberof Addresses + * @classdesc Represents a CertifiedRecord. + * @implements ICertifiedRecord + * @constructor + * @param {Addresses.ICertifiedRecord=} [p] Properties to set + */ + function CertifiedRecord(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * CertifiedRecord seq. + * @member {number} seq + * @memberof Addresses.CertifiedRecord + * @instance + */ + CertifiedRecord.prototype.seq = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * CertifiedRecord raw. + * @member {Uint8Array} raw + * @memberof Addresses.CertifiedRecord + * @instance + */ + CertifiedRecord.prototype.raw = $util.newBuffer([]); + + /** + * Encodes the specified CertifiedRecord message. Does not implicitly {@link Addresses.CertifiedRecord.verify|verify} messages. + * @function encode + * @memberof Addresses.CertifiedRecord + * @static + * @param {Addresses.ICertifiedRecord} m CertifiedRecord message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CertifiedRecord.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.seq != null && Object.hasOwnProperty.call(m, "seq")) + w.uint32(8).uint64(m.seq); + if (m.raw != null && Object.hasOwnProperty.call(m, "raw")) + w.uint32(18).bytes(m.raw); + return w; + }; + + /** + * Decodes a CertifiedRecord message from the specified reader or buffer. + * @function decode + * @memberof Addresses.CertifiedRecord + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Addresses.CertifiedRecord} CertifiedRecord + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CertifiedRecord.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses.CertifiedRecord(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.seq = r.uint64(); + break; + case 2: + m.raw = r.bytes(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates a CertifiedRecord message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Addresses.CertifiedRecord + * @static + * @param {Object.} d Plain object + * @returns {Addresses.CertifiedRecord} CertifiedRecord + */ + CertifiedRecord.fromObject = function fromObject(d) { + if (d instanceof $root.Addresses.CertifiedRecord) + return d; + var m = new $root.Addresses.CertifiedRecord(); + if (d.seq != null) { + if ($util.Long) + (m.seq = $util.Long.fromValue(d.seq)).unsigned = true; + else if (typeof d.seq === "string") + m.seq = parseInt(d.seq, 10); + else if (typeof d.seq === "number") + m.seq = d.seq; + else if (typeof d.seq === "object") + m.seq = new $util.LongBits(d.seq.low >>> 0, d.seq.high >>> 0).toNumber(true); + } + if (d.raw != null) { + if (typeof d.raw === "string") + $util.base64.decode(d.raw, m.raw = $util.newBuffer($util.base64.length(d.raw)), 0); + else if (d.raw.length) + m.raw = d.raw; + } + return m; + }; + + /** + * Creates a plain object from a CertifiedRecord message. Also converts values to other types if specified. + * @function toObject + * @memberof Addresses.CertifiedRecord + * @static + * @param {Addresses.CertifiedRecord} m CertifiedRecord + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + CertifiedRecord.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + if ($util.Long) { + var n = new $util.Long(0, 0, true); + d.seq = o.longs === String ? n.toString() : o.longs === Number ? n.toNumber() : n; + } else + d.seq = o.longs === String ? "0" : 0; + if (o.bytes === String) + d.raw = ""; + else { + d.raw = []; + if (o.bytes !== Array) + d.raw = $util.newBuffer(d.raw); + } + } + if (m.seq != null && m.hasOwnProperty("seq")) { + if (typeof m.seq === "number") + d.seq = o.longs === String ? String(m.seq) : m.seq; + else + d.seq = o.longs === String ? $util.Long.prototype.toString.call(m.seq) : o.longs === Number ? new $util.LongBits(m.seq.low >>> 0, m.seq.high >>> 0).toNumber(true) : m.seq; + } + if (m.raw != null && m.hasOwnProperty("raw")) { + d.raw = o.bytes === String ? $util.base64.encode(m.raw, 0, m.raw.length) : o.bytes === Array ? Array.prototype.slice.call(m.raw) : m.raw; + } + return d; + }; + + /** + * Converts this CertifiedRecord to JSON. + * @function toJSON + * @memberof Addresses.CertifiedRecord + * @instance + * @returns {Object.} JSON object + */ + CertifiedRecord.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CertifiedRecord; + })(); + + return Addresses; +})(); + +module.exports = $root; diff --git a/src/peer-store/persistent/pb/address-book.proto.js b/src/peer-store/persistent/pb/address-book.proto similarity index 81% rename from src/peer-store/persistent/pb/address-book.proto.js rename to src/peer-store/persistent/pb/address-book.proto index eff744e2e1..d154bf0de7 100644 --- a/src/peer-store/persistent/pb/address-book.proto.js +++ b/src/peer-store/persistent/pb/address-book.proto @@ -1,12 +1,9 @@ -'use strict' +syntax = "proto3"; -const protons = require('protons') - -const message = ` message Addresses { // Address represents a single multiaddr. message Address { - required bytes multiaddr = 1; + bytes multiaddr = 1; // Flag to indicate if the address comes from a certified source. optional bool isCertified = 2; @@ -27,7 +24,4 @@ message Addresses { // The most recently received signed PeerRecord. CertifiedRecord certified_record = 2; -} -` - -module.exports = protons(message).Addresses +} \ No newline at end of file diff --git a/src/peer-store/persistent/pb/proto-book.d.ts b/src/peer-store/persistent/pb/proto-book.d.ts new file mode 100644 index 0000000000..f3590f878c --- /dev/null +++ b/src/peer-store/persistent/pb/proto-book.d.ts @@ -0,0 +1,59 @@ +import * as $protobuf from "protobufjs"; +/** Properties of a Protocols. */ +export interface IProtocols { + + /** Protocols protocols */ + protocols?: (string[]|null); +} + +/** Represents a Protocols. */ +export class Protocols implements IProtocols { + + /** + * Constructs a new Protocols. + * @param [p] Properties to set + */ + constructor(p?: IProtocols); + + /** Protocols protocols. */ + public protocols: string[]; + + /** + * Encodes the specified Protocols message. Does not implicitly {@link Protocols.verify|verify} messages. + * @param m Protocols message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IProtocols, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Protocols message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Protocols + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Protocols; + + /** + * Creates a Protocols message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Protocols + */ + public static fromObject(d: { [k: string]: any }): Protocols; + + /** + * Creates a plain object from a Protocols message. Also converts values to other types if specified. + * @param m Protocols + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Protocols, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Protocols to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} diff --git a/src/peer-store/persistent/pb/proto-book.js b/src/peer-store/persistent/pb/proto-book.js new file mode 100644 index 0000000000..fea33f9933 --- /dev/null +++ b/src/peer-store/persistent/pb/proto-book.js @@ -0,0 +1,157 @@ +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.Protocols = (function() { + + /** + * Properties of a Protocols. + * @exports IProtocols + * @interface IProtocols + * @property {Array.|null} [protocols] Protocols protocols + */ + + /** + * Constructs a new Protocols. + * @exports Protocols + * @classdesc Represents a Protocols. + * @implements IProtocols + * @constructor + * @param {IProtocols=} [p] Properties to set + */ + function Protocols(p) { + this.protocols = []; + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Protocols protocols. + * @member {Array.} protocols + * @memberof Protocols + * @instance + */ + Protocols.prototype.protocols = $util.emptyArray; + + /** + * Encodes the specified Protocols message. Does not implicitly {@link Protocols.verify|verify} messages. + * @function encode + * @memberof Protocols + * @static + * @param {IProtocols} m Protocols message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Protocols.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.protocols != null && m.protocols.length) { + for (var i = 0; i < m.protocols.length; ++i) + w.uint32(10).string(m.protocols[i]); + } + return w; + }; + + /** + * Decodes a Protocols message from the specified reader or buffer. + * @function decode + * @memberof Protocols + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Protocols} Protocols + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Protocols.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Protocols(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + if (!(m.protocols && m.protocols.length)) + m.protocols = []; + m.protocols.push(r.string()); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates a Protocols message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Protocols + * @static + * @param {Object.} d Plain object + * @returns {Protocols} Protocols + */ + Protocols.fromObject = function fromObject(d) { + if (d instanceof $root.Protocols) + return d; + var m = new $root.Protocols(); + if (d.protocols) { + if (!Array.isArray(d.protocols)) + throw TypeError(".Protocols.protocols: array expected"); + m.protocols = []; + for (var i = 0; i < d.protocols.length; ++i) { + m.protocols[i] = String(d.protocols[i]); + } + } + return m; + }; + + /** + * Creates a plain object from a Protocols message. Also converts values to other types if specified. + * @function toObject + * @memberof Protocols + * @static + * @param {Protocols} m Protocols + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Protocols.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.arrays || o.defaults) { + d.protocols = []; + } + if (m.protocols && m.protocols.length) { + d.protocols = []; + for (var j = 0; j < m.protocols.length; ++j) { + d.protocols[j] = m.protocols[j]; + } + } + return d; + }; + + /** + * Converts this Protocols to JSON. + * @function toJSON + * @memberof Protocols + * @instance + * @returns {Object.} JSON object + */ + Protocols.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Protocols; +})(); + +module.exports = $root; diff --git a/src/peer-store/persistent/pb/proto-book.proto b/src/peer-store/persistent/pb/proto-book.proto new file mode 100644 index 0000000000..a452f0caf9 --- /dev/null +++ b/src/peer-store/persistent/pb/proto-book.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Protocols { + repeated string protocols = 1; +} \ No newline at end of file diff --git a/src/peer-store/persistent/pb/proto-book.proto.js b/src/peer-store/persistent/pb/proto-book.proto.js deleted file mode 100644 index 74b7e223ed..0000000000 --- a/src/peer-store/persistent/pb/proto-book.proto.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const protons = require('protons') - -/* eslint-disable no-tabs */ -const message = ` -message Protocols { - repeated string protocols = 1; -} -` - -module.exports = protons(message).Protocols diff --git a/src/peer-store/proto-book.js b/src/peer-store/proto-book.js index 5c17b1371a..3ce6d306e0 100644 --- a/src/peer-store/proto-book.js +++ b/src/peer-store/proto-book.js @@ -74,6 +74,10 @@ class ProtoBook extends Book { const recSet = this.data.get(id) const newSet = new Set(protocols) + /** + * @param {Set} a + * @param {Set} b + */ const isSetEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value)) // Already knows the peer and the recorded protocols are the same? diff --git a/src/ping/index.js b/src/ping/index.js index eb8d7b96e9..6ad988526f 100644 --- a/src/ping/index.js +++ b/src/ping/index.js @@ -8,6 +8,7 @@ const errCode = require('err-code') const crypto = require('libp2p-crypto') const { pipe } = require('it-pipe') +// @ts-ignore it-buffer has no types exported const { toBuffer } = require('it-buffer') const { collect, take } = require('streaming-iterables') const equals = require('uint8arrays/equals') @@ -16,8 +17,9 @@ const { PROTOCOL, PING_LENGTH } = require('./constants') /** * @typedef {import('../')} Libp2p - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('multiaddr').Multiaddr} Multiaddr * @typedef {import('peer-id')} PeerId + * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream */ /** @@ -31,7 +33,8 @@ async function ping (node, peer) { // @ts-ignore multiaddr might not have toB58String log('dialing %s to %s', PROTOCOL, peer.toB58String ? peer.toB58String() : peer) - const { stream } = await node.dialProtocol(peer, PROTOCOL) + const connection = await node.dial(peer) + const { stream } = await connection.newStream(PROTOCOL) const start = Date.now() const data = crypto.randomBytes(PING_LENGTH) @@ -39,7 +42,7 @@ async function ping (node, peer) { const [result] = await pipe( [data], stream, - stream => take(1, stream), + (/** @type {MuxedStream} */ stream) => take(1, stream), toBuffer, collect ) diff --git a/src/ping/util.js b/src/ping/util.js index d46b3c619b..e942420a5d 100644 --- a/src/ping/util.js +++ b/src/ping/util.js @@ -3,11 +3,16 @@ const crypto = require('libp2p-crypto') const constants = require('./constants') -exports = module.exports - -exports.rnd = (length) => { +/** + * @param {number} length + */ +function rnd (length) { if (!length) { length = constants.PING_LENGTH } return crypto.randomBytes(length) } + +module.exports = { + rnd +} diff --git a/src/pnet/crypto.js b/src/pnet/crypto.js index 9cf6f76581..da1f829710 100644 --- a/src/pnet/crypto.js +++ b/src/pnet/crypto.js @@ -7,6 +7,7 @@ const log = Object.assign(debug('libp2p:pnet'), { }) const Errors = require('./errors') +// @ts-ignore xsalsa20 has no types exported const xsalsa20 = require('xsalsa20') const KEY_LENGTH = require('./key-generator').KEY_LENGTH const uint8ArrayFromString = require('uint8arrays/from-string') @@ -21,7 +22,8 @@ const uint8ArrayToString = require('uint8arrays/to-string') */ module.exports.createBoxStream = (nonce, psk) => { const xor = xsalsa20(nonce, psk) - return (source) => (async function * () { + + return (/** @type {AsyncIterable} */ source) => (async function * () { for await (const chunk of source) { yield Uint8Array.from(xor.update(chunk.slice())) } @@ -36,7 +38,7 @@ module.exports.createBoxStream = (nonce, psk) => { * @returns {*} a through iterable */ module.exports.createUnboxStream = (nonce, psk) => { - return (source) => (async function * () { + return (/** @type {AsyncIterable} */ source) => (async function * () { const xor = xsalsa20(nonce, psk) log.trace('Decryption enabled') @@ -51,7 +53,7 @@ module.exports.createUnboxStream = (nonce, psk) => { * * @param {Uint8Array} pskBuffer * @throws {INVALID_PSK} - * @returns {Object} The PSK metadata (tag, codecName, psk) + * @returns {{ tag?: string, codecName?: string, psk: Uint8Array }} The PSK metadata (tag, codecName, psk) */ module.exports.decodeV1PSK = (pskBuffer) => { try { diff --git a/src/pnet/index.js b/src/pnet/index.js index 194a5005ec..c54e1f9c4d 100644 --- a/src/pnet/index.js +++ b/src/pnet/index.js @@ -6,6 +6,7 @@ const log = Object.assign(debug('libp2p:pnet'), { }) const { pipe } = require('it-pipe') const errcode = require('err-code') +// @ts-ignore it-pair has no types exported const duplexPair = require('it-pair/duplex') const crypto = require('libp2p-crypto') const Errors = require('./errors') @@ -17,6 +18,7 @@ const { createUnboxStream, decodeV1PSK } = require('./crypto') +// @ts-ignore it-handshake has no types exported const handshake = require('it-handshake') const { NONCE_LENGTH } = require('./key-generator') diff --git a/src/pnet/key-generator.js b/src/pnet/key-generator.js index 8a7a1ef5a2..e973f7787c 100644 --- a/src/pnet/key-generator.js +++ b/src/pnet/key-generator.js @@ -22,8 +22,12 @@ module.exports = generate module.exports.NONCE_LENGTH = 24 module.exports.KEY_LENGTH = KEY_LENGTH -// @ts-ignore This condition will always return 'false' since the types 'Module | undefined' -if (require.main === module) { - // @ts-ignore - generate(process.stdout) +try { + // @ts-ignore This condition will always return 'false' since the types 'Module | undefined' + if (require.main === module) { + // @ts-ignore + generate(process.stdout) + } +} catch (error) { + } diff --git a/src/pubsub-adapter.js b/src/pubsub-adapter.js index 7d7af8df2f..e965ab5c4b 100644 --- a/src/pubsub-adapter.js +++ b/src/pubsub-adapter.js @@ -1,12 +1,18 @@ 'use strict' +// Pubsub adapter to keep API with handlers while not removed. /** * @typedef {import('libp2p-interfaces/src/pubsub').InMessage} InMessage * @typedef {import('libp2p-interfaces/src/pubsub')} PubsubRouter */ -// Pubsub adapter to keep API with handlers while not removed. +/** + * @param {import("libp2p-interfaces/src/pubsub")} PubsubRouter + * @param {import('.')} libp2p + * @param {{ enabled: boolean; } & import(".").PubsubLocalOptions & import("libp2p-interfaces/src/pubsub").PubsubOptions} options + */ function pubsubAdapter (PubsubRouter, libp2p, options) { + // @ts-ignore Pubsub constructor type not defined const pubsub = new PubsubRouter(libp2p, options) pubsub._subscribeAdapter = pubsub.subscribe pubsub._unsubscribeAdapter = pubsub.unsubscribe diff --git a/src/record/envelope/envelope.d.ts b/src/record/envelope/envelope.d.ts new file mode 100644 index 0000000000..440590c14b --- /dev/null +++ b/src/record/envelope/envelope.d.ts @@ -0,0 +1,77 @@ +import * as $protobuf from "protobufjs"; +/** Properties of an Envelope. */ +export interface IEnvelope { + + /** Envelope publicKey */ + publicKey?: (Uint8Array|null); + + /** Envelope payloadType */ + payloadType?: (Uint8Array|null); + + /** Envelope payload */ + payload?: (Uint8Array|null); + + /** Envelope signature */ + signature?: (Uint8Array|null); +} + +/** Represents an Envelope. */ +export class Envelope implements IEnvelope { + + /** + * Constructs a new Envelope. + * @param [p] Properties to set + */ + constructor(p?: IEnvelope); + + /** Envelope publicKey. */ + public publicKey: Uint8Array; + + /** Envelope payloadType. */ + public payloadType: Uint8Array; + + /** Envelope payload. */ + public payload: Uint8Array; + + /** Envelope signature. */ + public signature: Uint8Array; + + /** + * Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages. + * @param m Envelope message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IEnvelope, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an Envelope message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns Envelope + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Envelope; + + /** + * Creates an Envelope message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns Envelope + */ + public static fromObject(d: { [k: string]: any }): Envelope; + + /** + * Creates a plain object from an Envelope message. Also converts values to other types if specified. + * @param m Envelope + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: Envelope, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Envelope to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} diff --git a/src/record/envelope/envelope.js b/src/record/envelope/envelope.js new file mode 100644 index 0000000000..ff102b2470 --- /dev/null +++ b/src/record/envelope/envelope.js @@ -0,0 +1,243 @@ +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.Envelope = (function() { + + /** + * Properties of an Envelope. + * @exports IEnvelope + * @interface IEnvelope + * @property {Uint8Array|null} [publicKey] Envelope publicKey + * @property {Uint8Array|null} [payloadType] Envelope payloadType + * @property {Uint8Array|null} [payload] Envelope payload + * @property {Uint8Array|null} [signature] Envelope signature + */ + + /** + * Constructs a new Envelope. + * @exports Envelope + * @classdesc Represents an Envelope. + * @implements IEnvelope + * @constructor + * @param {IEnvelope=} [p] Properties to set + */ + function Envelope(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * Envelope publicKey. + * @member {Uint8Array} publicKey + * @memberof Envelope + * @instance + */ + Envelope.prototype.publicKey = $util.newBuffer([]); + + /** + * Envelope payloadType. + * @member {Uint8Array} payloadType + * @memberof Envelope + * @instance + */ + Envelope.prototype.payloadType = $util.newBuffer([]); + + /** + * Envelope payload. + * @member {Uint8Array} payload + * @memberof Envelope + * @instance + */ + Envelope.prototype.payload = $util.newBuffer([]); + + /** + * Envelope signature. + * @member {Uint8Array} signature + * @memberof Envelope + * @instance + */ + Envelope.prototype.signature = $util.newBuffer([]); + + /** + * Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages. + * @function encode + * @memberof Envelope + * @static + * @param {IEnvelope} m Envelope message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Envelope.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.publicKey != null && Object.hasOwnProperty.call(m, "publicKey")) + w.uint32(10).bytes(m.publicKey); + if (m.payloadType != null && Object.hasOwnProperty.call(m, "payloadType")) + w.uint32(18).bytes(m.payloadType); + if (m.payload != null && Object.hasOwnProperty.call(m, "payload")) + w.uint32(26).bytes(m.payload); + if (m.signature != null && Object.hasOwnProperty.call(m, "signature")) + w.uint32(42).bytes(m.signature); + return w; + }; + + /** + * Decodes an Envelope message from the specified reader or buffer. + * @function decode + * @memberof Envelope + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {Envelope} Envelope + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Envelope.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.Envelope(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.publicKey = r.bytes(); + break; + case 2: + m.payloadType = r.bytes(); + break; + case 3: + m.payload = r.bytes(); + break; + case 5: + m.signature = r.bytes(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an Envelope message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Envelope + * @static + * @param {Object.} d Plain object + * @returns {Envelope} Envelope + */ + Envelope.fromObject = function fromObject(d) { + if (d instanceof $root.Envelope) + return d; + var m = new $root.Envelope(); + if (d.publicKey != null) { + if (typeof d.publicKey === "string") + $util.base64.decode(d.publicKey, m.publicKey = $util.newBuffer($util.base64.length(d.publicKey)), 0); + else if (d.publicKey.length) + m.publicKey = d.publicKey; + } + if (d.payloadType != null) { + if (typeof d.payloadType === "string") + $util.base64.decode(d.payloadType, m.payloadType = $util.newBuffer($util.base64.length(d.payloadType)), 0); + else if (d.payloadType.length) + m.payloadType = d.payloadType; + } + if (d.payload != null) { + if (typeof d.payload === "string") + $util.base64.decode(d.payload, m.payload = $util.newBuffer($util.base64.length(d.payload)), 0); + else if (d.payload.length) + m.payload = d.payload; + } + if (d.signature != null) { + if (typeof d.signature === "string") + $util.base64.decode(d.signature, m.signature = $util.newBuffer($util.base64.length(d.signature)), 0); + else if (d.signature.length) + m.signature = d.signature; + } + return m; + }; + + /** + * Creates a plain object from an Envelope message. Also converts values to other types if specified. + * @function toObject + * @memberof Envelope + * @static + * @param {Envelope} m Envelope + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + Envelope.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + if (o.bytes === String) + d.publicKey = ""; + else { + d.publicKey = []; + if (o.bytes !== Array) + d.publicKey = $util.newBuffer(d.publicKey); + } + if (o.bytes === String) + d.payloadType = ""; + else { + d.payloadType = []; + if (o.bytes !== Array) + d.payloadType = $util.newBuffer(d.payloadType); + } + if (o.bytes === String) + d.payload = ""; + else { + d.payload = []; + if (o.bytes !== Array) + d.payload = $util.newBuffer(d.payload); + } + if (o.bytes === String) + d.signature = ""; + else { + d.signature = []; + if (o.bytes !== Array) + d.signature = $util.newBuffer(d.signature); + } + } + if (m.publicKey != null && m.hasOwnProperty("publicKey")) { + d.publicKey = o.bytes === String ? $util.base64.encode(m.publicKey, 0, m.publicKey.length) : o.bytes === Array ? Array.prototype.slice.call(m.publicKey) : m.publicKey; + } + if (m.payloadType != null && m.hasOwnProperty("payloadType")) { + d.payloadType = o.bytes === String ? $util.base64.encode(m.payloadType, 0, m.payloadType.length) : o.bytes === Array ? Array.prototype.slice.call(m.payloadType) : m.payloadType; + } + if (m.payload != null && m.hasOwnProperty("payload")) { + d.payload = o.bytes === String ? $util.base64.encode(m.payload, 0, m.payload.length) : o.bytes === Array ? Array.prototype.slice.call(m.payload) : m.payload; + } + if (m.signature != null && m.hasOwnProperty("signature")) { + d.signature = o.bytes === String ? $util.base64.encode(m.signature, 0, m.signature.length) : o.bytes === Array ? Array.prototype.slice.call(m.signature) : m.signature; + } + return d; + }; + + /** + * Converts this Envelope to JSON. + * @function toJSON + * @memberof Envelope + * @instance + * @returns {Object.} JSON object + */ + Envelope.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Envelope; +})(); + +module.exports = $root; diff --git a/src/record/envelope/envelope.proto.js b/src/record/envelope/envelope.proto similarity index 79% rename from src/record/envelope/envelope.proto.js rename to src/record/envelope/envelope.proto index c8907debda..5b80cf504c 100644 --- a/src/record/envelope/envelope.proto.js +++ b/src/record/envelope/envelope.proto @@ -1,9 +1,5 @@ -'use strict' +syntax = "proto3"; -const protons = require('protons') - -/** @type {{Envelope: import('../../types').MessageProto}} */ -module.exports = protons(` message Envelope { // public_key is the public key of the keypair the enclosed payload was // signed with. @@ -20,5 +16,4 @@ message Envelope { // the enclosed public key, over the payload, prefixing a domain string for // additional security. bytes signature = 5; -} -`) +} \ No newline at end of file diff --git a/src/record/envelope/index.js b/src/record/envelope/index.js index 46f9c3ccf6..02be96e06f 100644 --- a/src/record/envelope/index.js +++ b/src/record/envelope/index.js @@ -3,13 +3,14 @@ const errCode = require('err-code') const uint8arraysConcat = require('uint8arrays/concat') const uint8arraysFromString = require('uint8arrays/from-string') +// @ts-ignore libp2p-crypto does not support types const cryptoKeys = require('libp2p-crypto/src/keys') const PeerId = require('peer-id') const varint = require('varint') const uint8arraysEquals = require('uint8arrays/equals') const { codes } = require('../../errors') -const Protobuf = require('./envelope.proto') +const { Envelope: Protobuf } = require('./envelope') /** * @typedef {import('libp2p-interfaces/src/record/types').Record} Record @@ -49,12 +50,12 @@ class Envelope { const publicKey = cryptoKeys.marshalPublicKey(this.peerId.pubKey) - this._marshal = Protobuf.Envelope.encode({ - public_key: publicKey, - payload_type: this.payloadType, + this._marshal = Protobuf.encode({ + publicKey: publicKey, + payloadType: this.payloadType, payload: this.payload, signature: this.signature - }) + }).finish() return this._marshal } @@ -124,12 +125,12 @@ const formatSignaturePayload = (domain, payloadType, payload) => { * @returns {Promise} */ Envelope.createFromProtobuf = async (data) => { - const envelopeData = Protobuf.Envelope.decode(data) - const peerId = await PeerId.createFromPubKey(envelopeData.public_key) + const envelopeData = Protobuf.decode(data) + const peerId = await PeerId.createFromPubKey(envelopeData.publicKey) return new Envelope({ peerId, - payloadType: envelopeData.payload_type, + payloadType: envelopeData.payloadType, payload: envelopeData.payload, signature: envelopeData.signature }) diff --git a/src/record/peer-record/index.js b/src/record/peer-record/index.js index 32d018abc5..dcdc7b6285 100644 --- a/src/record/peer-record/index.js +++ b/src/record/peer-record/index.js @@ -1,18 +1,17 @@ 'use strict' -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const arrayEquals = require('libp2p-utils/src/array-equals') -const Protobuf = require('./peer-record.proto') +const { PeerRecord: Protobuf } = require('./peer-record') const { ENVELOPE_DOMAIN_PEER_RECORD, ENVELOPE_PAYLOAD_TYPE_PEER_RECORD } = require('./consts') /** - * @typedef {import('peer-id')} PeerId - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('../../peer-store/address-book.js').Address} Address * @typedef {import('libp2p-interfaces/src/record/types').Record} Record */ @@ -52,13 +51,13 @@ class PeerRecord { return this._marshal } - this._marshal = Protobuf.PeerRecord.encode({ - peer_id: this.peerId.toBytes(), + this._marshal = Protobuf.encode({ + peerId: this.peerId.toBytes(), seq: this.seqNumber, addresses: this.multiaddrs.map((m) => ({ multiaddr: m.bytes })) - }) + }).finish() return this._marshal } @@ -100,12 +99,11 @@ class PeerRecord { * @returns {PeerRecord} */ PeerRecord.createFromProtobuf = (buf) => { - // Decode - const peerRecord = Protobuf.PeerRecord.decode(buf) + const peerRecord = Protobuf.decode(buf) - const peerId = PeerId.createFromBytes(peerRecord.peer_id) - const multiaddrs = (peerRecord.addresses || []).map((a) => multiaddr(a.multiaddr)) - const seqNumber = peerRecord.seq + const peerId = PeerId.createFromBytes(peerRecord.peerId) + const multiaddrs = (peerRecord.addresses || []).map((a) => new Multiaddr(a.multiaddr)) + const seqNumber = Number(peerRecord.seq) return new PeerRecord({ peerId, multiaddrs, seqNumber }) } diff --git a/src/record/peer-record/peer-record.d.ts b/src/record/peer-record/peer-record.d.ts new file mode 100644 index 0000000000..a851b53307 --- /dev/null +++ b/src/record/peer-record/peer-record.d.ts @@ -0,0 +1,133 @@ +import * as $protobuf from "protobufjs"; +/** Properties of a PeerRecord. */ +export interface IPeerRecord { + + /** PeerRecord peerId */ + peerId?: (Uint8Array|null); + + /** PeerRecord seq */ + seq?: (number|null); + + /** PeerRecord addresses */ + addresses?: (PeerRecord.IAddressInfo[]|null); +} + +/** Represents a PeerRecord. */ +export class PeerRecord implements IPeerRecord { + + /** + * Constructs a new PeerRecord. + * @param [p] Properties to set + */ + constructor(p?: IPeerRecord); + + /** PeerRecord peerId. */ + public peerId: Uint8Array; + + /** PeerRecord seq. */ + public seq: number; + + /** PeerRecord addresses. */ + public addresses: PeerRecord.IAddressInfo[]; + + /** + * Encodes the specified PeerRecord message. Does not implicitly {@link PeerRecord.verify|verify} messages. + * @param m PeerRecord message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: IPeerRecord, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a PeerRecord message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns PeerRecord + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): PeerRecord; + + /** + * Creates a PeerRecord message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns PeerRecord + */ + public static fromObject(d: { [k: string]: any }): PeerRecord; + + /** + * Creates a plain object from a PeerRecord message. Also converts values to other types if specified. + * @param m PeerRecord + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: PeerRecord, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this PeerRecord to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +export namespace PeerRecord { + + /** Properties of an AddressInfo. */ + interface IAddressInfo { + + /** AddressInfo multiaddr */ + multiaddr?: (Uint8Array|null); + } + + /** Represents an AddressInfo. */ + class AddressInfo implements IAddressInfo { + + /** + * Constructs a new AddressInfo. + * @param [p] Properties to set + */ + constructor(p?: PeerRecord.IAddressInfo); + + /** AddressInfo multiaddr. */ + public multiaddr: Uint8Array; + + /** + * Encodes the specified AddressInfo message. Does not implicitly {@link PeerRecord.AddressInfo.verify|verify} messages. + * @param m AddressInfo message or plain object to encode + * @param [w] Writer to encode to + * @returns Writer + */ + public static encode(m: PeerRecord.IAddressInfo, w?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes an AddressInfo message from the specified reader or buffer. + * @param r Reader or buffer to decode from + * @param [l] Message length if known beforehand + * @returns AddressInfo + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): PeerRecord.AddressInfo; + + /** + * Creates an AddressInfo message from a plain object. Also converts values to their respective internal types. + * @param d Plain object + * @returns AddressInfo + */ + public static fromObject(d: { [k: string]: any }): PeerRecord.AddressInfo; + + /** + * Creates a plain object from an AddressInfo message. Also converts values to other types if specified. + * @param m AddressInfo + * @param [o] Conversion options + * @returns Plain object + */ + public static toObject(m: PeerRecord.AddressInfo, o?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this AddressInfo to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } +} diff --git a/src/record/peer-record/peer-record.js b/src/record/peer-record/peer-record.js new file mode 100644 index 0000000000..e851b146b7 --- /dev/null +++ b/src/record/peer-record/peer-record.js @@ -0,0 +1,367 @@ +/*eslint-disable*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.PeerRecord = (function() { + + /** + * Properties of a PeerRecord. + * @exports IPeerRecord + * @interface IPeerRecord + * @property {Uint8Array|null} [peerId] PeerRecord peerId + * @property {number|null} [seq] PeerRecord seq + * @property {Array.|null} [addresses] PeerRecord addresses + */ + + /** + * Constructs a new PeerRecord. + * @exports PeerRecord + * @classdesc Represents a PeerRecord. + * @implements IPeerRecord + * @constructor + * @param {IPeerRecord=} [p] Properties to set + */ + function PeerRecord(p) { + this.addresses = []; + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * PeerRecord peerId. + * @member {Uint8Array} peerId + * @memberof PeerRecord + * @instance + */ + PeerRecord.prototype.peerId = $util.newBuffer([]); + + /** + * PeerRecord seq. + * @member {number} seq + * @memberof PeerRecord + * @instance + */ + PeerRecord.prototype.seq = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * PeerRecord addresses. + * @member {Array.} addresses + * @memberof PeerRecord + * @instance + */ + PeerRecord.prototype.addresses = $util.emptyArray; + + /** + * Encodes the specified PeerRecord message. Does not implicitly {@link PeerRecord.verify|verify} messages. + * @function encode + * @memberof PeerRecord + * @static + * @param {IPeerRecord} m PeerRecord message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + PeerRecord.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.peerId != null && Object.hasOwnProperty.call(m, "peerId")) + w.uint32(10).bytes(m.peerId); + if (m.seq != null && Object.hasOwnProperty.call(m, "seq")) + w.uint32(16).uint64(m.seq); + if (m.addresses != null && m.addresses.length) { + for (var i = 0; i < m.addresses.length; ++i) + $root.PeerRecord.AddressInfo.encode(m.addresses[i], w.uint32(26).fork()).ldelim(); + } + return w; + }; + + /** + * Decodes a PeerRecord message from the specified reader or buffer. + * @function decode + * @memberof PeerRecord + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {PeerRecord} PeerRecord + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + PeerRecord.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.PeerRecord(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.peerId = r.bytes(); + break; + case 2: + m.seq = r.uint64(); + break; + case 3: + if (!(m.addresses && m.addresses.length)) + m.addresses = []; + m.addresses.push($root.PeerRecord.AddressInfo.decode(r, r.uint32())); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates a PeerRecord message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof PeerRecord + * @static + * @param {Object.} d Plain object + * @returns {PeerRecord} PeerRecord + */ + PeerRecord.fromObject = function fromObject(d) { + if (d instanceof $root.PeerRecord) + return d; + var m = new $root.PeerRecord(); + if (d.peerId != null) { + if (typeof d.peerId === "string") + $util.base64.decode(d.peerId, m.peerId = $util.newBuffer($util.base64.length(d.peerId)), 0); + else if (d.peerId.length) + m.peerId = d.peerId; + } + if (d.seq != null) { + if ($util.Long) + (m.seq = $util.Long.fromValue(d.seq)).unsigned = true; + else if (typeof d.seq === "string") + m.seq = parseInt(d.seq, 10); + else if (typeof d.seq === "number") + m.seq = d.seq; + else if (typeof d.seq === "object") + m.seq = new $util.LongBits(d.seq.low >>> 0, d.seq.high >>> 0).toNumber(true); + } + if (d.addresses) { + if (!Array.isArray(d.addresses)) + throw TypeError(".PeerRecord.addresses: array expected"); + m.addresses = []; + for (var i = 0; i < d.addresses.length; ++i) { + if (typeof d.addresses[i] !== "object") + throw TypeError(".PeerRecord.addresses: object expected"); + m.addresses[i] = $root.PeerRecord.AddressInfo.fromObject(d.addresses[i]); + } + } + return m; + }; + + /** + * Creates a plain object from a PeerRecord message. Also converts values to other types if specified. + * @function toObject + * @memberof PeerRecord + * @static + * @param {PeerRecord} m PeerRecord + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + PeerRecord.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.arrays || o.defaults) { + d.addresses = []; + } + if (o.defaults) { + if (o.bytes === String) + d.peerId = ""; + else { + d.peerId = []; + if (o.bytes !== Array) + d.peerId = $util.newBuffer(d.peerId); + } + if ($util.Long) { + var n = new $util.Long(0, 0, true); + d.seq = o.longs === String ? n.toString() : o.longs === Number ? n.toNumber() : n; + } else + d.seq = o.longs === String ? "0" : 0; + } + if (m.peerId != null && m.hasOwnProperty("peerId")) { + d.peerId = o.bytes === String ? $util.base64.encode(m.peerId, 0, m.peerId.length) : o.bytes === Array ? Array.prototype.slice.call(m.peerId) : m.peerId; + } + if (m.seq != null && m.hasOwnProperty("seq")) { + if (typeof m.seq === "number") + d.seq = o.longs === String ? String(m.seq) : m.seq; + else + d.seq = o.longs === String ? $util.Long.prototype.toString.call(m.seq) : o.longs === Number ? new $util.LongBits(m.seq.low >>> 0, m.seq.high >>> 0).toNumber(true) : m.seq; + } + if (m.addresses && m.addresses.length) { + d.addresses = []; + for (var j = 0; j < m.addresses.length; ++j) { + d.addresses[j] = $root.PeerRecord.AddressInfo.toObject(m.addresses[j], o); + } + } + return d; + }; + + /** + * Converts this PeerRecord to JSON. + * @function toJSON + * @memberof PeerRecord + * @instance + * @returns {Object.} JSON object + */ + PeerRecord.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + PeerRecord.AddressInfo = (function() { + + /** + * Properties of an AddressInfo. + * @memberof PeerRecord + * @interface IAddressInfo + * @property {Uint8Array|null} [multiaddr] AddressInfo multiaddr + */ + + /** + * Constructs a new AddressInfo. + * @memberof PeerRecord + * @classdesc Represents an AddressInfo. + * @implements IAddressInfo + * @constructor + * @param {PeerRecord.IAddressInfo=} [p] Properties to set + */ + function AddressInfo(p) { + if (p) + for (var ks = Object.keys(p), i = 0; i < ks.length; ++i) + if (p[ks[i]] != null) + this[ks[i]] = p[ks[i]]; + } + + /** + * AddressInfo multiaddr. + * @member {Uint8Array} multiaddr + * @memberof PeerRecord.AddressInfo + * @instance + */ + AddressInfo.prototype.multiaddr = $util.newBuffer([]); + + /** + * Encodes the specified AddressInfo message. Does not implicitly {@link PeerRecord.AddressInfo.verify|verify} messages. + * @function encode + * @memberof PeerRecord.AddressInfo + * @static + * @param {PeerRecord.IAddressInfo} m AddressInfo message or plain object to encode + * @param {$protobuf.Writer} [w] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + AddressInfo.encode = function encode(m, w) { + if (!w) + w = $Writer.create(); + if (m.multiaddr != null && Object.hasOwnProperty.call(m, "multiaddr")) + w.uint32(10).bytes(m.multiaddr); + return w; + }; + + /** + * Decodes an AddressInfo message from the specified reader or buffer. + * @function decode + * @memberof PeerRecord.AddressInfo + * @static + * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from + * @param {number} [l] Message length if known beforehand + * @returns {PeerRecord.AddressInfo} AddressInfo + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + AddressInfo.decode = function decode(r, l) { + if (!(r instanceof $Reader)) + r = $Reader.create(r); + var c = l === undefined ? r.len : r.pos + l, m = new $root.PeerRecord.AddressInfo(); + while (r.pos < c) { + var t = r.uint32(); + switch (t >>> 3) { + case 1: + m.multiaddr = r.bytes(); + break; + default: + r.skipType(t & 7); + break; + } + } + return m; + }; + + /** + * Creates an AddressInfo message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof PeerRecord.AddressInfo + * @static + * @param {Object.} d Plain object + * @returns {PeerRecord.AddressInfo} AddressInfo + */ + AddressInfo.fromObject = function fromObject(d) { + if (d instanceof $root.PeerRecord.AddressInfo) + return d; + var m = new $root.PeerRecord.AddressInfo(); + if (d.multiaddr != null) { + if (typeof d.multiaddr === "string") + $util.base64.decode(d.multiaddr, m.multiaddr = $util.newBuffer($util.base64.length(d.multiaddr)), 0); + else if (d.multiaddr.length) + m.multiaddr = d.multiaddr; + } + return m; + }; + + /** + * Creates a plain object from an AddressInfo message. Also converts values to other types if specified. + * @function toObject + * @memberof PeerRecord.AddressInfo + * @static + * @param {PeerRecord.AddressInfo} m AddressInfo + * @param {$protobuf.IConversionOptions} [o] Conversion options + * @returns {Object.} Plain object + */ + AddressInfo.toObject = function toObject(m, o) { + if (!o) + o = {}; + var d = {}; + if (o.defaults) { + if (o.bytes === String) + d.multiaddr = ""; + else { + d.multiaddr = []; + if (o.bytes !== Array) + d.multiaddr = $util.newBuffer(d.multiaddr); + } + } + if (m.multiaddr != null && m.hasOwnProperty("multiaddr")) { + d.multiaddr = o.bytes === String ? $util.base64.encode(m.multiaddr, 0, m.multiaddr.length) : o.bytes === Array ? Array.prototype.slice.call(m.multiaddr) : m.multiaddr; + } + return d; + }; + + /** + * Converts this AddressInfo to JSON. + * @function toJSON + * @memberof PeerRecord.AddressInfo + * @instance + * @returns {Object.} JSON object + */ + AddressInfo.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return AddressInfo; + })(); + + return PeerRecord; +})(); + +module.exports = $root; diff --git a/src/record/peer-record/peer-record.proto.js b/src/record/peer-record/peer-record.proto similarity index 52% rename from src/record/peer-record/peer-record.proto.js rename to src/record/peer-record/peer-record.proto index 0ebb3b90d0..6b740dc80f 100644 --- a/src/record/peer-record/peer-record.proto.js +++ b/src/record/peer-record/peer-record.proto @@ -1,14 +1,5 @@ -'use strict' +syntax = "proto3"; -const protons = require('protons') - -// PeerRecord messages contain information that is useful to share with other peers. -// Currently, a PeerRecord contains the public listen addresses for a peer, but this -// is expected to expand to include other information in the future. -// PeerRecords are designed to be serialized to bytes and placed inside of -// SignedEnvelopes before sharing with other peers. -/** @type {{PeerRecord: import('../../types').MessageProto}} */ -module.exports = protons(` message PeerRecord { // AddressInfo is a wrapper around a binary multiaddr. It is defined as a // separate message to allow us to add per-address metadata in the future. @@ -24,5 +15,4 @@ message PeerRecord { // addresses is a list of public listen addresses for the peer. repeated AddressInfo addresses = 3; -} -`) +} \ No newline at end of file diff --git a/src/registrar.js b/src/registrar.js index 367f110c80..2a2f9f4084 100644 --- a/src/registrar.js +++ b/src/registrar.js @@ -1,8 +1,8 @@ 'use strict' const debug = require('debug') -const log = Object.assign(debug('libp2p:peer-store'), { - error: debug('libp2p:peer-store:err') +const log = Object.assign(debug('libp2p:registrar'), { + error: debug('libp2p:registrar:err') }) const errcode = require('err-code') @@ -16,7 +16,11 @@ const Topology = require('libp2p-interfaces/src/topology') * @typedef {import('./peer-store')} PeerStore * @typedef {import('./connection-manager')} ConnectionManager * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection - * @typedef {import('libp2p-interfaces/src/topology')} Topology + * @typedef {import('./').HandlerProps} HandlerProps + */ + +/** + * */ /** @@ -38,20 +42,28 @@ class Registrar { /** * Map of topologies * - * @type {Map} + * @type {Map} */ this.topologies = new Map() + /** @type {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} */ + // @ts-ignore handle is not optional this._handle = undefined this._onDisconnect = this._onDisconnect.bind(this) this.connectionManager.on('peer:disconnect', this._onDisconnect) } + /** + * @returns {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} + */ get handle () { return this._handle } + /** + * @param {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} handle + */ set handle (handle) { this._handle = handle } @@ -103,12 +115,11 @@ class Registrar { * Remove a disconnected peer from the record * * @param {Connection} connection - * @param {Error} [error] * @returns {void} */ - _onDisconnect (connection, error) { + _onDisconnect (connection) { for (const [, topology] of this.topologies) { - topology.disconnect(connection.remotePeer, error) + topology.disconnect(connection.remotePeer) } } } diff --git a/src/transport-manager.js b/src/transport-manager.js index 7b41b87d39..1993edf80c 100644 --- a/src/transport-manager.js +++ b/src/transport-manager.js @@ -12,10 +12,10 @@ const errCode = require('err-code') const { updateSelfPeerRecord } = require('./record/utils') /** - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('multiaddr').Multiaddr} Multiaddr * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection - * @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory - * @typedef {import('libp2p-interfaces/src/transport/types').Transport} Transport + * @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory + * @typedef {import('libp2p-interfaces/src/transport/types').Transport} Transport * * @typedef {Object} TransportManagerProperties * @property {import('./')} libp2p @@ -121,6 +121,7 @@ class TransportManager { * @returns {Multiaddr[]} */ getAddrs () { + /** @type {Multiaddr[]} */ let addrs = [] for (const listeners of this._listeners.values()) { for (const listener of listeners) { diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index 16c00ef109..0000000000 --- a/src/types.ts +++ /dev/null @@ -1,103 +0,0 @@ - -// Insecure Message types -export enum KeyType { - RSA = 0, - Ed25519 = 1, - Secp256k1 = 2, - ECDSA = 3 -} - -// Protobufs -export type MessageProto = { - encode(value: any): Uint8Array - decode(bytes: Uint8Array): any -} - -export type SUCCESS = 100; -export type HOP_SRC_ADDR_TOO_LONG = 220; -export type HOP_DST_ADDR_TOO_LONG = 221; -export type HOP_SRC_MULTIADDR_INVALID = 250; -export type HOP_DST_MULTIADDR_INVALID = 251; -export type HOP_NO_CONN_TO_DST = 260; -export type HOP_CANT_DIAL_DST = 261; -export type HOP_CANT_OPEN_DST_STREAM = 262; -export type HOP_CANT_SPEAK_RELAY = 270; -export type HOP_CANT_RELAY_TO_SELF = 280; -export type STOP_SRC_ADDR_TOO_LONG = 320; -export type STOP_DST_ADDR_TOO_LONG = 321; -export type STOP_SRC_MULTIADDR_INVALID = 350; -export type STOP_DST_MULTIADDR_INVALID = 351; -export type STOP_RELAY_REFUSED = 390; -export type MALFORMED_MESSAGE = 400; - -export type CircuitStatus = SUCCESS | HOP_SRC_ADDR_TOO_LONG | HOP_DST_ADDR_TOO_LONG - | HOP_SRC_MULTIADDR_INVALID | HOP_DST_MULTIADDR_INVALID | HOP_NO_CONN_TO_DST - | HOP_CANT_DIAL_DST | HOP_CANT_OPEN_DST_STREAM | HOP_CANT_SPEAK_RELAY | HOP_CANT_RELAY_TO_SELF - | STOP_SRC_ADDR_TOO_LONG | STOP_DST_ADDR_TOO_LONG | STOP_SRC_MULTIADDR_INVALID - | STOP_DST_MULTIADDR_INVALID | STOP_RELAY_REFUSED | MALFORMED_MESSAGE - -export type HOP = 1; -export type STOP = 2; -export type STATUS = 3; -export type CAN_HOP = 4; - -export type CircuitType = HOP | STOP | STATUS | CAN_HOP - -export type CircuitPeer = { - id: Uint8Array - addrs: Uint8Array[] -} - -export type CircuitRequest = { - type: CircuitType - dstPeer: CircuitPeer - srcPeer: CircuitPeer -} - -export type CircuitMessageProto = { - encode(value: any): Uint8Array - decode(bytes: Uint8Array): any - Status: { - SUCCESS: SUCCESS, - HOP_SRC_ADDR_TOO_LONG: HOP_SRC_ADDR_TOO_LONG, - HOP_DST_ADDR_TOO_LONG: HOP_DST_ADDR_TOO_LONG, - HOP_SRC_MULTIADDR_INVALID: HOP_SRC_MULTIADDR_INVALID, - HOP_DST_MULTIADDR_INVALID: HOP_DST_MULTIADDR_INVALID, - HOP_NO_CONN_TO_DST: HOP_NO_CONN_TO_DST, - HOP_CANT_DIAL_DST: HOP_CANT_DIAL_DST, - HOP_CANT_OPEN_DST_STREAM: HOP_CANT_OPEN_DST_STREAM, - HOP_CANT_SPEAK_RELAY: HOP_CANT_SPEAK_RELAY, - HOP_CANT_RELAY_TO_SELF: HOP_CANT_RELAY_TO_SELF, - STOP_SRC_ADDR_TOO_LONG: STOP_SRC_ADDR_TOO_LONG, - STOP_DST_ADDR_TOO_LONG: STOP_DST_ADDR_TOO_LONG, - STOP_SRC_MULTIADDR_INVALID: STOP_SRC_MULTIADDR_INVALID, - STOP_DST_MULTIADDR_INVALID: STOP_DST_MULTIADDR_INVALID, - STOP_RELAY_REFUSED: STOP_RELAY_REFUSED, - MALFORMED_MESSAGE: MALFORMED_MESSAGE - }, - Type: { - HOP: HOP, - STOP: STOP, - STATUS: STATUS, - CAN_HOP: CAN_HOP - } -} - -export interface EventEmitterFactory { - new(): EventEmitter; -} - -export interface EventEmitter { - addListener(event: string | symbol, listener: (...args: any[]) => void); - on(event: string | symbol, listener: (...args: any[]) => void); - once(event: string | symbol, listener: (...args: any[]) => void); - removeListener(event: string | symbol, listener: (...args: any[]) => void); - off(event: string | symbol, listener: (...args: any[]) => void); - removeAllListeners(event?: string | symbol); - setMaxListeners(n: number); - getMaxListeners(): number; - listeners(event: string | symbol): Function[]; // eslint-disable-line @typescript-eslint/ban-types - rawListeners(event: string | symbol): Function[]; // eslint-disable-line @typescript-eslint/ban-types - emit(event: string | symbol, ...args: any[]): boolean; - listenerCount(event: string | symbol): number; -} diff --git a/src/upgrader.js b/src/upgrader.js index 7e7ec22a95..6f5f3f0169 100644 --- a/src/upgrader.js +++ b/src/upgrader.js @@ -5,10 +5,12 @@ const log = Object.assign(debug('libp2p:upgrader'), { error: debug('libp2p:upgrader:err') }) const errCode = require('err-code') +// @ts-ignore multistream-select does not export types const Multistream = require('multistream-select') const { Connection } = require('libp2p-interfaces/src/connection') const PeerId = require('peer-id') const { pipe } = require('it-pipe') +// @ts-ignore mutable-proxy does not export types const mutableProxy = require('mutable-proxy') const { codes } = require('./errors') @@ -19,7 +21,8 @@ const { codes } = require('./errors') * @typedef {import('libp2p-interfaces/src/stream-muxer/types').Muxer} Muxer * @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream * @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto - * @typedef {import('multiaddr')} Multiaddr + * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection + * @typedef {import('multiaddr').Multiaddr} Multiaddr */ /** @@ -36,8 +39,8 @@ class Upgrader { * @param {import('./metrics')} [options.metrics] * @param {Map} [options.cryptos] * @param {Map} [options.muxers] - * @param {(Connection) => void} options.onConnection - Called when a connection is upgraded - * @param {(Connection) => void} options.onConnectionEnd + * @param {(connection: Connection) => void} options.onConnection - Called when a connection is upgraded + * @param {(connection: Connection) => void} options.onConnectionEnd */ constructor ({ localPeer, @@ -51,6 +54,7 @@ class Upgrader { this.metrics = metrics this.cryptos = cryptos this.muxers = muxers + /** @type {import("./pnet") | null} */ this.protector = null this.protocols = new Map() this.onConnection = onConnection @@ -216,16 +220,18 @@ class Upgrader { Muxer, remotePeer }) { + /** @type {import("libp2p-interfaces/src/stream-muxer/types").Muxer} */ let muxer let newStream - // eslint-disable-next-line prefer-const - let connection + /** @type {Connection} */ + let connection // eslint-disable-line prefer-const if (Muxer) { // Create the muxer muxer = new Muxer({ // Run anytime a remote stream is created onStream: async muxedStream => { + if (!connection) return const mss = new Multistream.Listener(muxedStream) try { const { stream, protocol } = await mss.handle(Array.from(this.protocols.keys())) @@ -243,7 +249,7 @@ class Upgrader { } }) - newStream = async protocols => { + newStream = async (/** @type {string | string[]} */ protocols) => { log('%s: starting new stream on %s', direction, protocols) const muxedStream = muxer.newStream() const mss = new Multistream.Dialer(muxedStream) @@ -302,12 +308,12 @@ class Upgrader { encryption: cryptoProtocol }, newStream: newStream || errConnectionNotMultiplexed, - getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed, - close: async (err) => { + getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed(), + close: async (/** @type {Error | undefined} */ err) => { await maConn.close(err) // Ensure remaining streams are aborted if (muxer) { - muxer.streams.map(stream => stream.abort(err)) + muxer.streams.map(stream => stream.abort()) } } }) @@ -371,7 +377,7 @@ class Upgrader { * @private * @async * @param {PeerId} localPeer - The initiators PeerId - * @param {*} connection + * @param {MultiaddrConnection} connection * @param {PeerId} remotePeerId * @param {Map} cryptos * @returns {Promise} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used diff --git a/test/addresses/address-manager.spec.js b/test/addresses/address-manager.spec.js index c27ef2992d..1074700864 100644 --- a/test/addresses/address-manager.spec.js +++ b/test/addresses/address-manager.spec.js @@ -2,7 +2,7 @@ /* eslint-env mocha */ const { expect } = require('aegir/utils/chai') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const AddressManager = require('../../src/address-manager') @@ -37,8 +37,8 @@ describe('Address Manager', () => { const listenMultiaddrs = am.getListenAddrs() expect(listenMultiaddrs.length).to.equal(2) - expect(listenMultiaddrs[0].equals(multiaddr(listenAddresses[0]))).to.equal(true) - expect(listenMultiaddrs[1].equals(multiaddr(listenAddresses[1]))).to.equal(true) + expect(listenMultiaddrs[0].equals(new Multiaddr(listenAddresses[0]))).to.equal(true) + expect(listenMultiaddrs[1].equals(new Multiaddr(listenAddresses[1]))).to.equal(true) }) it('should return announce multiaddrs on get', () => { @@ -52,7 +52,7 @@ describe('Address Manager', () => { const announceMultiaddrs = am.getAnnounceAddrs() expect(announceMultiaddrs.length).to.equal(1) - expect(announceMultiaddrs[0].equals(multiaddr(announceAddreses[0]))).to.equal(true) + expect(announceMultiaddrs[0].equals(new Multiaddr(announceAddreses[0]))).to.equal(true) }) it('should add observed addresses', () => { diff --git a/test/addresses/addresses.node.js b/test/addresses/addresses.node.js index 719e52721a..00d93ca13b 100644 --- a/test/addresses/addresses.node.js +++ b/test/addresses/addresses.node.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback') const { AddressesOptions } = require('./utils') @@ -111,9 +111,9 @@ describe('libp2p.multiaddrs', () => { expect(libp2p.multiaddrs.length).to.equal(0) // Stub transportManager addresses to add a public address - const stubMa = multiaddr('/ip4/120.220.10.1/tcp/1000') + const stubMa = new Multiaddr('/ip4/120.220.10.1/tcp/1000') sinon.stub(libp2p.transportManager, 'getAddrs').returns([ - ...listenAddresses.map((a) => multiaddr(a)), + ...listenAddresses.map((a) => new Multiaddr(a)), stubMa ]) diff --git a/test/content-routing/content-routing.node.js b/test/content-routing/content-routing.node.js index 09a11f250f..ff2079a505 100644 --- a/test/content-routing/content-routing.node.js +++ b/test/content-routing/content-routing.node.js @@ -11,7 +11,7 @@ const mergeOptions = require('merge-options') const CID = require('cids') const ipfsHttpClient = require('ipfs-http-client') const DelegatedContentRouter = require('libp2p-delegated-content-routing') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const drain = require('it-drain') const all = require('it-all') @@ -28,6 +28,8 @@ describe('content-routing', () => { }) }) + after(() => node.stop()) + it('.findProviders should return an error', async () => { try { for await (const _ of node.contentRouting.findProviders('a cid')) {} // eslint-disable-line @@ -277,7 +279,7 @@ describe('content-routing', () => { const result = { id: providerPeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/49320') + new Multiaddr('/ip4/123.123.123.123/tcp/49320') ] } @@ -301,7 +303,7 @@ describe('content-routing', () => { const result = { id: providerPeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/49320') + new Multiaddr('/ip4/123.123.123.123/tcp/49320') ] } @@ -327,7 +329,7 @@ describe('content-routing', () => { const result = { id: providerPeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/49320') + new Multiaddr('/ip4/123.123.123.123/tcp/49320') ] } @@ -348,13 +350,13 @@ describe('content-routing', () => { const result1 = { id: providerPeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/49320') + new Multiaddr('/ip4/123.123.123.123/tcp/49320') ] } const result2 = { id: providerPeerId, multiaddrs: [ - multiaddr('/ip4/213.213.213.213/tcp/2344') + new Multiaddr('/ip4/213.213.213.213/tcp/2344') ] } diff --git a/test/content-routing/dht/operation.node.js b/test/content-routing/dht/operation.node.js index 6f8a4a0b52..946d92748f 100644 --- a/test/content-routing/dht/operation.node.js +++ b/test/content-routing/dht/operation.node.js @@ -3,7 +3,7 @@ const { expect } = require('aegir/utils/chai') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const pWaitFor = require('p-wait-for') const mergeOptions = require('merge-options') const uint8ArrayFromString = require('uint8arrays/from-string') @@ -12,8 +12,8 @@ const { create } = require('../../../src') const { subsystemOptions, subsystemMulticodecs } = require('./utils') const peerUtils = require('../../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/8000') -const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/8001') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8000') +const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8001') describe('DHT subsystem operates correctly', () => { let peerId, remotePeerId diff --git a/test/core/ping.node.js b/test/core/ping.node.js index 510e5e3cb7..4bbd4f76cc 100644 --- a/test/core/ping.node.js +++ b/test/core/ping.node.js @@ -23,6 +23,8 @@ describe('ping', () => { nodes[1].peerStore.addressBook.set(nodes[0].peerId, nodes[0].multiaddrs) }) + afterEach(() => Promise.all(nodes.map(n => n.stop()))) + it('ping once from peer0 to peer1 using a multiaddr', async () => { const ma = `${nodes[2].multiaddrs[0]}/p2p/${nodes[2].peerId.toB58String()}` const latency = await nodes[0].ping(ma) @@ -56,6 +58,7 @@ describe('ping', () => { if (firstInvocation) { firstInvocation = false + // eslint-disable-next-line no-unreachable-loop for await (const data of stream) { return { value: data, diff --git a/test/dialing/direct.node.js b/test/dialing/direct.node.js index 33a73d0fbe..1f8a5dfee7 100644 --- a/test/dialing/direct.node.js +++ b/test/dialing/direct.node.js @@ -6,7 +6,7 @@ const sinon = require('sinon') const Transport = require('libp2p-tcp') const Muxer = require('libp2p-mplex') const { NOISE: Crypto } = require('libp2p-noise') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const delay = require('delay') const pDefer = require('p-defer') @@ -33,8 +33,8 @@ const createMockConnection = require('../utils/mockConnection') const Peers = require('../fixtures/peers') const { createPeerId } = require('../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') -const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') +const unsupportedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN') describe('Dialing (direct, TCP)', () => { let remoteTM @@ -147,7 +147,7 @@ describe('Dialing (direct, TCP)', () => { const dialer = new Dialer({ transportManager: localTM, peerStore, - timeout: 50 + dialTimeout: 50 }) sinon.stub(localTM, 'dial').callsFake(async (addr, options) => { expect(options.signal).to.exist() @@ -165,13 +165,13 @@ describe('Dialing (direct, TCP)', () => { it('should dial to the max concurrency', async () => { const addrs = [ - multiaddr('/ip4/0.0.0.0/tcp/8000'), - multiaddr('/ip4/0.0.0.0/tcp/8001'), - multiaddr('/ip4/0.0.0.0/tcp/8002') + new Multiaddr('/ip4/0.0.0.0/tcp/8000'), + new Multiaddr('/ip4/0.0.0.0/tcp/8001'), + new Multiaddr('/ip4/0.0.0.0/tcp/8002') ] const dialer = new Dialer({ transportManager: localTM, - concurrency: 2, + maxParallelDials: 2, peerStore: { addressBook: { add: () => {}, diff --git a/test/dialing/direct.spec.js b/test/dialing/direct.spec.js index 782d947164..a074e02f97 100644 --- a/test/dialing/direct.spec.js +++ b/test/dialing/direct.spec.js @@ -10,7 +10,7 @@ const Transport = require('libp2p-websockets') const filters = require('libp2p-websockets/src/filters') const Muxer = require('libp2p-mplex') const { NOISE: Crypto } = require('libp2p-noise') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const AggregateError = require('aggregate-error') const { AbortError } = require('libp2p-interfaces/src/transport/errors') @@ -26,7 +26,7 @@ const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser') const mockUpgrader = require('../utils/mockUpgrader') const createMockConnection = require('../utils/mockConnection') const { createPeerId } = require('../utils/creators/peer') -const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN') +const unsupportedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN') const remoteAddr = MULTIADDRS_WEBSOCKETS[0] describe('Dialing (direct, WebSockets)', () => { @@ -52,7 +52,7 @@ describe('Dialing (direct, WebSockets)', () => { it('should have appropriate defaults', () => { const dialer = new Dialer({ transportManager: localTM, peerStore }) - expect(dialer.concurrency).to.equal(Constants.MAX_PARALLEL_DIALS) + expect(dialer.maxParallelDials).to.equal(Constants.MAX_PARALLEL_DIALS) expect(dialer.timeout).to.equal(Constants.DIAL_TIMEOUT) }) @@ -155,7 +155,7 @@ describe('Dialing (direct, WebSockets)', () => { it('should abort dials on queue task timeout', async () => { const dialer = new Dialer({ transportManager: localTM, - timeout: 50, + dialTimeout: 50, peerStore: { addressBook: { add: () => {}, @@ -179,9 +179,9 @@ describe('Dialing (direct, WebSockets)', () => { it('should sort addresses on dial', async () => { const peerMultiaddrs = [ - multiaddr('/ip4/127.0.0.1/tcp/15001/ws'), - multiaddr('/ip4/20.0.0.1/tcp/15001/ws'), - multiaddr('/ip4/30.0.0.1/tcp/15001/ws') + new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws'), + new Multiaddr('/ip4/20.0.0.1/tcp/15001/ws'), + new Multiaddr('/ip4/30.0.0.1/tcp/15001/ws') ] sinon.spy(addressSort, 'publicAddressesFirst') @@ -190,7 +190,7 @@ describe('Dialing (direct, WebSockets)', () => { const dialer = new Dialer({ transportManager: localTM, addressSorter: addressSort.publicAddressesFirst, - concurrency: 3, + maxParallelDials: 3, peerStore }) @@ -211,7 +211,7 @@ describe('Dialing (direct, WebSockets)', () => { it('should dial to the max concurrency', async () => { const dialer = new Dialer({ transportManager: localTM, - concurrency: 2, + maxParallelDials: 2, peerStore: { addressBook: { set: () => {}, @@ -249,7 +249,7 @@ describe('Dialing (direct, WebSockets)', () => { it('.destroy should abort pending dials', async () => { const dialer = new Dialer({ transportManager: localTM, - concurrency: 2, + maxParallelDials: 2, peerStore: { addressBook: { set: () => {}, @@ -318,8 +318,8 @@ describe('Dialing (direct, WebSockets)', () => { }) expect(libp2p.dialer).to.exist() - expect(libp2p.dialer.concurrency).to.equal(Constants.MAX_PARALLEL_DIALS) - expect(libp2p.dialer.perPeerLimit).to.equal(Constants.MAX_PER_PEER_DIALS) + expect(libp2p.dialer.maxParallelDials).to.equal(Constants.MAX_PARALLEL_DIALS) + expect(libp2p.dialer.maxDialsPerPeer).to.equal(Constants.MAX_PER_PEER_DIALS) expect(libp2p.dialer.timeout).to.equal(Constants.DIAL_TIMEOUT) // Ensure the dialer also has the transport manager expect(libp2p.transportManager).to.equal(libp2p.dialer.transportManager) @@ -349,8 +349,8 @@ describe('Dialing (direct, WebSockets)', () => { libp2p = await Libp2p.create(config) expect(libp2p.dialer).to.exist() - expect(libp2p.dialer.concurrency).to.equal(config.dialer.maxParallelDials) - expect(libp2p.dialer.perPeerLimit).to.equal(config.dialer.maxDialsPerPeer) + expect(libp2p.dialer.maxParallelDials).to.equal(config.dialer.maxParallelDials) + expect(libp2p.dialer.maxDialsPerPeer).to.equal(config.dialer.maxDialsPerPeer) expect(libp2p.dialer.timeout).to.equal(config.dialer.dialTimeout) }) diff --git a/test/dialing/resolver.spec.js b/test/dialing/resolver.spec.js index 094f657a6d..f5088ae982 100644 --- a/test/dialing/resolver.spec.js +++ b/test/dialing/resolver.spec.js @@ -4,8 +4,8 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') -const multiaddr = require('multiaddr') -const { Resolver } = require('multiaddr/src/resolvers/dns') +const { Multiaddr } = require('multiaddr') +const Resolver = require('multiaddr/src/resolvers/dns') const { codes: ErrorCodes } = require('../../src/errors') @@ -39,7 +39,7 @@ describe('Dialing (resolvable addresses)', () => { config: { ...baseOptions, addresses: { - listen: [multiaddr(`${relayAddr}/p2p-circuit`)] + listen: [new Multiaddr(`${relayAddr}/p2p-circuit`)] }, config: { ...baseOptions.config, @@ -60,8 +60,8 @@ describe('Dialing (resolvable addresses)', () => { it('resolves dnsaddr to ws local address', async () => { const remoteId = remoteLibp2p.peerId.toB58String() - const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) - const relayedAddrFetched = multiaddr(relayedAddr(remoteId)) + const dialAddr = new Multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) + const relayedAddrFetched = new Multiaddr(relayedAddr(remoteId)) // Transport spy const transport = libp2p.transportManager._transports.get('Circuit') @@ -82,8 +82,8 @@ describe('Dialing (resolvable addresses)', () => { it('resolves a dnsaddr recursively', async () => { const remoteId = remoteLibp2p.peerId.toB58String() - const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) - const relayedAddrFetched = multiaddr(relayedAddr(remoteId)) + const dialAddr = new Multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) + const relayedAddrFetched = new Multiaddr(relayedAddr(remoteId)) // Transport spy const transport = libp2p.transportManager._transports.get('Circuit') @@ -114,10 +114,10 @@ describe('Dialing (resolvable addresses)', () => { // Resolver just returns the received multiaddrs it('stops recursive resolve if finds dns4/dns6 and dials it', async () => { const remoteId = remoteLibp2p.peerId.toB58String() - const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) + const dialAddr = new Multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) // Stub resolver - const dnsMa = multiaddr(`/dns4/ams-1.remote.libp2p.io/tcp/443/wss/p2p/${remoteId}`) + const dnsMa = new Multiaddr(`/dns4/ams-1.remote.libp2p.io/tcp/443/wss/p2p/${remoteId}`) const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt') stubResolve.returns(Promise.resolve([ [`dnsaddr=${dnsMa}`] @@ -135,8 +135,8 @@ describe('Dialing (resolvable addresses)', () => { it('resolves a dnsaddr recursively not failing if one address fails to resolve', async () => { const remoteId = remoteLibp2p.peerId.toB58String() - const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) - const relayedAddrFetched = multiaddr(relayedAddr(remoteId)) + const dialAddr = new Multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) + const relayedAddrFetched = new Multiaddr(relayedAddr(remoteId)) // Transport spy const transport = libp2p.transportManager._transports.get('Circuit') @@ -159,7 +159,7 @@ describe('Dialing (resolvable addresses)', () => { it('fails to dial if resolve fails and there are no addresses to dial', async () => { const remoteId = remoteLibp2p.peerId.toB58String() - const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) + const dialAddr = new Multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`) // Stub resolver const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt') diff --git a/test/fixtures/browser.js b/test/fixtures/browser.js index f5f33259dc..8bcec6a116 100644 --- a/test/fixtures/browser.js +++ b/test/fixtures/browser.js @@ -1,7 +1,7 @@ 'use strict' -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') module.exports.MULTIADDRS_WEBSOCKETS = [ - multiaddr('/ip4/127.0.0.1/tcp/15001/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5') + new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5') ] diff --git a/test/identify/index.spec.js b/test/identify/index.spec.js index d7b0d8b2bf..65d2a77f20 100644 --- a/test/identify/index.spec.js +++ b/test/identify/index.spec.js @@ -7,7 +7,7 @@ const sinon = require('sinon') const { EventEmitter } = require('events') const PeerId = require('peer-id') const duplexPair = require('it-pair/duplex') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const pWaitFor = require('p-wait-for') const unit8ArrayToString = require('uint8arrays/to-string') @@ -25,7 +25,7 @@ const AddressManager = require('../../src/address-manager') const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser') const remoteAddr = MULTIADDRS_WEBSOCKETS[0] -const listenMaddrs = [multiaddr('/ip4/127.0.0.1/tcp/15002/ws')] +const listenMaddrs = [new Multiaddr('/ip4/127.0.0.1/tcp/15002/ws')] describe('Identify', () => { let localPeer, localPeerStore, localAddressManager @@ -74,7 +74,7 @@ describe('Identify', () => { } }) - const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234') + const observedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/1234') const localConnectionMock = { newStream: () => {}, remotePeer } const remoteConnectionMock = { remoteAddr: observedAddr } @@ -110,6 +110,7 @@ describe('Identify', () => { // LEGACY it('should be able to identify another peer with no certified peer records support', async () => { + const agentVersion = `js-libp2p/${pkg.version}` const localIdentify = new IdentifyService({ libp2p: { peerId: localPeer, @@ -118,7 +119,7 @@ describe('Identify', () => { peerStore: localPeerStore, multiaddrs: listenMaddrs, isStarted: () => true, - _options: { host: {} } + _options: { host: { agentVersion } } } }) @@ -130,11 +131,11 @@ describe('Identify', () => { peerStore: remotePeerStore, multiaddrs: listenMaddrs, isStarted: () => true, - _options: { host: {} } + _options: { host: { agentVersion } } } }) - const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234') + const observedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/1234') const localConnectionMock = { newStream: () => {}, remotePeer } const remoteConnectionMock = { remoteAddr: observedAddr } @@ -162,7 +163,7 @@ describe('Identify', () => { const metadataArgs = localIdentify.peerStore.metadataBook.set.firstCall.args expect(metadataArgs[0].id.bytes).to.equal(remotePeer.bytes) expect(metadataArgs[1]).to.equal('AgentVersion') - expect(unit8ArrayToString(metadataArgs[2])).to.equal(`js-libp2p/${pkg.version}`) + expect(unit8ArrayToString(metadataArgs[2])).to.equal(agentVersion) // Validate the remote peer gets updated in the peer store const call = localIdentify.peerStore.addressBook.set.firstCall @@ -192,7 +193,7 @@ describe('Identify', () => { } }) - const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234') + const observedAddr = new Multiaddr('/ip4/127.0.0.1/tcp/1234') const localConnectionMock = { newStream: () => {}, remotePeer: localPeer } const remoteConnectionMock = { remoteAddr: observedAddr } @@ -500,7 +501,7 @@ describe('Identify', () => { await libp2p.identifyService.identify.firstCall.returnValue sinon.stub(libp2p, 'isStarted').returns(true) - libp2p.peerStore.addressBook.add(libp2p.peerId, [multiaddr('/ip4/180.0.0.1/tcp/15001/ws')]) + libp2p.peerStore.addressBook.add(libp2p.peerId, [new Multiaddr('/ip4/180.0.0.1/tcp/15001/ws')]) // Verify the remote peer is notified of change expect(libp2p.identifyService.push.callCount).to.equal(1) diff --git a/test/keychain/keychain.spec.js b/test/keychain/keychain.spec.js index 1b74c91eb2..55e1511097 100644 --- a/test/keychain/keychain.spec.js +++ b/test/keychain/keychain.spec.js @@ -27,8 +27,8 @@ describe('keychain', () => { datastore1 = new MemoryDatastore() datastore2 = new MemoryDatastore() - ks = new Keychain(datastore2, { passPhrase: passPhrase }) - emptyKeystore = new Keychain(datastore1, { passPhrase: passPhrase }) + ks = new Keychain(datastore2, { pass: passPhrase }) + emptyKeystore = new Keychain(datastore1, { pass: passPhrase }) await datastore1.open() await datastore2.open() @@ -44,11 +44,11 @@ describe('keychain', () => { }) it('needs a NIST SP 800-132 non-weak pass phrase', () => { - expect(() => new Keychain(datastore2, { passPhrase: '< 20 character' })).to.throw() + expect(() => new Keychain(datastore2, { pass: '< 20 character' })).to.throw() }) it('needs a store to persist a key', () => { - expect(() => new Keychain(null, { passPhrase: passPhrase })).to.throw() + expect(() => new Keychain(null, { pass: passPhrase })).to.throw() }) it('has default options', () => { @@ -56,12 +56,12 @@ describe('keychain', () => { }) it('supports supported hashing alorithms', () => { - const ok = new Keychain(datastore2, { passPhrase: passPhrase, dek: { hash: 'sha2-256' } }) + const ok = new Keychain(datastore2, { pass: passPhrase, dek: { hash: 'sha2-256' } }) expect(ok).to.exist() }) it('does not support unsupported hashing alorithms', () => { - expect(() => new Keychain(datastore2, { passPhrase: passPhrase, dek: { hash: 'my-hash' } })).to.throw() + expect(() => new Keychain(datastore2, { pass: passPhrase, dek: { hash: 'my-hash' } })).to.throw() }) it('can list keys without a password', async () => { @@ -72,7 +72,7 @@ describe('keychain', () => { it('can find a key without a password', async () => { const keychain = new Keychain(datastore2) - const keychainWithPassword = new Keychain(datastore2, { passPhrase: `hello-${Date.now()}-${Date.now()}` }) + const keychainWithPassword = new Keychain(datastore2, { pass: `hello-${Date.now()}-${Date.now()}` }) const name = `key-${Math.random()}` const { id } = await keychainWithPassword.createKey(name, 'ed25519') @@ -82,7 +82,7 @@ describe('keychain', () => { it('can remove a key without a password', async () => { const keychainWithoutPassword = new Keychain(datastore2) - const keychainWithPassword = new Keychain(datastore2, { passPhrase: `hello-${Date.now()}-${Date.now()}` }) + const keychainWithPassword = new Keychain(datastore2, { pass: `hello-${Date.now()}-${Date.now()}` }) const name = `key-${Math.random()}` expect(await keychainWithPassword.createKey(name, 'ed25519')).to.have.property('name', name) @@ -99,7 +99,7 @@ describe('keychain', () => { it('can generate options', () => { const options = Keychain.generateOptions() - options.passPhrase = passPhrase + options.pass = passPhrase const chain = new Keychain(datastore2, options) expect(chain).to.exist() }) diff --git a/test/nat-manager/nat-manager.node.js b/test/nat-manager/nat-manager.node.js index 55acb0babd..5f5562e0b0 100644 --- a/test/nat-manager/nat-manager.node.js +++ b/test/nat-manager/nat-manager.node.js @@ -71,7 +71,7 @@ describe('Nat Manager (TCP)', () => { } } - afterEach(() => Promise.all(teardown)) + afterEach(() => Promise.all(teardown.map(t => t()))) it('should map TCP connections to external ports', async () => { const { diff --git a/test/peer-discovery/index.node.js b/test/peer-discovery/index.node.js index 63976cb83c..3f6b3f33ea 100644 --- a/test/peer-discovery/index.node.js +++ b/test/peer-discovery/index.node.js @@ -10,14 +10,14 @@ const Bootstrap = require('libp2p-bootstrap') const crypto = require('libp2p-crypto') const KadDht = require('libp2p-kad-dht') const MulticastDNS = require('libp2p-mdns') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const uint8ArrayToString = require('uint8arrays/to-string') const Libp2p = require('../../src') const baseOptions = require('../utils/base-options') const { createPeerId } = require('../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') describe('peer discovery scenarios', () => { let peerId, remotePeerId1, remotePeerId2 @@ -30,6 +30,7 @@ describe('peer discovery scenarios', () => { afterEach(async () => { libp2p && await libp2p.stop() }) + it('should ignore self on discovery', async () => { libp2p = new Libp2p(mergeOptions(baseOptions, { peerId, diff --git a/test/peer-discovery/index.spec.js b/test/peer-discovery/index.spec.js index 2fd037a0ef..72248621b0 100644 --- a/test/peer-discovery/index.spec.js +++ b/test/peer-discovery/index.spec.js @@ -7,7 +7,7 @@ const sinon = require('sinon') const defer = require('p-defer') const mergeOptions = require('merge-options') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const WebRTCStar = require('libp2p-webrtc-star') const Libp2p = require('../../src') @@ -38,7 +38,7 @@ describe('peer discovery', () => { } }) - libp2p.peerStore.addressBook.set(remotePeerId, [multiaddr('/ip4/165.1.1.1/tcp/80')]) + libp2p.peerStore.addressBook.set(remotePeerId, [new Multiaddr('/ip4/165.1.1.1/tcp/80')]) const deferred = defer() sinon.stub(libp2p.dialer, 'connectToPeer').callsFake((remotePeerId) => { @@ -89,6 +89,10 @@ describe('peer discovery', () => { [peerId] = await createPeerId() }) + afterEach(async () => { + libp2p && await libp2p.stop() + }) + it('should add discovery module if present in transports and enabled', async () => { libp2p = new Libp2p(mergeOptions(baseOptions, { peerId, diff --git a/test/peer-routing/peer-routing.node.js b/test/peer-routing/peer-routing.node.js index 2badd3597a..5413c3f189 100644 --- a/test/peer-routing/peer-routing.node.js +++ b/test/peer-routing/peer-routing.node.js @@ -15,7 +15,7 @@ const all = require('it-all') const ipfsHttpClient = require('ipfs-http-client') const DelegatedPeerRouter = require('libp2p-delegated-peer-routing') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const peerUtils = require('../utils/creators/peer') @@ -31,6 +31,8 @@ describe('peer-routing', () => { }) }) + after(() => node.stop()) + it('.findPeer should return an error', async () => { await expect(node.peerRouting.findPeer('a cid')) .to.eventually.be.rejected() @@ -360,7 +362,7 @@ describe('peer-routing', () => { const results = { id: remotePeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/38982') + new Multiaddr('/ip4/123.123.123.123/tcp/38982') ] } @@ -400,7 +402,7 @@ describe('peer-routing', () => { const result = { id: remotePeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/38982') + new Multiaddr('/ip4/123.123.123.123/tcp/38982') ] } @@ -422,7 +424,7 @@ describe('peer-routing', () => { const results = [{ id: remotePeerId, multiaddrs: [ - multiaddr('/ip4/123.123.123.123/tcp/38982') + new Multiaddr('/ip4/123.123.123.123/tcp/38982') ] }] @@ -456,8 +458,8 @@ describe('peer-routing', () => { it('should be enabled and start by default', async () => { const results = [ - { id: peerIds[0], multiaddrs: [multiaddr('/ip4/30.0.0.1/tcp/2000')] }, - { id: peerIds[1], multiaddrs: [multiaddr('/ip4/32.0.0.1/tcp/2000')] } + { id: peerIds[0], multiaddrs: [new Multiaddr('/ip4/30.0.0.1/tcp/2000')] }, + { id: peerIds[1], multiaddrs: [new Multiaddr('/ip4/32.0.0.1/tcp/2000')] } ] ;[node] = await peerUtils.createPeer({ @@ -533,7 +535,7 @@ describe('peer-routing', () => { }) sinon.stub(node._dht, 'getClosestPeers').callsFake(function * () { - yield { id: peerIds[0], multiaddrs: [multiaddr('/ip4/30.0.0.1/tcp/2000')] } + yield { id: peerIds[0], multiaddrs: [new Multiaddr('/ip4/30.0.0.1/tcp/2000')] } }) await node.start() diff --git a/test/peer-store/address-book.spec.js b/test/peer-store/address-book.spec.js index 0adae21d61..48eb7180bc 100644 --- a/test/peer-store/address-book.spec.js +++ b/test/peer-store/address-book.spec.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const { Buffer } = require('buffer') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const arrayEquals = require('libp2p-utils/src/array-equals') const addressSort = require('libp2p-utils/src/address-sort') const PeerId = require('peer-id') @@ -19,9 +19,9 @@ const { codes: { ERR_INVALID_PARAMETERS } } = require('../../src/errors') -const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000') -const addr2 = multiaddr('/ip4/20.0.0.1/tcp/8001') -const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002') +const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000') +const addr2 = new Multiaddr('/ip4/20.0.0.1/tcp/8001') +const addr3 = new Multiaddr('/ip4/127.0.0.1/tcp/8002') describe('addressBook', () => { let peerId diff --git a/test/peer-store/peer-store.node.js b/test/peer-store/peer-store.node.js index 8c322a2cce..794de82c2f 100644 --- a/test/peer-store/peer-store.node.js +++ b/test/peer-store/peer-store.node.js @@ -21,6 +21,8 @@ describe('libp2p.peerStore', () => { }) }) + afterEach(() => Promise.all([libp2p, remoteLibp2p].map(l => l.stop()))) + it('adds peer address to AddressBook and keys to the keybook when establishing connection', async () => { const remoteIdStr = remoteLibp2p.peerId.toB58String() diff --git a/test/peer-store/peer-store.spec.js b/test/peer-store/peer-store.spec.js index 39c2c7187d..c316240bdd 100644 --- a/test/peer-store/peer-store.spec.js +++ b/test/peer-store/peer-store.spec.js @@ -4,15 +4,15 @@ const { expect } = require('aegir/utils/chai') const PeerStore = require('../../src/peer-store') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const uint8ArrayFromString = require('uint8arrays/from-string') const peerUtils = require('../utils/creators/peer') -const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000') -const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001') -const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002') -const addr4 = multiaddr('/ip4/127.0.0.1/tcp/8003') +const addr1 = new Multiaddr('/ip4/127.0.0.1/tcp/8000') +const addr2 = new Multiaddr('/ip4/127.0.0.1/tcp/8001') +const addr3 = new Multiaddr('/ip4/127.0.0.1/tcp/8002') +const addr4 = new Multiaddr('/ip4/127.0.0.1/tcp/8003') const proto1 = '/protocol1' const proto2 = '/protocol2' diff --git a/test/peer-store/persisted-peer-store.spec.js b/test/peer-store/persisted-peer-store.spec.js index e1d7047629..9c669efd52 100644 --- a/test/peer-store/persisted-peer-store.spec.js +++ b/test/peer-store/persisted-peer-store.spec.js @@ -8,7 +8,7 @@ const Envelope = require('../../src/record/envelope') const PeerRecord = require('../../src/record/peer-record') const PeerStore = require('../../src/peer-store/persistent') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const { MemoryDatastore } = require('interface-datastore') const uint8ArrayFromString = require('uint8arrays/from-string') @@ -65,7 +65,7 @@ describe('Persisted PeerStore', () => { it('should store peerStore content on datastore after peer marked as dirty (threshold 1)', async () => { const [peer] = await peerUtils.createPeerId({ number: 2 }) - const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')] const protocols = ['/ping/1.0.0'] const spyDirty = sinon.spy(peerStore, '_addDirtyPeer') const spyDs = sinon.spy(datastore, 'batch') @@ -115,8 +115,8 @@ describe('Persisted PeerStore', () => { const peers = await peerUtils.createPeerId({ number: 2 }) const commitSpy = sinon.spy(peerStore, '_commitData') const multiaddrs = [ - multiaddr('/ip4/156.10.1.22/tcp/1000'), - multiaddr('/ip4/156.10.1.23/tcp/1000') + new Multiaddr('/ip4/156.10.1.22/tcp/1000'), + new Multiaddr('/ip4/156.10.1.23/tcp/1000') ] const protocols = ['/ping/1.0.0'] @@ -173,7 +173,7 @@ describe('Persisted PeerStore', () => { it('should delete content from the datastore on delete', async () => { const [peer] = await peerUtils.createPeerId() - const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')] const protocols = ['/ping/1.0.0'] const commitSpy = sinon.spy(peerStore, '_commitData') @@ -221,7 +221,7 @@ describe('Persisted PeerStore', () => { it('should store certified peer records after peer marked as dirty (threshold 1)', async () => { const [peerId] = await peerUtils.createPeerId() - const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')] const spyDirty = sinon.spy(peerStore, '_addDirtyPeer') const spyDs = sinon.spy(datastore, 'batch') const commitSpy = sinon.spy(peerStore, '_commitData') @@ -266,8 +266,8 @@ describe('Persisted PeerStore', () => { const peers = await peerUtils.createPeerId({ number: 2 }) const commitSpy = sinon.spy(peerStore, '_commitData') const multiaddrs = [ - multiaddr('/ip4/156.10.1.22/tcp/1000'), - multiaddr('/ip4/156.10.1.23/tcp/1000') + new Multiaddr('/ip4/156.10.1.22/tcp/1000'), + new Multiaddr('/ip4/156.10.1.23/tcp/1000') ] const peerRecord0 = new PeerRecord({ peerId: peers[0], @@ -332,7 +332,7 @@ describe('Persisted PeerStore', () => { it('should delete certified peer records from the datastore on delete', async () => { const [peer] = await peerUtils.createPeerId() - const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')] const commitSpy = sinon.spy(peerStore, '_commitData') await peerStore.start() @@ -395,7 +395,7 @@ describe('Persisted PeerStore', () => { const peers = await peerUtils.createPeerId({ number: 2 }) - const multiaddrs = [multiaddr('/ip4/156.10.1.22/tcp/1000')] + const multiaddrs = [new Multiaddr('/ip4/156.10.1.22/tcp/1000')] const protocols = ['/ping/1.0.0'] await peerStore.start() @@ -540,8 +540,8 @@ describe('libp2p.peerStore (Persisted)', () => { const commitSpy = sinon.spy(libp2p.peerStore, '_commitData') const peers = await peerUtils.createPeerId({ number: 3 }) const multiaddrs = [ - multiaddr('/ip4/156.10.1.22/tcp/1000'), - multiaddr('/ip4/156.10.1.23/tcp/1000') + new Multiaddr('/ip4/156.10.1.22/tcp/1000'), + new Multiaddr('/ip4/156.10.1.23/tcp/1000') ] const protocols = ['/ping/1.0.0'] @@ -572,6 +572,11 @@ describe('libp2p.peerStore (Persisted)', () => { datastore: memoryDatastore, peerStore: { persistence: true + }, + config: { + peerDiscovery: { + autoDial: false + } } } }) diff --git a/test/pubsub/configuration.node.js b/test/pubsub/configuration.node.js index 12b0b584a6..998b886ee5 100644 --- a/test/pubsub/configuration.node.js +++ b/test/pubsub/configuration.node.js @@ -3,13 +3,13 @@ const { expect } = require('aegir/utils/chai') const mergeOptions = require('merge-options') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const { create } = require('../../src') const { baseOptions, subsystemOptions } = require('./utils') const peerUtils = require('../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') describe('Pubsub subsystem is configurable', () => { let libp2p diff --git a/test/pubsub/implementations.node.js b/test/pubsub/implementations.node.js index 3243d94b94..165df61bc1 100644 --- a/test/pubsub/implementations.node.js +++ b/test/pubsub/implementations.node.js @@ -12,14 +12,14 @@ const { multicodec: floodsubMulticodec } = require('libp2p-floodsub') const { multicodec: gossipsubMulticodec } = require('libp2p-gossipsub') const uint8ArrayToString = require('uint8arrays/to-string') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const { create } = require('../../src') const { baseOptions } = require('./utils') const peerUtils = require('../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') -const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') +const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') describe('Pubsub subsystem is able to use different implementations', () => { let peerId, remotePeerId diff --git a/test/pubsub/operation.node.js b/test/pubsub/operation.node.js index 2ebe39dae4..2103438373 100644 --- a/test/pubsub/operation.node.js +++ b/test/pubsub/operation.node.js @@ -7,15 +7,15 @@ const sinon = require('sinon') const pWaitFor = require('p-wait-for') const pDefer = require('p-defer') const mergeOptions = require('merge-options') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const uint8ArrayToString = require('uint8arrays/to-string') const { create } = require('../../src') const { subsystemOptions, subsystemMulticodecs } = require('./utils') const peerUtils = require('../utils/creators/peer') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') -const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') +const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') describe('Pubsub subsystem operates correctly', () => { let peerId, remotePeerId diff --git a/test/record/peer-record.spec.js b/test/record/peer-record.spec.js index e8b8ed64cd..7865e2dfad 100644 --- a/test/record/peer-record.spec.js +++ b/test/record/peer-record.spec.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const tests = require('libp2p-interfaces/src/record/tests') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const Envelope = require('../../src/record/envelope') @@ -60,7 +60,7 @@ describe('PeerRecord', () => { it('creates a peer record with provided data', () => { const multiaddrs = [ - multiaddr('/ip4/127.0.0.1/tcp/2000') + new Multiaddr('/ip4/127.0.0.1/tcp/2000') ] const seqNumber = Date.now() const peerRecord = new PeerRecord({ peerId, multiaddrs, seqNumber }) @@ -75,7 +75,7 @@ describe('PeerRecord', () => { it('marshals and unmarshals a peer record', () => { const multiaddrs = [ - multiaddr('/ip4/127.0.0.1/tcp/2000') + new Multiaddr('/ip4/127.0.0.1/tcp/2000') ] const seqNumber = Date.now() const peerRecord = new PeerRecord({ peerId, multiaddrs, seqNumber }) @@ -115,12 +115,12 @@ describe('PeerRecord', () => { it('equals returns false if the peer record has a different multiaddrs', () => { const multiaddrs = [ - multiaddr('/ip4/127.0.0.1/tcp/2000') + new Multiaddr('/ip4/127.0.0.1/tcp/2000') ] const peerRecord0 = new PeerRecord({ peerId, multiaddrs }) const multiaddrs1 = [ - multiaddr('/ip4/127.0.0.1/tcp/2001') + new Multiaddr('/ip4/127.0.0.1/tcp/2001') ] const peerRecord1 = new PeerRecord({ peerId, multiaddrs: multiaddrs1 }) @@ -136,7 +136,7 @@ describe('PeerRecord inside Envelope', () => { before(async () => { [peerId] = await peerUtils.createPeerId() const multiaddrs = [ - multiaddr('/ip4/127.0.0.1/tcp/2000') + new Multiaddr('/ip4/127.0.0.1/tcp/2000') ] const seqNumber = Date.now() peerRecord = new PeerRecord({ peerId, multiaddrs, seqNumber }) diff --git a/test/relay/auto-relay.node.js b/test/relay/auto-relay.node.js index 2411f48a57..a254b0475d 100644 --- a/test/relay/auto-relay.node.js +++ b/test/relay/auto-relay.node.js @@ -9,7 +9,7 @@ const nock = require('nock') const ipfsHttpClient = require('ipfs-http-client') const DelegatedContentRouter = require('libp2p-delegated-content-routing') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const Libp2p = require('../../src') const { relay: relayMulticodec } = require('../../src/circuit/multicodec') @@ -204,7 +204,7 @@ describe('auto-relay', () => { expect(relayLibp2p1.multiaddrs[originalMultiaddrs1Length].getPeerId()).to.eql(relayLibp2p2.peerId.toB58String()) // Dial from the other through a relay - const relayedMultiaddr2 = multiaddr(`${relayLibp2p1.multiaddrs[0]}/p2p/${relayLibp2p1.peerId.toB58String()}/p2p-circuit`) + const relayedMultiaddr2 = new Multiaddr(`${relayLibp2p1.multiaddrs[0]}/p2p/${relayLibp2p1.peerId.toB58String()}/p2p-circuit`) libp2p.peerStore.addressBook.add(relayLibp2p2.peerId, [relayedMultiaddr2]) await libp2p.dial(relayLibp2p2.peerId) @@ -473,7 +473,7 @@ describe('auto-relay', () => { protocol: 'http', port: 60197 }), [ - multiaddr('/ip4/0.0.0.0/tcp/60197') + new Multiaddr('/ip4/0.0.0.0/tcp/60197') ]) const opts = { diff --git a/test/relay/relay.node.js b/test/relay/relay.node.js index 163bd83105..033f21a3fc 100644 --- a/test/relay/relay.node.js +++ b/test/relay/relay.node.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const { collect } = require('streaming-iterables') const pipe = require('it-pipe') const AggregateError = require('aggregate-error') @@ -67,7 +67,7 @@ describe('Dialing (via relay, TCP)', () => { .encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerId.toB58String()}`) const tcpAddrs = dstLibp2p.transportManager.getAddrs() - sinon.stub(dstLibp2p.addressManager, 'listen').value([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)]) + sinon.stub(dstLibp2p.addressManager, 'listen').value([new Multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)]) await dstLibp2p.transportManager.listen(dstLibp2p.addressManager.getListenAddrs()) expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')]) @@ -152,7 +152,7 @@ describe('Dialing (via relay, TCP)', () => { // Connect the destination peer and the relay const tcpAddrs = dstLibp2p.transportManager.getAddrs() - sinon.stub(dstLibp2p.addressManager, 'getListenAddrs').returns([multiaddr(`${relayAddr}/p2p-circuit`)]) + sinon.stub(dstLibp2p.addressManager, 'getListenAddrs').returns([new Multiaddr(`${relayAddr}/p2p-circuit`)]) await dstLibp2p.transportManager.listen(dstLibp2p.addressManager.getListenAddrs()) expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')]) diff --git a/test/transports/transport-manager.node.js b/test/transports/transport-manager.node.js index 6c335d92bf..13854ce031 100644 --- a/test/transports/transport-manager.node.js +++ b/test/transports/transport-manager.node.js @@ -9,13 +9,13 @@ const PeerStore = require('../../src/peer-store') const PeerRecord = require('../../src/record/peer-record') const Transport = require('libp2p-tcp') const PeerId = require('peer-id') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const mockUpgrader = require('../utils/mockUpgrader') const sinon = require('sinon') const Peers = require('../fixtures/peers') const addrs = [ - multiaddr('/ip4/127.0.0.1/tcp/0'), - multiaddr('/ip4/127.0.0.1/tcp/0') + new Multiaddr('/ip4/127.0.0.1/tcp/0'), + new Multiaddr('/ip4/127.0.0.1/tcp/0') ] describe('Transport Manager (TCP)', () => { diff --git a/test/transports/transport-manager.spec.js b/test/transports/transport-manager.spec.js index 5c6c08b06e..75bb1b9193 100644 --- a/test/transports/transport-manager.spec.js +++ b/test/transports/transport-manager.spec.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const Transport = require('libp2p-websockets') const filters = require('libp2p-websockets/src/filters') const { NOISE: Crypto } = require('libp2p-noise') @@ -19,7 +19,7 @@ const { FaultTolerance } = require('../../src/transport-manager') const Peers = require('../fixtures/peers') const PeerId = require('peer-id') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') describe('Transport Manager (WebSockets)', () => { let tm @@ -76,7 +76,7 @@ describe('Transport Manager (WebSockets)', () => { it('should fail to dial an unsupported address', async () => { tm.add(Transport.prototype[Symbol.toStringTag], Transport, { filter: filters.all }) - const addr = multiaddr('/ip4/127.0.0.1/tcp/0') + const addr = new Multiaddr('/ip4/127.0.0.1/tcp/0') await expect(tm.dial(addr)) .to.eventually.be.rejected() .and.to.have.property('code', ErrorCodes.ERR_TRANSPORT_UNAVAILABLE) @@ -191,7 +191,7 @@ describe('libp2p.transportManager (dial only)', () => { libp2p = new Libp2p({ peerId, addresses: { - listen: [multiaddr('/ip4/127.0.0.1/tcp/0')] + listen: [new Multiaddr('/ip4/127.0.0.1/tcp/0')] }, modules: { transport: [Transport], @@ -213,7 +213,7 @@ describe('libp2p.transportManager (dial only)', () => { libp2p = new Libp2p({ peerId, addresses: { - listen: [multiaddr('/ip4/127.0.0.1/tcp/0')] + listen: [new Multiaddr('/ip4/127.0.0.1/tcp/0')] }, transportManager: { faultTolerance: FaultTolerance.NO_FATAL @@ -231,7 +231,7 @@ describe('libp2p.transportManager (dial only)', () => { libp2p = new Libp2p({ peerId, addresses: { - listen: [multiaddr('/ip4/127.0.0.1/tcp/12345/p2p/QmWDn2LY8nannvSWJzruUYoLZ4vV83vfCBwd8DipvdgQc3/p2p-circuit')] + listen: [new Multiaddr('/ip4/127.0.0.1/tcp/12345/p2p/QmWDn2LY8nannvSWJzruUYoLZ4vV83vfCBwd8DipvdgQc3/p2p-circuit')] }, transportManager: { faultTolerance: FaultTolerance.NO_FATAL diff --git a/test/ts-use/package.json b/test/ts-use/package.json new file mode 100644 index 0000000000..c3a06e4a81 --- /dev/null +++ b/test/ts-use/package.json @@ -0,0 +1,24 @@ +{ + "name": "ts-use", + "private": true, + "dependencies": { + "datastore-level": "^4.0.0", + "ipfs-http-client": "^49.0.4", + "libp2p": "file:../..", + "libp2p-bootstrap": "^0.12.2", + "libp2p-delegated-content-routing": "^0.9.0", + "libp2p-delegated-peer-routing": "^0.8.2", + "libp2p-gossipsub": "^0.8.0", + "libp2p-interfaces": "^0.8.4", + "libp2p-kad-dht": "^0.21.0", + "libp2p-mplex": "^0.10.2", + "libp2p-noise": "^2.0.5", + "libp2p-tcp": "^0.15.3", + "libp2p-websockets": "^0.15.3", + "peer-id": "^0.14.3" + }, + "scripts": { + "build": "npx tsc", + "test": "npm install && npx -p typescript tsc --noEmit" + } +} diff --git a/test/ts-use/src/main.ts b/test/ts-use/src/main.ts new file mode 100644 index 0000000000..4dc4efe4cb --- /dev/null +++ b/test/ts-use/src/main.ts @@ -0,0 +1,192 @@ +import Libp2p = require('libp2p') + +const TCP = require('libp2p-tcp') +const WEBSOCKETS = require('libp2p-websockets') +const NOISE = require('libp2p-noise') +const MPLEX = require('libp2p-mplex') +const Gossipsub = require('libp2p-gossipsub') +const DHT = require('libp2p-kad-dht') + +const { dnsaddrResolver } = require('multiaddr/src/resolvers') +const { publicAddressesFirst } = require('libp2p-utils/src/address-sort') + +const { SignaturePolicy } = require('libp2p-interfaces/src/pubsub/signature-policy') +const { FaultTolerance } = require('libp2p/src/transport-manager') +const filters = require('libp2p-websockets/src/filters') + +const Bootstrap = require('libp2p-bootstrap') +const LevelStore = require('datastore-level') + +const ipfsHttpClient = require('ipfs-http-client') +const DelegatedPeerRouter = require('libp2p-delegated-peer-routing') +const DelegatedContentRouter = require('libp2p-delegated-content-routing') +const PeerId = require('peer-id') + +// Known peers addresses +const bootstrapMultiaddrs = [ + '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', + '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN' +] +const transportKey = WEBSOCKETS.prototype[Symbol.toStringTag] + +async function main() { + // create a peerId + const peerId = await PeerId.create() + + const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({ + host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates + protocol: 'https', + port: 443 + })) + + const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({ + host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates + protocol: 'https', + port: 443 + })) + + const libp2p = await Libp2p.create({ + peerId, + addresses: { + listen: ['/ip4/127.0.0.1/tcp/8000', '/ip4/127.0.0.1/tcp/8001/ws'] + }, + modules: { + transport: [TCP, WEBSOCKETS], + streamMuxer: [MPLEX], + connEncryption: [NOISE], + peerDiscovery: [Bootstrap], + pubsub: Gossipsub, + dht: DHT, + contentRouting: [delegatedContentRouting], + peerRouting: [delegatedPeerRouting] + }, + peerRouting: { + refreshManager: { + enabled: true, + interval: 1000, + bootDelay: 11111 + } + }, + dialer: { + maxParallelDials: 100, + maxDialsPerPeer: 4, + dialTimeout: 30e3, + resolvers: { + dnsaddr: dnsaddrResolver + }, + addressSorter: publicAddressesFirst + }, + connectionManager: { + maxConnections: Infinity, + minConnections: 0, + pollInterval: 2000, + defaultPeerValue: 1, + maxData: Infinity, + maxSentData: Infinity, + maxReceivedData: Infinity, + maxEventLoopDelay: Infinity, + movingAverageInterval: 60000 + }, + transportManager: { + faultTolerance: FaultTolerance.NO_FATAL + }, + metrics: { + enabled: true, + computeThrottleMaxQueueSize: 1000, + computeThrottleTimeout: 2000, + movingAverageIntervals: [ + 60 * 1000, // 1 minute + 5 * 60 * 1000, // 5 minutes + 15 * 60 * 1000 // 15 minutes + ], + maxOldPeersRetention: 50 + }, + datastore: new LevelStore('path/to/store'), + peerStore: { + persistence: false, + threshold: 5 + }, + keychain: { + pass: 'notsafepassword123456789', + datastore: new LevelStore('path/to/store-keys') + }, + config: { + peerDiscovery: { + autoDial: true, + [Bootstrap.tag]: { + enabled: true, + list: bootstrapMultiaddrs // provide array of multiaddrs + } + }, + dht: { + enabled: true, + kBucketSize: 20, + randomWalk: { + enabled: true, // Allows to disable discovery (enabled by default) + interval: 300e3, + timeout: 10e3 + } + }, + nat: { + description: 'my-node', // set as the port mapping description on the router, defaults the current libp2p version and your peer id + enabled: true, // defaults to true + gateway: '192.168.1.1', // leave unset to auto-discover + externalIp: '80.1.1.1', // leave unset to auto-discover + ttl: 7200, // TTL for port mappings (min 20 minutes) + keepAlive: true, // Refresh port mapping after TTL expires + pmp: { + enabled: false, // defaults to false + } + }, + relay: { + enabled: true, // Allows you to dial and accept relayed connections. Does not make you a relay. + hop: { + enabled: true, // Allows you to be a relay for other peers + active: true // You will attempt to dial destination peers if you are not connected to them + }, + advertise: { + bootDelay: 15 * 60 * 1000, // Delay before HOP relay service is advertised on the network + enabled: true, // Allows you to disable the advertise of the Hop service + ttl: 30 * 60 * 1000 // Delay Between HOP relay service advertisements on the network + }, + autoRelay: { + enabled: true, // Allows you to bind to relays with HOP enabled for improving node dialability + maxListeners: 2 // Configure maximum number of HOP relays to use + } + }, + transport: { + [transportKey]: { + filter: filters.all + } + }, + pubsub: { // The pubsub options (and defaults) can be found in the pubsub router documentation + enabled: true, + emitSelf: false, // whether the node should emit to self on publish + globalSignaturePolicy: SignaturePolicy.StrictSign // message signing policy + } + } + }) + + libp2p.connectionManager.on('peer:connect', (connection) => { + console.log(`Connected to ${connection.remotePeer.toB58String()}`) + }) + + + + // Listen for new connections to peers + libp2p.connectionManager.on('peer:connect', (connection) => { + console.log(`Connected to ${connection.remotePeer.toB58String()}`) + }) + + // Listen for peers disconnecting + libp2p.connectionManager.on('peer:disconnect', (connection) => { + console.log(`Disconnected from ${connection.remotePeer.toB58String()}`) + }) + + + await libp2p.start() + console.log('started') + await libp2p.stop() +} + +main() diff --git a/test/ts-use/tsconfig.json b/test/ts-use/tsconfig.json new file mode 100644 index 0000000000..8cd47e1e86 --- /dev/null +++ b/test/ts-use/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "skipLibCheck": true + } +} \ No newline at end of file diff --git a/test/upgrading/upgrader.spec.js b/test/upgrading/upgrader.spec.js index 96df354952..b9f276a7ed 100644 --- a/test/upgrading/upgrader.spec.js +++ b/test/upgrading/upgrader.spec.js @@ -4,7 +4,7 @@ const { expect } = require('aegir/utils/chai') const sinon = require('sinon') const Muxer = require('libp2p-mplex') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const pipe = require('it-pipe') const { collect } = require('streaming-iterables') @@ -22,8 +22,8 @@ const { codes } = require('../../src/errors') const mockMultiaddrConnPair = require('../utils/mockMultiaddrConn') const Peers = require('../fixtures/peers') const addrs = [ - multiaddr('/ip4/127.0.0.1/tcp/0'), - multiaddr('/ip4/127.0.0.1/tcp/0') + new Multiaddr('/ip4/127.0.0.1/tcp/0'), + new Multiaddr('/ip4/127.0.0.1/tcp/0') ] describe('Upgrader', () => { diff --git a/test/utils/creators/peer.js b/test/utils/creators/peer.js index 2c77cb63a0..c9f213f44e 100644 --- a/test/utils/creators/peer.js +++ b/test/utils/creators/peer.js @@ -2,14 +2,14 @@ const pTimes = require('p-times') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const PeerId = require('peer-id') const Libp2p = require('../../../src') const Peers = require('../../fixtures/peers') const defaultOptions = require('../base-options.browser') -const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0') +const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0') /** * Create libp2p nodes. diff --git a/test/utils/mockConnection.js b/test/utils/mockConnection.js index b85c036ebb..66c659fb16 100644 --- a/test/utils/mockConnection.js +++ b/test/utils/mockConnection.js @@ -2,7 +2,7 @@ const pipe = require('it-pipe') const { Connection } = require('libp2p-interfaces/src/connection') -const multiaddr = require('multiaddr') +const { Multiaddr } = require('multiaddr') const Muxer = require('libp2p-mplex') const Multistream = require('multistream-select') const pair = require('it-pair') @@ -13,8 +13,8 @@ const mockMultiaddrConnPair = require('./mockMultiaddrConn') const peerUtils = require('./creators/peer') module.exports = async (properties = {}) => { - const localAddr = multiaddr('/ip4/127.0.0.1/tcp/8080') - const remoteAddr = multiaddr('/ip4/127.0.0.1/tcp/8081') + const localAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8080') + const remoteAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8081') const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 }) const openStreams = [] diff --git a/tsconfig.json b/tsconfig.json index 5b9a618c43..d9083a6a34 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,5 +5,14 @@ }, "include": [ "src" + ], + "exclude": [ + "src/circuit/protocol/index.js", // exclude generated file + "src/identify/message.js", // exclude generated file + "src/insecure/proto.js", // exclude generated file + "src/peer-store/persistent/pb/address-book.js", // exclude generated file + "src/peer-store/persistent/pb/proto-book.js", // exclude generated file + "src/record/peer-record/peer-record.js", // exclude generated file + "src/record/envelope/envelope.js" // exclude generated file ] } \ No newline at end of file