Compare commits

..

33 Commits

Author SHA1 Message Date
Pavel Murygin
cacef402ee fix types 2021-04-09 18:55:39 +03:00
Pavel Murygin
5bfad1908b bump dependencies 2021-04-09 18:12:25 +03:00
Vasco Santos
4326d714d9 chore: release version v0.3.0 2021-04-08 11:55:53 +02:00
Vasco Santos
c206807805 chore: update contributors 2021-04-08 11:55:52 +02:00
Vasco Santos
e0552b5b6b
feat: add types (#16) 2021-04-08 11:52:55 +02:00
Vasco Santos
28869e6cda chore: release version v0.2.3 2020-11-30 11:09:49 +01:00
Vasco Santos
6e7c7c64ce chore: update contributors 2020-11-30 11:09:49 +01:00
Vasco Santos
d16d9fe0a6
chore: update private-ip (#15) 2020-11-30 10:35:45 +01:00
Vasco Santos
584af9d7c0 chore: release version v0.2.2 2020-11-16 15:06:09 +01:00
Vasco Santos
edbd46e25d chore: update contributors 2020-11-16 15:06:09 +01:00
Vasco Santos
cb5e71644b
feat: address sorter (#13) 2020-11-16 15:03:20 +01:00
Vasco Santos
301c63a91e chore: release version v0.2.1 2020-10-08 09:33:45 +02:00
Vasco Santos
684366b8ae chore: update contributors 2020-10-08 09:33:44 +02:00
Vasco Santos
b38bf34729 chore: create API doc 2020-10-08 09:33:00 +02:00
Vasco Santos
b91a241d07 chore: apply suggestions from code review
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-10-08 09:33:00 +02:00
Vasco Santos
645b483cb4 chore: complete docs 2020-10-08 09:33:00 +02:00
Vasco Santos
d7fa562d91
feat: is multiaddr private and loopback (#10) 2020-10-07 17:02:08 +02:00
Jacob Heun
03e272cd24
chore: release version v0.2.0 2020-08-07 17:43:27 +02:00
Jacob Heun
c564ea01f9
chore: update contributors 2020-08-07 17:43:26 +02:00
Alex Potsides
a2ea68f319
chore: update deps (#9)
* chore: update deps

Pulls in the latest multiaddrs that replaces node Buffers with
Uint8Arrays

BREAKING CHANGES:

- The multiaddr dep of this module uses Uint8Arrays and may not be
  compatible with previous versions

* chore: remove gh url
2020-08-07 17:40:19 +02:00
Vasco Santos
46d17ca142 chore: release version v0.1.3 2020-07-15 12:29:21 +02:00
Vasco Santos
141aac3a33 chore: update contributors 2020-07-15 12:29:21 +02:00
Vasco Santos
2f81fc4914 chore: apply suggestions from code review
Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-07-15 12:28:37 +02:00
Vasco Santos
673da42470 chore: update deps 2020-07-15 12:28:37 +02:00
Vasco Santos
80668fff1a feat: arrayEquals for non primitive types with equals function 2020-07-15 12:28:37 +02:00
dependabot-preview[bot]
0e7fc344ec
chore(deps-dev): bump aegir from 21.10.2 to 22.0.0 (#7)
Bumps [aegir](https://github.com/ipfs/aegir) from 21.10.2 to 22.0.0.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v21.10.2...v22.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-27 19:52:33 +02:00
dependabot-preview[bot]
c8c9c76ebf
chore(deps-dev): bump aegir from 20.6.1 to 21.0.2 (#6)
Bumps [aegir](https://github.com/ipfs/aegir) from 20.6.1 to 21.0.2.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v20.6.1...v21.0.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-17 21:18:34 +00:00
Vasco Santos
1491fabc96 chore: release version v0.1.2 2020-02-15 08:44:29 +00:00
Vasco Santos
e7d0879474 chore: update contributors 2020-02-15 08:44:29 +00:00
Vasco Santos
622063163d
feat: stream to multiaddr connection converter (#2) 2020-02-15 09:43:12 +01:00
Vasco Santos
b67dcbe74a chore: release version v0.1.1 2020-02-13 16:22:57 +01:00
Vasco Santos
523f80ea6c chore: update contributors 2020-02-13 16:22:57 +01:00
Vasco Santos
30c236d92f
chore: add meaningful errors for ip:port to multiaddr (#4)
* chore: add meaningful errors for ip:port to multiaddr

* chore: address review
2020-02-13 16:22:12 +01:00
19 changed files with 943 additions and 80 deletions

74
.github/workflows/main.yml vendored Normal file
View File

@ -0,0 +1,74 @@
name: ci
on:
push:
branches:
- master
pull_request:
branches:
- master
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
- run: npx aegir dep-check
- uses: ipfs/aegir/actions/bundle-size@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
test-node:
needs: check
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
node: [14, 15]
fail-fast: true
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npx nyc --reporter=lcov aegir test -t node -- --bail
- uses: codecov/codecov-action@v1
test-chrome:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- 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: npm install
- run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless
test-webkit:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: microsoft/playwright-github-action@v1
- run: npm install
- run: npx aegir test -t browser -t webworker --bail -- --browser webkit
test-electron-main:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npx xvfb-maybe aegir test -t electron-main --bail
test-electron-renderer:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npx xvfb-maybe aegir test -t electron-renderer --bail

View File

@ -1,52 +0,0 @@
language: node_js
cache: npm
stages:
- check
- test
- cov
node_js:
- '10'
- '12'
os:
- linux
- osx
script: npx nyc -s npm run test:node -- --bail
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
jobs:
include:
- os: windows
filter_secrets: false
cache: false
- stage: check
script:
- npx aegir commitlint --travis
- npx aegir dep-check
- npm run lint
- stage: test
name: chrome
addons:
chrome: stable
script: npx aegir test -t browser -t webworker
- stage: test
name: firefox
addons:
firefox: latest
script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless
- stage: test
name: electron
services:
- xvfb
script:
- npm run test:electron
- npm run test:electron-renderer
notifications:
email: false

209
API.md Normal file
View File

@ -0,0 +1,209 @@
# API
* [addressSort.publicAddressesFirst(addresses)](#addresssortpublicaddressesfirstaddresses)
* [Parameters](#parameters)
* [Returns](#returns)
* [Example](#example)
* [arrayEquals(a, b)](#arrayequalsa-b)
* [Parameters](#parameters)
* [Returns](#returns)
* [Example](#example)
* [multiaddr .isLoopback(ma)](#multiaddr-isloopbackma)
* [Parameters](#parameters-1)
* [Returns](#returns-1)
* [Example](#example-1)
* [multiaddr .isPrivate(ma)](#multiaddr-isprivatema)
* [Parameters](#parameters-2)
* [Returns](#returns-2)
* [Example](#example-2)
* [ipPortToMultiaddr(ip, port)](#ipporttomultiaddrip-port)
* [Parameters](#parameters-3)
* [Returns](#returns-3)
* [Example](#example-3)
* [streamToMaConnection(streamProperties, options)](#streamtomaconnectionstreamproperties-options)
* [Parameters](#parameters-4)
* [Returns](#returns-4)
* [Example](#example-4)
## addressSort.publicAddressesFirst(addresses)
Sort given addresses by putting public addresses first. In case of equality, a certified address will come first.
### Parameters
| Name | Type | Description |
|------|------|-------------|
| addresses | `Array<Address>` | Array of AddressBook addresses |
### Returns
| Type | Description |
|------|-------------|
| `Array<Address>` | returns array of sorted addresses |
### Example
```js
const multiaddr = require('multiaddr')
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
const addresses = [
{
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4000'),
isCertified: false
},
{
multiaddr: multiaddr('/ip4/30.0.0.1/tcp/4000'),
isCertified: false
}
]
const sortedAddresses = publicAddressesFirst(addresses)
```
## arrayEquals(a, b)
Verify if two arrays of non primitive types with the "equals" function are equal.
Compatible with multiaddr, peer-id and others.
### Parameters
| Name | Type | Description |
|------|------|-------------|
| a | `Array<*>` | First array to verify |
| b | `Array<*>` | Second array to verify |
### Returns
| Type | Description |
|------|-------------|
| `boolean` | returns true if arrays are equal, false otherwise |
### Example
```js
const PeerId = require('peer-id')
const arrayEquals = require('libp2p-utils/src/array-equals')
const peerId1 = await PeerId.create()
const peerId2 = await PeerId.create()
const equals = arrayEquals([peerId1], [peerId2])
```
## multiaddr `.isLoopback(ma)`
Check if a given multiaddr is a loopback address.
### Parameters
| Name | Type | Description |
|------|------|-------------|
| ma | `Multiaddr` | multiaddr to verify |
### Returns
| Type | Description |
|------|-------------|
| `boolean` | returns true if multiaddr is a loopback address, false otherwise |
### Example
```js
const multiaddr = require('multiaddr')
const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback')
const ma = multiaddr('/ip4/127.0.0.1/tcp/1000')
isMultiaddrLoopbackAddrs = isLoopback(ma)
```
## multiaddr `.isPrivate(ma)`
Check if a given multiaddr has a private address.
### Parameters
| Name | Type | Description |
|------|------|-------------|
| ma | `Multiaddr` | multiaddr to verify |
### Returns
| Type | Description |
|------|-------------|
| `boolean` | returns true if multiaddr is a private address, false otherwise |
### Example
```js
const multiaddr = require('multiaddr')
const isPrivate = require('libp2p-utils/src/multiaddr/is-private')
const ma = multiaddr('/ip4/10.0.0.1/tcp/1000')
isMultiaddrPrivateAddrs = isPrivate(ma)
```
## ipPortToMultiaddr(ip, port)
Transform an IP, Port pair into a multiaddr with tcp transport.
### Parameters
| Name | Type | Description |
|------|------|-------------|
| ip | `string` | ip for multiaddr |
| port | `number|string` | port for multiaddr |
### Returns
| Type | Description |
|------|-------------|
| `Multiaddr` | returns created multiaddr |
### Example
```js
const ipPortPairToMultiaddr = require('libp2p-utils/src/multiaddr/ip-port-to-multiaddr')
const ip = '127.0.0.1'
const port = '9090'
const ma = ipPortPairToMultiaddr(ma)
```
## streamToMaConnection(streamProperties, options)
Convert a duplex stream into a [MultiaddrConnection](https://github.com/libp2p/interface-transport#multiaddrconnection).
### Parameters
| Name | Type | Description |
|------|------|-------------|
| streamProperties | `object` | duplex stream properties |
| streamProperties.stream | [`DuplexStream`](https://github.com/libp2p/js-libp2p/blob/master/doc/STREAMING_ITERABLES.md#duplex) | duplex stream |
| streamProperties.remoteAddr | `Multiaddr` | stream remote address |
| streamProperties.localAddr | `Multiaddr` | stream local address |
| [options] | `object` | options |
| [options.signal] | `AbortSignal` | abort signal |
### Returns
| Type | Description |
|------|-------------|
| `Connection` | returns a multiaddr [Connection](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/connection) |
### Example
```js
const streamToMaConnection = require('libp2p-utils/src/stream-to-ma-conn')
const stream = {
sink: async source => {/* ... */},
source: { [Symbol.asyncIterator] () {/* ... */} }
}
const conn = streamToMaConnection({
stream,
remoteAddr: /* ... */
localAddr; /* ... */
})
```

View File

@ -1,3 +1,93 @@
# [0.3.0](https://github.com/libp2p/js-libp2p-utils/compare/v0.2.3...v0.3.0) (2021-04-08)
### Features
* add types ([#16](https://github.com/libp2p/js-libp2p-utils/issues/16)) ([e0552b5](https://github.com/libp2p/js-libp2p-utils/commit/e0552b5b6b1d912a8f6f1e39b1a4b70fca91f547))
<a name="0.2.3"></a>
## [0.2.3](https://github.com/libp2p/js-libp2p-utils/compare/v0.2.2...v0.2.3) (2020-11-30)
<a name="0.2.2"></a>
## [0.2.2](https://github.com/libp2p/js-libp2p-utils/compare/v0.2.1...v0.2.2) (2020-11-16)
### Features
* address sorter ([#13](https://github.com/libp2p/js-libp2p-utils/issues/13)) ([cb5e716](https://github.com/libp2p/js-libp2p-utils/commit/cb5e716))
<a name="0.2.1"></a>
## [0.2.1](https://github.com/libp2p/js-libp2p-utils/compare/v0.1.3...v0.2.1) (2020-10-08)
### Chores
* update deps ([#9](https://github.com/libp2p/js-libp2p-utils/issues/9)) ([a2ea68f](https://github.com/libp2p/js-libp2p-utils/commit/a2ea68f))
### Features
* is multiaddr private and loopback ([#10](https://github.com/libp2p/js-libp2p-utils/issues/10)) ([d7fa562](https://github.com/libp2p/js-libp2p-utils/commit/d7fa562))
### BREAKING CHANGES
* - The multiaddr dep of this module uses Uint8Arrays and may not be
compatible with previous versions
* chore: remove gh url
<a name="0.2.0"></a>
# [0.2.0](https://github.com/libp2p/js-libp2p-utils/compare/v0.1.3...v0.2.0) (2020-08-07)
### Chores
* update deps ([#9](https://github.com/libp2p/js-libp2p-utils/issues/9)) ([a2ea68f](https://github.com/libp2p/js-libp2p-utils/commit/a2ea68f))
### BREAKING CHANGES
* - The multiaddr dep of this module uses Uint8Arrays and may not be
compatible with previous versions
* chore: remove gh url
<a name="0.1.3"></a>
## [0.1.3](https://github.com/libp2p/js-libp2p-utils/compare/v0.1.2...v0.1.3) (2020-07-15)
### Features
* arrayEquals for non primitive types with equals function ([80668ff](https://github.com/libp2p/js-libp2p-utils/commit/80668ff))
<a name="0.1.2"></a>
## [0.1.2](https://github.com/libp2p/js-libp2p-utils/compare/v0.1.1...v0.1.2) (2020-02-15)
### Features
* stream to multiaddr connection converter ([#2](https://github.com/libp2p/js-libp2p-utils/issues/2)) ([6220631](https://github.com/libp2p/js-libp2p-utils/commit/6220631))
<a name="0.1.1"></a>
## [0.1.1](https://github.com/libp2p/js-libp2p-utils/compare/v0.1.0...v0.1.1) (2020-02-13)
<a name="0.1.0"></a>
# 0.1.0 (2019-09-23)

View File

@ -38,6 +38,8 @@ const ipAndPortToMultiaddr = require('libp2p-utils/src/ip-port-to-multiaddr')
const ma = ipAndPortToMultiaddr('127.0.0.1', 9000)
```
You can check the [API docs](./API.md).
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/libp2p/js-libp2p-utils/issues).

View File

@ -1,10 +1,24 @@
{
"name": "libp2p-utils",
"version": "0.1.0",
"version": "0.3.0",
"description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem",
"leadMaintainer": "Vasco Santos <santos.vasco10@gmail.com>",
"main": "src/index.js",
"types": "dist/src/index.d.ts",
"typesVersions": {
"*": {
"src/*": [
"dist/src/*",
"dist/src/*/index"
]
}
},
"files": [
"src",
"dist"
],
"scripts": {
"prepare": "aegir build --no-bundle",
"test": "aegir test",
"test:browser": "aegir test -t browser",
"test:node": "aegir test -t node",
@ -29,15 +43,26 @@
},
"homepage": "https://github.com/libp2p/js-libp2p-utils#readme",
"devDependencies": {
"aegir": "^20.3.1",
"chai": "^4.2.0",
"dirty-chai": "^2.0.1"
"@types/debug": "^4.1.5",
"aegir": "^32.1.0",
"it-pair": "^1.0.0",
"it-pipe": "^1.1.0",
"libp2p-interfaces": "fluencelabs/js-libp2p-interfaces",
"streaming-iterables": "^5.0.3",
"util": "^0.12.3"
},
"dependencies": {
"ip-address": "^6.1.0",
"multiaddr": "^7.1.0"
"abortable-iterator": "^3.0.0",
"debug": "^4.3.0",
"err-code": "^3.0.1",
"ip-address": "^7.1.0",
"is-loopback-addr": "^1.0.0",
"multiaddr": "^9.0.1",
"private-ip": "^2.1.1"
},
"contributors": [
"Vasco Santos <vasco.santos@moxy.studio>"
"Vasco Santos <vasco.santos@moxy.studio>",
"Jacob Heun <jacobheun@gmail.com>",
"Alex Potsides <alex@achingbrain.net>"
]
}

54
src/address-sort.js Normal file
View File

@ -0,0 +1,54 @@
'use strict'
const isPrivate = require('./multiaddr/is-private')
/**
* @typedef {import('multiaddr').Multiaddr} Multiaddr
*/
/**
* @typedef {Object} Address
* @property {Multiaddr} multiaddr peer multiaddr.
* @property {boolean} isCertified obtained from a signed peer record.
*/
/**
* Compare function for array.sort().
* This sort aims to move the private adresses to the end of the array.
* In case of equality, a certified address will come first.
*
* @param {Address} a
* @param {Address} b
* @returns {number}
*/
function addressesPublicFirstCompareFunction (a, b) {
const isAPrivate = isPrivate(a.multiaddr)
const isBPrivate = isPrivate(b.multiaddr)
if (isAPrivate && !isBPrivate) {
return 1
} else if (!isAPrivate && isBPrivate) {
return -1
}
// Check certified?
if (a.isCertified && !b.isCertified) {
return -1
} else if (!a.isCertified && b.isCertified) {
return 1
}
return 0
}
/**
* Sort given addresses by putting public addresses first.
* In case of equality, a certified address will come first.
*
* @param {Array<Address>} addresses
* @returns {Array<Address>}
*/
function publicAddressesFirst (addresses) {
return [...addresses].sort(addressesPublicFirstCompareFunction)
}
module.exports.publicAddressesFirst = publicAddressesFirst

15
src/array-equals.js Normal file
View File

@ -0,0 +1,15 @@
'use strict'
/**
* Verify if two arrays of non primitive types with the "equals" function are equal.
* Compatible with multiaddr, peer-id and others.
*
* @param {Array<*>} a
* @param {Array<*>} b
* @returns {boolean}
*/
function arrayEquals (a, b) {
return a.length === b.length && b.sort() && a.sort().every((item, index) => b[index].equals(item))
}
module.exports = arrayEquals

View File

@ -1,30 +1,57 @@
'use strict'
const debug = require('debug')
const log = Object.assign(debug('libp2p:ip-port-to-multiaddr'), {
error: debug('libp2p:ip-port-to-multiaddr:err')
})
const multiaddr = require('multiaddr')
const errCode = require('err-code')
const { Address4, Address6 } = require('ip-address')
module.exports = (ip, port) => {
const errors = {
ERR_INVALID_IP_PARAMETER: 'ERR_INVALID_IP_PARAMETER',
ERR_INVALID_PORT_PARAMETER: 'ERR_INVALID_PORT_PARAMETER',
ERR_INVALID_IP: 'ERR_INVALID_IP'
}
/**
* Transform an IP, Port pair into a multiaddr
*
* @param {string} ip
* @param {number|string} port
*/
function ipPortToMultiaddr (ip, port) {
if (typeof ip !== 'string') {
throw new Error('invalid ip')
throw errCode(new Error(`invalid ip provided: ${ip}`), errors.ERR_INVALID_IP_PARAMETER)
}
port = parseInt(port)
if (typeof port === 'string') {
port = parseInt(port)
}
if (isNaN(port)) {
throw new Error('invalid port')
throw errCode(new Error(`invalid port provided: ${port}`), errors.ERR_INVALID_PORT_PARAMETER)
}
if (new Address4(ip).isValid()) {
return multiaddr(`/ip4/${ip}/tcp/${port}`)
}
try {
// Test valid IPv4
new Address4(ip) // eslint-disable-line no-new
return new multiaddr.Multiaddr(`/ip4/${ip}/tcp/${port}`)
} catch {}
const ip6 = new Address6(ip)
if (ip6.isValid()) {
try {
// Test valid IPv6
const ip6 = new Address6(ip)
return ip6.is4()
? multiaddr(`/ip4/${ip6.to4().correctForm()}/tcp/${port}`)
: multiaddr(`/ip6/${ip}/tcp/${port}`)
? new multiaddr.Multiaddr(`/ip4/${ip6.to4().correctForm()}/tcp/${port}`)
: new multiaddr.Multiaddr(`/ip6/${ip}/tcp/${port}`)
} catch (err) {
const errMsg = `invalid ip:port for creating a multiaddr: ${ip}:${port}`
log.error(errMsg)
throw errCode(new Error(errMsg), errors.ERR_INVALID_IP)
}
throw new Error('invalid ip')
}
module.exports = ipPortToMultiaddr
module.exports.Errors = errors

View File

@ -0,0 +1,22 @@
'use strict'
// @ts-ignore is-loopback-addr does not publish types
const isLoopbackAddr = require('is-loopback-addr')
/**
* @typedef {import('multiaddr').Multiaddr} Multiaddr
*/
/**
* Check if a given multiaddr is a loopback address.
*
* @param {Multiaddr} ma
* @returns {boolean}
*/
function isLoopback (ma) {
const { address } = ma.nodeAddress()
return isLoopbackAddr(address)
}
module.exports = isLoopback

View File

@ -0,0 +1,22 @@
'use strict'
// @ts-ignore private-ip does not publish types
const isIpPrivate = require('private-ip')
/**
* @typedef {import('multiaddr').Multiaddr} Multiaddr
*/
/**
* Check if a given multiaddr has a private address.
*
* @param {Multiaddr} ma
* @returns {boolean}
*/
function isPrivate (ma) {
const { address } = ma.nodeAddress()
return isIpPrivate(address)
}
module.exports = isPrivate

76
src/stream-to-ma-conn.js Normal file
View File

@ -0,0 +1,76 @@
'use strict'
const { source: abortable } = require('abortable-iterator')
const debug = require('debug')
const log = debug('libp2p:stream:converter')
/**
* @typedef {import('multiaddr').Multiaddr} Multiaddr
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
*
* @typedef {Object} Timeline
* @property {number} open - connection opening timestamp.
* @property {number} [upgraded] - connection upgraded timestamp.
* @property {number} [close]
*/
/**
* Convert a duplex iterable into a MultiaddrConnection.
* https://github.com/libp2p/interface-transport#multiaddrconnection
*
* @param {object} streamProperties
* @param {MuxedStream} streamProperties.stream
* @param {Multiaddr} streamProperties.remoteAddr
* @param {Multiaddr} streamProperties.localAddr
* @param {object} [options]
* @param {AbortSignal} [options.signal]
* @returns {import('libp2p-interfaces/src/transport/types').MultiaddrConnection}
*/
function streamToMaConnection ({ stream, remoteAddr, localAddr }, options = {}) {
const { sink, source } = stream
const maConn = {
/**
* @param {Uint8Array} source
*/
async sink (source) {
if (options.signal) {
// @ts-ignore ts infers source template will be a number
source = abortable(source, options.signal)
}
try {
await sink(source)
} catch (err) {
// If aborted we can safely ignore
if (err.type !== 'aborted') {
// If the source errored the socket will already have been destroyed by
// toIterable.duplex(). If the socket errored it will already be
// destroyed. There's nothing to do here except log the error & return.
log(err)
}
}
close()
},
source: options.signal ? abortable(source, options.signal) : source,
conn: stream,
localAddr,
remoteAddr,
/** @type {Timeline} */
timeline: { open: Date.now(), close: undefined },
close () {
sink(new Uint8Array(0))
return close()
}
}
function close () {
if (!maConn.timeline.close) {
maConn.timeline.close = Date.now()
}
return Promise.resolve()
}
return maConn
}
module.exports = streamToMaConnection

53
test/address-sort.spec.js Normal file
View File

@ -0,0 +1,53 @@
'use strict'
/* eslint-env mocha */
const { expect } = require('aegir/utils/chai')
const multiaddr = require('multiaddr')
const { publicAddressesFirst } = require('../src/address-sort')
describe('address-sort', () => {
it('should sort public addresses first', () => {
const addresses = [
{
multiaddr: new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/4000'),
isCertified: false
},
{
multiaddr: new multiaddr.Multiaddr('/ip4/30.0.0.1/tcp/4000'),
isCertified: false
},
{
multiaddr: new multiaddr.Multiaddr('/ip4/31.0.0.1/tcp/4000'),
isCertified: false
}
]
const sortedAddresses = publicAddressesFirst(addresses)
expect(sortedAddresses[0].multiaddr.equals(new multiaddr.Multiaddr('/ip4/30.0.0.1/tcp/4000'))).to.eql(true)
expect(sortedAddresses[1].multiaddr.equals(new multiaddr.Multiaddr('/ip4/31.0.0.1/tcp/4000'))).to.eql(true)
expect(sortedAddresses[2].multiaddr.equals(new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/4000'))).to.eql(true)
})
it('should sort public certified addresses first', () => {
const addresses = [
{
multiaddr: new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/4000'),
isCertified: false
},
{
multiaddr: new multiaddr.Multiaddr('/ip4/30.0.0.1/tcp/4000'),
isCertified: false
},
{
multiaddr: new multiaddr.Multiaddr('/ip4/31.0.0.1/tcp/4000'),
isCertified: true
}
]
const sortedAddresses = publicAddressesFirst(addresses)
expect(sortedAddresses[0].multiaddr.equals(new multiaddr.Multiaddr('/ip4/31.0.0.1/tcp/4000'))).to.eql(true)
expect(sortedAddresses[1].multiaddr.equals(new multiaddr.Multiaddr('/ip4/30.0.0.1/tcp/4000'))).to.eql(true)
expect(sortedAddresses[2].multiaddr.equals(new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/4000'))).to.eql(true)
})
})

72
test/array-equals.spec.js Normal file
View File

@ -0,0 +1,72 @@
/* eslint-env mocha */
'use strict'
const { expect } = require('aegir/utils/chai')
const multiaddr = require('multiaddr')
const arrayEquals = require('../src/array-equals')
describe('non primitive array equals', () => {
it('returns true if two arrays of multiaddrs are equal', () => {
const a = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
const b = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
expect(arrayEquals(a, b)).to.eql(true)
})
it('returns true if two arrays of multiaddrs have the same content but different orders', () => {
const a = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
const b = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
expect(arrayEquals(a, b)).to.eql(true)
})
it('returns false if two arrays of multiaddrs are different', () => {
const a = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
const b = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8001'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
expect(arrayEquals(a, b)).to.eql(false)
})
it('returns false if two arrays of multiaddrs are partially equal, but different lengths', () => {
const a = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/3000/ws'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
const b = [
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/8000'),
new multiaddr.Multiaddr('/dns4/test.libp2p.io')
]
expect(arrayEquals(a, b)).to.eql(false)
})
})

View File

@ -1,11 +1,9 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
const { expect } = require('aegir/utils/chai')
const toMultiaddr = require('../src/ip-port-to-multiaddr')
const { Errors } = require('../src/ip-port-to-multiaddr')
describe('IP and port to Multiaddr', () => {
it('creates multiaddr from valid IPv4 IP and port', () => {
@ -33,18 +31,18 @@ describe('IP and port to Multiaddr', () => {
})
it('throws for missing IP address', () => {
expect(() => toMultiaddr()).to.throw('invalid ip')
expect(() => toMultiaddr()).to.throw('invalid ip provided').with.property('code', Errors.ERR_INVALID_IP_PARAMETER)
})
it('throws for invalid IP address', () => {
const ip = 'aewmrn4awoew'
const port = '234'
expect(() => toMultiaddr(ip, port)).to.throw('invalid ip')
expect(() => toMultiaddr(ip, port)).to.throw('invalid ip:port for creating a multiaddr').with.property('code', Errors.ERR_INVALID_IP)
})
it('throws for invalid port', () => {
const ip = '127.0.0.1'
const port = 'garbage'
expect(() => toMultiaddr(ip, port)).to.throw('invalid port')
expect(() => toMultiaddr(ip, port)).to.throw('invalid port provided').with.property('code', Errors.ERR_INVALID_PORT_PARAMETER)
})
})

View File

@ -0,0 +1,57 @@
/* eslint-env mocha */
'use strict'
const { expect } = require('aegir/utils/chai')
const multiaddr = require('multiaddr')
const isLoopback = require('../../src/multiaddr/is-loopback')
describe('multiaddr isLoopback', () => {
it('identifies loopback ip4 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/127.0.1.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/127.1.1.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/127.255.255.255/tcp/1000')
].forEach(ma => {
expect(isLoopback(ma)).to.eql(true)
})
})
it('identifies non loopback ip4 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip4/101.0.26.90/tcp/1000'),
new multiaddr.Multiaddr('/ip4/10.0.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/192.168.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/172.16.0.1/tcp/1000')
].forEach(ma => {
expect(isLoopback(ma)).to.eql(false)
})
})
it('identifies loopback ip6 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip6/::1/tcp/1000')
].forEach(ma => {
expect(isLoopback(ma)).to.eql(true)
})
})
it('identifies non loopback ip6 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/1000'),
new multiaddr.Multiaddr('/ip6/::/tcp/1000')
].forEach(ma => {
expect(isLoopback(ma)).to.eql(false)
})
})
it('identifies other multiaddrs as not loopback addresses', () => {
[
new multiaddr.Multiaddr('/dns4/wss0.bootstrap.libp2p.io/tcp/443'),
new multiaddr.Multiaddr('/dns6/wss0.bootstrap.libp2p.io/tcp/443')
].forEach(ma => {
expect(isLoopback(ma)).to.eql(false)
})
})
})

View File

@ -0,0 +1,58 @@
/* eslint-env mocha */
'use strict'
const { expect } = require('aegir/utils/chai')
const multiaddr = require('multiaddr')
const isPrivate = require('../../src/multiaddr/is-private')
describe('multiaddr isPrivate', () => {
it('identifies private ip4 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip4/127.0.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/10.0.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/192.168.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/172.16.0.1/tcp/1000')
].forEach(ma => {
expect(isPrivate(ma)).to.eql(true)
})
})
it('identifies public ip4 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip4/101.0.26.90/tcp/1000'),
new multiaddr.Multiaddr('/ip4/40.1.20.9/tcp/1000'),
new multiaddr.Multiaddr('/ip4/92.168.0.1/tcp/1000'),
new multiaddr.Multiaddr('/ip4/2.16.0.1/tcp/1000')
].forEach(ma => {
expect(isPrivate(ma)).to.eql(false)
})
})
it('identifies private ip6 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip6/fd52:8342:fc46:6c91:3ac9:86ff:fe31:7095/tcp/1000'),
new multiaddr.Multiaddr('/ip6/fd52:8342:fc46:6c91:3ac9:86ff:fe31:1/tcp/1000')
].forEach(ma => {
expect(isPrivate(ma)).to.eql(true)
})
})
it('identifies public ip6 multiaddrs', () => {
[
new multiaddr.Multiaddr('/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/1000'),
new multiaddr.Multiaddr('/ip6/2000:8a0:7ac5:4201:3ac9:86ff:fe31:7095/tcp/1000')
].forEach(ma => {
expect(isPrivate(ma)).to.eql(false)
})
})
it('identifies other multiaddrs as not private addresses', () => {
[
new multiaddr.Multiaddr('/dns4/wss0.bootstrap.libp2p.io/tcp/443'),
new multiaddr.Multiaddr('/dns6/wss0.bootstrap.libp2p.io/tcp/443')
].forEach(ma => {
expect(isPrivate(ma)).to.eql(false)
})
})
})

View File

@ -0,0 +1,52 @@
/* eslint-env mocha */
'use strict'
const { expect } = require('aegir/utils/chai')
const pair = require('it-pair')
const pipe = require('it-pipe')
const { collect } = require('streaming-iterables')
const multiaddr = require('multiaddr')
const streamToMaConn = require('../src/stream-to-ma-conn')
describe('Convert stream into a multiaddr connection', () => {
it('converts a stream and adds the provided metadata', () => {
const stream = pair()
const localAddr = new multiaddr.Multiaddr('/ip4/101.45.75.219/tcp/6000')
const remoteAddr = new multiaddr.Multiaddr('/ip4/100.46.74.201/tcp/6002')
const maConn = streamToMaConn({
stream,
localAddr,
remoteAddr
})
expect(maConn).to.exist()
expect(maConn.sink).to.exist()
expect(maConn.source).to.exist()
expect(maConn.localAddr).to.eql(localAddr)
expect(maConn.remoteAddr).to.eql(remoteAddr)
expect(maConn.timeline).to.exist()
expect(maConn.timeline.open).to.exist()
expect(maConn.timeline.close).to.not.exist()
maConn.close()
expect(maConn.timeline.close).to.exist()
})
it('can stream data over the multiaddr connection', async () => {
const stream = pair()
const maConn = streamToMaConn({ stream })
const data = 'hey'
const streamData = await pipe(
[data],
maConn,
collect
)
expect(streamData).to.eql([data])
// underlying stream end closes the connection
expect(maConn.timeline.close).to.exist()
})
})

9
tsconfig.json Normal file
View File

@ -0,0 +1,9 @@
{
"extends": "aegir/src/config/tsconfig.aegir.json",
"compilerOptions": {
"outDir": "dist"
},
"include": [
"src"
]
}