├── .cspell.json ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── open_an_issue.md │ └── release.md ├── dependabot.yml ├── dictionary.txt ├── pull_request_template.md └── workflows │ ├── automerge.yml │ ├── examples.yml │ ├── generated-pr.yml │ ├── main.yml │ ├── semantic-pull-request.yml │ └── stale.yml ├── .gitignore ├── .release-please-manifest.json ├── .release-please.json ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── ROADMAP.md ├── SECURITY.md ├── doc ├── API.md ├── ARCHITECTURE.md ├── CONFIGURATION.md ├── GETTING_STARTED.md ├── LIMITS.md ├── METRICS.md ├── PEER_DISCOVERY.md ├── SERVICES.md ├── STREAMING_ITERABLES.md ├── migrations │ ├── MIGRATION_TEMPLATE.md │ ├── v0.26-v0.27.md │ ├── v0.27-v0.28.md │ ├── v0.28-v0.29.md │ ├── v0.29-v0.30.md │ ├── v0.30-v0.31.md │ ├── v0.31-v0.32.md │ ├── v0.32-v0.33.md │ ├── v0.36-v0.37.md │ ├── v0.37-v0.38.md │ ├── v0.38-v0.39.md │ ├── v0.39-v0.40.md │ ├── v0.40-v0.41.md │ ├── v0.41-v0.42.md │ ├── v0.42-v0.43.md │ ├── v0.43-v0.44.md │ ├── v0.44-v0.45.md │ ├── v0.45-v0.46.md │ ├── v0.46-v1.0.0.md │ └── v1.0.0-v2.0.0.md ├── package.json ├── production │ ├── DELEGATE_NODES.md │ └── README.md └── tsconfig.json ├── funding.json ├── img ├── js-libp2p-ipfs-browser.png ├── js-libp2p-ipfs.png ├── js-libp2p.png ├── libp2p-arch.png ├── libp2p-logos.sketch └── libp2p.png ├── interop ├── .aegir.js ├── BrowserDockerfile ├── Dockerfile ├── Makefile ├── README.md ├── chromium-version.json ├── firefox-version.json ├── node-version.json ├── package.json ├── src │ └── index.ts ├── test │ ├── dialer.spec.ts │ ├── fixtures │ │ ├── get-libp2p.ts │ │ ├── redis-proxy.ts │ │ └── relay.ts │ └── listener.spec.ts ├── tsconfig.json └── webkit-version.json ├── package.json ├── packages ├── config │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── load-private-key.ts │ ├── test │ │ └── load-private-key.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── connection-encrypter-plaintext │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── pb │ │ │ ├── proto.proto │ │ │ └── proto.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── connection-encrypter-tls │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── pb │ │ │ ├── index.proto │ │ │ └── index.ts │ │ ├── tls.browser.ts │ │ ├── tls.ts │ │ └── utils.ts │ ├── test │ │ ├── fixtures │ │ │ └── test-vectors.ts │ │ ├── index.spec.ts │ │ └── utils.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── crypto │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benchmark │ │ ├── der │ │ │ ├── decode-pkcs1-to-jwk.js │ │ │ ├── decode-pkix-to-jwk.js │ │ │ ├── encode-jwk-to-pkcs1.js │ │ │ └── encode-jwk-to-pkix.js │ │ ├── ed25519 │ │ │ ├── compat.cjs │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── ephemeral-keys.cjs │ │ ├── key-stretcher.cjs │ │ └── rsa.cjs │ ├── package.json │ ├── src │ │ ├── ciphers │ │ │ ├── aes-gcm.browser.ts │ │ │ ├── aes-gcm.ts │ │ │ ├── index.ts │ │ │ └── interface.ts │ │ ├── errors.ts │ │ ├── hmac │ │ │ ├── index.browser.ts │ │ │ ├── index.ts │ │ │ └── lengths.ts │ │ ├── index.ts │ │ ├── keys │ │ │ ├── ecdh │ │ │ │ ├── index.browser.ts │ │ │ │ └── index.ts │ │ │ ├── ecdsa │ │ │ │ ├── ecdsa.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── ed25519 │ │ │ │ ├── ed25519.ts │ │ │ │ ├── index.browser.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ ├── ephemeral-keys.ts │ │ │ ├── index.ts │ │ │ ├── interface.ts │ │ │ ├── key-stretcher.ts │ │ │ ├── keys.proto │ │ │ ├── keys.ts │ │ │ ├── rsa │ │ │ │ ├── der.ts │ │ │ │ ├── index.browser.ts │ │ │ │ ├── index.ts │ │ │ │ ├── rsa.ts │ │ │ │ └── utils.ts │ │ │ └── secp256k1 │ │ │ │ ├── index.browser.ts │ │ │ │ ├── index.ts │ │ │ │ ├── secp256k1.ts │ │ │ │ └── utils.ts │ │ ├── pbkdf2.ts │ │ ├── random-bytes.ts │ │ ├── util.ts │ │ └── webcrypto │ │ │ ├── index.ts │ │ │ ├── webcrypto.browser.ts │ │ │ └── webcrypto.ts │ ├── test │ │ ├── crypto.spec.ts │ │ ├── fixtures │ │ │ ├── ecdsa.ts │ │ │ ├── go-elliptic-key.ts │ │ │ ├── go-key-ed25519.ts │ │ │ ├── go-key-rsa.ts │ │ │ ├── go-key-secp256k1.ts │ │ │ ├── go-stretch-key.ts │ │ │ ├── rsa.ts │ │ │ └── secp256k1.ts │ │ ├── helpers │ │ │ └── test-garbage-error-handling.ts │ │ ├── hmac │ │ │ └── hmac.spec.ts │ │ ├── keys │ │ │ ├── ecdsa.spec.ts │ │ │ ├── ed25519.spec.ts │ │ │ ├── ephemeral-keys.spec.ts │ │ │ ├── key-stretcher.spec.ts │ │ │ ├── rsa.spec.ts │ │ │ └── secp256k1.spec.ts │ │ ├── random-bytes.spec.ts │ │ ├── util.spec.ts │ │ └── workaround.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── integration-tests │ ├── .aegir.js │ ├── LICENSE │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ ├── bootstrap.spec.ts │ │ ├── circuit-relay-discovery.node.ts │ │ ├── circuit-relay-discovery.spec.ts │ │ ├── circuit-relay.node.ts │ │ ├── circuit-relay.spec.ts │ │ ├── compliance │ │ │ ├── connection-encryption │ │ │ │ ├── plaintext.spec.ts │ │ │ │ └── tls.spec.ts │ │ │ └── transport │ │ │ │ ├── circuit-relay.spec.ts │ │ │ │ ├── memory.spec.ts │ │ │ │ ├── tcp.spec.ts │ │ │ │ ├── webrtc-direct.spec.ts │ │ │ │ ├── webrtc.spec.ts │ │ │ │ └── websockets.spec.ts │ │ ├── connections.spec.ts │ │ ├── core.spec.ts │ │ ├── dcutr.node.ts │ │ ├── dht.node.ts │ │ ├── events.spec.ts │ │ ├── fetch.spec.ts │ │ ├── fixtures │ │ │ ├── base-options.browser.ts │ │ │ ├── base-options.ts │ │ │ ├── create-peers.ts │ │ │ ├── slow-muxer.ts │ │ │ └── utils.ts │ │ ├── identify.node.ts │ │ ├── interop.ts │ │ ├── lifecycle.spec.ts │ │ ├── listening.spec.ts │ │ ├── mdns.node.ts │ │ ├── node.ts │ │ ├── peers.spec.ts │ │ ├── ping.spec.ts │ │ ├── protocol-prefix.spec.ts │ │ └── webrtc-private-to-private.spec.ts │ └── tsconfig.json ├── interface-compliance-tests │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── connection-encryption │ │ │ ├── index.ts │ │ │ └── utils │ │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── is-valid-tick.ts │ │ ├── matchers.ts │ │ ├── mocks │ │ │ ├── connection-manager.ts │ │ │ ├── connection.ts │ │ │ ├── duplex.ts │ │ │ ├── index.ts │ │ │ ├── multiaddr-connection.ts │ │ │ ├── muxer.ts │ │ │ ├── registrar.ts │ │ │ └── upgrader.ts │ │ ├── peer-discovery │ │ │ └── index.ts │ │ ├── pubsub │ │ │ ├── api.ts │ │ │ ├── connection-handlers.ts │ │ │ ├── emit-self.ts │ │ │ ├── index.ts │ │ │ ├── messages.ts │ │ │ ├── multiple-nodes.ts │ │ │ ├── two-nodes.ts │ │ │ └── utils.ts │ │ ├── stream-muxer │ │ │ ├── base-test.ts │ │ │ ├── close-test.ts │ │ │ ├── fixtures │ │ │ │ └── pb │ │ │ │ │ ├── message.proto │ │ │ │ │ └── message.ts │ │ │ ├── index.ts │ │ │ ├── mega-stress-test.ts │ │ │ ├── spawner.ts │ │ │ └── stress-test.ts │ │ └── transport │ │ │ ├── index.ts │ │ │ └── utils.ts │ ├── test │ │ ├── matchers.spec.ts │ │ └── mocks │ │ │ └── muxer.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── interface-internal │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── address-manager.ts │ │ ├── connection-manager.ts │ │ ├── index.ts │ │ ├── random-walk.ts │ │ ├── registrar.ts │ │ └── transport-manager.ts │ ├── tsconfig.json │ └── typedoc.json ├── interface │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── connection-encrypter.ts │ │ ├── connection-gater.ts │ │ ├── connection.ts │ │ ├── content-routing.ts │ │ ├── errors.ts │ │ ├── event-target.ts │ │ ├── events.browser.ts │ │ ├── events.ts │ │ ├── index.ts │ │ ├── keys.ts │ │ ├── metrics.ts │ │ ├── peer-discovery.ts │ │ ├── peer-id.ts │ │ ├── peer-info.ts │ │ ├── peer-routing.ts │ │ ├── peer-store.ts │ │ ├── pubsub.ts │ │ ├── record.ts │ │ ├── startable.ts │ │ ├── stream-handler.ts │ │ ├── stream-muxer.ts │ │ ├── topology.ts │ │ └── transport.ts │ ├── tsconfig.json │ └── typedoc.json ├── kad-dht │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benchmarks │ │ └── add-with-kad-id.js │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── content-fetching │ │ │ └── index.ts │ │ ├── content-routing │ │ │ └── index.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── kad-dht.ts │ │ ├── message │ │ │ ├── dht.proto │ │ │ ├── dht.ts │ │ │ └── utils.ts │ │ ├── network.ts │ │ ├── peer-distance-list.ts │ │ ├── peer-routing │ │ │ └── index.ts │ │ ├── providers.ts │ │ ├── query-self.ts │ │ ├── query │ │ │ ├── events.ts │ │ │ ├── manager.ts │ │ │ ├── query-path.ts │ │ │ └── types.ts │ │ ├── record │ │ │ ├── selectors.ts │ │ │ └── validators.ts │ │ ├── reprovider.ts │ │ ├── routing-table │ │ │ ├── closest-peers.ts │ │ │ ├── generated-prefix-list-browser.ts │ │ │ ├── generated-prefix-list.ts │ │ │ ├── index.ts │ │ │ ├── k-bucket.ts │ │ │ └── refresh.ts │ │ ├── rpc │ │ │ ├── handlers │ │ │ │ ├── add-provider.ts │ │ │ │ ├── find-node.ts │ │ │ │ ├── get-providers.ts │ │ │ │ ├── get-value.ts │ │ │ │ ├── ping.ts │ │ │ │ └── put-value.ts │ │ │ └── index.ts │ │ ├── topology-listener.ts │ │ └── utils.ts │ ├── test │ │ ├── closest-peers.spec.ts │ │ ├── content-routing.spec.ts │ │ ├── enable-server-mode.spec.ts │ │ ├── fixtures │ │ │ ├── msg-1 │ │ │ ├── msg-2 │ │ │ ├── msg-3 │ │ │ ├── msg-4 │ │ │ ├── msg-5 │ │ │ ├── msg-6 │ │ │ ├── msg-7 │ │ │ ├── msg-8 │ │ │ └── record │ │ │ │ └── go-key-records.ts │ │ ├── generate-peers │ │ │ ├── .gitignore │ │ │ ├── generate-peer.go │ │ │ └── generate-peers.node.ts │ │ ├── kad-dht.spec.ts │ │ ├── kad-utils.spec.ts │ │ ├── libp2p-routing.spec.ts │ │ ├── message.node.ts │ │ ├── message.spec.ts │ │ ├── multiple-nodes.spec.ts │ │ ├── network.spec.ts │ │ ├── peer-distance-list.spec.ts │ │ ├── peer-routing.spec.ts │ │ ├── providers.spec.ts │ │ ├── query-self.spec.ts │ │ ├── query.spec.ts │ │ ├── record │ │ │ ├── selection.spec.ts │ │ │ └── validator.spec.ts │ │ ├── reprovider.spec.ts │ │ ├── routing-table.spec.ts │ │ ├── rpc │ │ │ ├── handlers │ │ │ │ ├── add-provider.spec.ts │ │ │ │ ├── find-node.spec.ts │ │ │ │ ├── get-providers.spec.ts │ │ │ │ ├── get-value.spec.ts │ │ │ │ ├── ping.spec.ts │ │ │ │ └── put-value.spec.ts │ │ │ └── index.node.ts │ │ └── utils │ │ │ ├── create-peer-id.ts │ │ │ ├── create-values.ts │ │ │ ├── sort-closest-peers.ts │ │ │ └── test-dht.ts │ ├── tsconfig.json │ └── typedoc.json ├── keychain │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── doc │ │ ├── private-key.png │ │ └── private-key.xml │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── keychain.ts │ │ └── utils │ │ │ ├── constants.ts │ │ │ ├── export.ts │ │ │ └── import.ts │ ├── test │ │ ├── keychain.spec.ts │ │ └── utils │ │ │ └── import-export.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── libp2p │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package-list.json │ ├── package.json │ ├── scripts │ │ └── update-version.js │ ├── src │ │ ├── address-manager │ │ │ ├── dns-mappings.ts │ │ │ ├── index.ts │ │ │ ├── ip-mappings.ts │ │ │ ├── observed-addresses.ts │ │ │ └── transport-addresses.ts │ │ ├── components.ts │ │ ├── config.ts │ │ ├── config │ │ │ ├── connection-gater.browser.ts │ │ │ └── connection-gater.ts │ │ ├── connection-manager │ │ │ ├── address-sorter.ts │ │ │ ├── connection-pruner.ts │ │ │ ├── constants.browser.ts │ │ │ ├── constants.defaults.ts │ │ │ ├── constants.ts │ │ │ ├── dial-queue.ts │ │ │ ├── index.ts │ │ │ ├── reconnect-queue.ts │ │ │ └── utils.ts │ │ ├── connection-monitor.ts │ │ ├── connection │ │ │ └── index.ts │ │ ├── content-routing.ts │ │ ├── errors.ts │ │ ├── get-peer.ts │ │ ├── index.ts │ │ ├── libp2p.ts │ │ ├── peer-routing.ts │ │ ├── random-walk.ts │ │ ├── registrar.ts │ │ ├── transport-manager.ts │ │ ├── upgrader.ts │ │ ├── user-agent.browser.ts │ │ ├── user-agent.react-native.ts │ │ ├── user-agent.ts │ │ └── version.ts │ ├── test │ │ ├── addresses │ │ │ └── address-manager.spec.ts │ │ ├── connection-manager │ │ │ ├── address-sorter.spec.ts │ │ │ ├── connection-gater.spec.ts │ │ │ ├── connection-pruner.spec.ts │ │ │ ├── dial-queue.spec.ts │ │ │ ├── index.spec.ts │ │ │ ├── multiaddr-to-ipnet.spec.ts │ │ │ ├── reconnect-queue.spec.ts │ │ │ └── utils.ts │ │ ├── connection-monitor │ │ │ └── index.spec.ts │ │ ├── connection │ │ │ ├── fixtures │ │ │ │ └── pair.ts │ │ │ └── index.spec.ts │ │ ├── content-routing │ │ │ └── content-routing.spec.ts │ │ ├── core │ │ │ ├── core.spec.ts │ │ │ ├── events.spec.ts │ │ │ ├── get-public-key.spec.ts │ │ │ ├── peer-id.spec.ts │ │ │ ├── random-walk.spec.ts │ │ │ ├── service-dependencies.spec.ts │ │ │ ├── status.spec.ts │ │ │ └── user-agent.spec.ts │ │ ├── fixtures │ │ │ └── get-component.ts │ │ ├── peer-discovery │ │ │ └── peer-discovery.spec.ts │ │ ├── peer-routing │ │ │ └── peer-routing.spec.ts │ │ ├── registrar │ │ │ ├── errors.spec.ts │ │ │ ├── protocols.spec.ts │ │ │ └── registrar.spec.ts │ │ ├── transports │ │ │ └── transport-manager.spec.ts │ │ └── upgrading │ │ │ ├── upgrader.spec.ts │ │ │ └── utils.ts │ ├── tsconfig.json │ └── typedoc.json ├── logger │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── utils.ts │ ├── test │ │ ├── index.spec.ts │ │ └── utils.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── metrics-opentelemetry │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── counter-group.ts │ │ ├── counter.ts │ │ ├── histogram-group.ts │ │ ├── histogram.ts │ │ ├── index.ts │ │ ├── metric-group.ts │ │ ├── metric.ts │ │ ├── summary-group.ts │ │ ├── summary.ts │ │ ├── system-metrics.browser.ts │ │ └── system-metrics.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── metrics-prometheus │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── counter-group.ts │ │ ├── counter.ts │ │ ├── histogram-group.ts │ │ ├── histogram.ts │ │ ├── index.ts │ │ ├── metric-group.ts │ │ ├── metric.ts │ │ ├── summary-group.ts │ │ ├── summary.ts │ │ └── utils.ts │ ├── test │ │ ├── counter-groups.spec.ts │ │ ├── counters.spec.ts │ │ ├── custom-registry.spec.ts │ │ ├── fixtures │ │ │ └── random-metric-name.ts │ │ ├── histogram-groups.spec.ts │ │ ├── histograms.spec.ts │ │ ├── index.spec.ts │ │ ├── metric-groups.spec.ts │ │ ├── metrics.spec.ts │ │ ├── streams.spec.ts │ │ ├── summaries.spec.ts │ │ ├── summary-groups.spec.ts │ │ └── utils.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── metrics-simple │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── multistream-select │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── handle.ts │ │ ├── index.ts │ │ ├── multistream.ts │ │ └── select.ts │ ├── test │ │ ├── dialer.spec.ts │ │ ├── integration.spec.ts │ │ ├── listener.spec.ts │ │ └── multistream.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-collections │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── filter.ts │ │ ├── index.ts │ │ ├── list.ts │ │ ├── map.ts │ │ ├── set.ts │ │ ├── tracked-list.ts │ │ ├── tracked-map.ts │ │ ├── tracked-set.ts │ │ └── util.ts │ ├── test │ │ ├── filter.spec.ts │ │ ├── list.spec.ts │ │ ├── map.spec.ts │ │ ├── set.spec.ts │ │ ├── tracked-list.spec.ts │ │ ├── tracked-map.spec.ts │ │ └── tracked-set.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-discovery-bootstrap │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ ├── bootstrap.spec.ts │ │ ├── compliance.spec.ts │ │ └── fixtures │ │ │ ├── default-peers.ts │ │ │ └── some-invalid-peers.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-discovery-mdns │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── mdns.ts │ │ ├── query.ts │ │ └── utils.ts │ ├── test │ │ ├── compliance.spec.ts │ │ └── multicast-dns.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-id │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── peer-id.ts │ ├── test │ │ ├── fixtures │ │ │ ├── go-private-key.ts │ │ │ └── sample-id.ts │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-record │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── envelope │ │ │ ├── envelope.proto │ │ │ ├── envelope.ts │ │ │ ├── errors.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── peer-record │ │ │ ├── consts.ts │ │ │ ├── index.ts │ │ │ ├── peer-record.proto │ │ │ └── peer-record.ts │ ├── test │ │ ├── envelope.spec.ts │ │ └── peer-record.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── peer-store │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benchmarks │ │ └── load-peers.js │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── pb │ │ │ ├── peer.proto │ │ │ └── peer.ts │ │ ├── store.ts │ │ └── utils │ │ │ ├── bytes-to-peer.ts │ │ │ ├── dedupe-addresses.ts │ │ │ ├── peer-equals.ts │ │ │ ├── peer-id-to-datastore-key.ts │ │ │ └── to-peer-pb.ts │ ├── test │ │ ├── index.spec.ts │ │ ├── merge.spec.ts │ │ ├── patch.spec.ts │ │ ├── save.spec.ts │ │ └── utils │ │ │ └── dedupe-addresses.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── pnet │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── crypto.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ └── key-generator.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-autonat │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── autonat.ts │ │ ├── constants.ts │ │ ├── index.ts │ │ └── pb │ │ │ ├── index.proto │ │ │ └── index.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-dcutr │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── dcutr.ts │ │ ├── index.ts │ │ ├── pb │ │ │ ├── message.proto │ │ │ └── message.ts │ │ └── utils.ts │ ├── test │ │ └── utils.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-echo │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── echo.ts │ │ └── index.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-fetch │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── fetch.ts │ │ ├── index.ts │ │ └── pb │ │ │ ├── proto.proto │ │ │ └── proto.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-identify │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── consts.ts │ │ ├── identify-push.ts │ │ ├── identify.ts │ │ ├── index.ts │ │ ├── pb │ │ │ ├── message.proto │ │ │ └── message.ts │ │ └── utils.ts │ ├── test │ │ ├── fixtures │ │ │ └── index.ts │ │ ├── index.spec.ts │ │ └── push.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-perf │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ └── perf-service.ts │ ├── test │ │ ├── index.spec.ts │ │ └── run._ts │ ├── tsconfig.json │ └── typedoc.json ├── protocol-ping │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ └── ping.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── pubsub-floodsub │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── img │ │ ├── test-cases.monopic │ │ └── test-cases.txt │ ├── package.json │ ├── src │ │ ├── cache.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── message │ │ │ ├── rpc.proto │ │ │ └── rpc.ts │ ├── test │ │ ├── compliance.spec.ts │ │ ├── fixtures │ │ │ ├── peers.ts │ │ │ └── relay.ts │ │ └── floodsub.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── pubsub │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── peer-streams.ts │ │ ├── sign.ts │ │ └── utils.ts │ ├── test │ │ ├── emit-self.spec.ts │ │ ├── instance.spec.ts │ │ ├── lifecycle.spec.ts │ │ ├── message.spec.ts │ │ ├── message │ │ │ ├── rpc.proto │ │ │ └── rpc.ts │ │ ├── peer-streams.spec.ts │ │ ├── pubsub.spec.ts │ │ ├── sign.spec.ts │ │ ├── topic-validators.spec.ts │ │ ├── utils.spec.ts │ │ └── utils │ │ │ └── index.ts │ ├── tsconfig.json │ └── typedoc.json ├── record │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── record.proto │ │ ├── record.ts │ │ └── utils.ts │ ├── test │ │ ├── fixtures │ │ │ └── go-record.ts │ │ ├── record.spec.ts │ │ └── utils.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── stream-multiplexer-mplex │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benchmark │ │ ├── send-and-receive.js │ │ └── stream-transfer.js │ ├── package.json │ ├── src │ │ ├── decode.ts │ │ ├── encode.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── message-types.ts │ │ ├── mplex.ts │ │ └── stream.ts │ ├── test │ │ ├── coder.spec.ts │ │ ├── compliance.spec.ts │ │ ├── fixtures │ │ │ ├── decode.ts │ │ │ └── utils.ts │ │ ├── mplex.spec.ts │ │ ├── restrict-size.spec.ts │ │ └── stream.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-circuit-relay-v2 │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── pb │ │ │ ├── index.proto │ │ │ └── index.ts │ │ ├── server │ │ │ ├── index.ts │ │ │ ├── reservation-store.ts │ │ │ └── reservation-voucher.ts │ │ ├── transport │ │ │ ├── discovery.ts │ │ │ ├── index.ts │ │ │ ├── listener.ts │ │ │ ├── reservation-store.ts │ │ │ └── transport.ts │ │ └── utils.ts │ ├── test │ │ ├── hop.spec.ts │ │ ├── listener.spec.ts │ │ ├── reservation-store.spec.ts │ │ ├── stop.spec.ts │ │ ├── transport │ │ │ └── reservation-store.spec.ts │ │ ├── utils.spec.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-memory │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── connections.ts │ │ ├── index.ts │ │ ├── listener.ts │ │ └── memory.ts │ ├── test │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-tcp │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── listener.ts │ │ ├── socket-to-conn.ts │ │ ├── tcp.browser.ts │ │ ├── tcp.ts │ │ └── utils.ts │ ├── test │ │ ├── browser.ts │ │ ├── connection-limits.spec.ts │ │ ├── connection.spec.ts │ │ ├── filter.spec.ts │ │ ├── listen-dial.spec.ts │ │ ├── max-connections.spec.ts │ │ └── socket-to-conn.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-webrtc │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── error.ts │ │ ├── index.ts │ │ ├── maconn.ts │ │ ├── muxer.ts │ │ ├── private-to-private │ │ │ ├── initiate-connection.ts │ │ │ ├── listener.ts │ │ │ ├── pb │ │ │ │ ├── message.proto │ │ │ │ └── message.ts │ │ │ ├── signaling-stream-handler.ts │ │ │ ├── transport.ts │ │ │ └── util.ts │ │ ├── private-to-public │ │ │ ├── listener.browser.ts │ │ │ ├── listener.ts │ │ │ ├── pb │ │ │ │ ├── message.proto │ │ │ │ └── message.ts │ │ │ ├── transport.ts │ │ │ └── utils │ │ │ │ ├── connect.ts │ │ │ │ ├── generate-certificates.browser.ts │ │ │ │ ├── generate-certificates.ts │ │ │ │ ├── generate-noise-prologue.ts │ │ │ │ ├── get-rtcpeerconnection.browser.ts │ │ │ │ ├── get-rtcpeerconnection.ts │ │ │ │ ├── pem.ts │ │ │ │ ├── sdp.ts │ │ │ │ └── stun-listener.ts │ │ ├── stream.ts │ │ ├── util.ts │ │ └── webrtc │ │ │ ├── index.browser.ts │ │ │ ├── index.react-native.ts │ │ │ └── index.ts │ ├── test │ │ ├── certificates.spec.ts │ │ ├── listener.spec.ts │ │ ├── maconn.spec.ts │ │ ├── muxer.spec.ts │ │ ├── peer.spec.ts │ │ ├── sdp.spec.ts │ │ ├── stream.spec.ts │ │ ├── transport.spec.ts │ │ └── util.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-websockets │ ├── .aegir.js │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── filters.ts │ │ ├── index.ts │ │ ├── listener.browser.ts │ │ ├── listener.ts │ │ └── socket-to-conn.ts │ ├── test │ │ ├── browser.ts │ │ ├── fixtures │ │ │ ├── certificate.pem │ │ │ └── key.pem │ │ └── node.ts │ ├── tsconfig.json │ └── typedoc.json ├── transport-webtransport │ ├── .aegir.js │ ├── .gitignore │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── index.ts │ │ ├── listener.browser.ts │ │ ├── listener.ts │ │ ├── muxer.ts │ │ ├── stream.ts │ │ ├── utils │ │ │ ├── generate-certificates.browser.ts │ │ │ ├── generate-certificates.ts │ │ │ ├── inert-duplex.ts │ │ │ ├── is-subset.ts │ │ │ └── parse-multiaddr.ts │ │ ├── webtransport.browser.ts │ │ └── webtransport.ts │ ├── test │ │ ├── browser.ts │ │ ├── fixtures │ │ │ └── random-bytes.ts │ │ ├── transport.spec.ts │ │ └── utils │ │ │ ├── is-subset.spec.ts │ │ │ └── parse-multiaddr.spec.ts │ ├── tsconfig.json │ └── typedoc.json ├── upnp-nat │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── package.json │ ├── src │ │ ├── check-external-address.ts │ │ ├── constants.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── search-gateway-finder.ts │ │ ├── static-gateway-finder.ts │ │ ├── upnp-nat.browser.ts │ │ ├── upnp-nat.ts │ │ └── upnp-port-mapper.ts │ ├── test │ │ ├── browser.ts │ │ └── index.spec.ts │ ├── tsconfig.json │ └── typedoc.json └── utils │ ├── CHANGELOG.md │ ├── CODE_OF_CONDUCT.md │ ├── LICENSE-APACHE │ ├── LICENSE-MIT │ ├── README.md │ ├── benchmark │ └── filter │ │ └── bloom-filter.cjs │ ├── package.json │ ├── src │ ├── abort-options.ts │ ├── abstract-stream.ts │ ├── adaptive-timeout.ts │ ├── array-equals.ts │ ├── close-source.ts │ ├── close.ts │ ├── debounce.ts │ ├── errors.ts │ ├── filters │ │ ├── bloom-filter.ts │ │ ├── bucket.ts │ │ ├── cuckoo-filter.ts │ │ ├── fingerprint.ts │ │ ├── hashes.ts │ │ ├── index.ts │ │ ├── scalable-cuckoo-filter.ts │ │ └── utils.ts │ ├── get-thin-waist-addresses.browser.ts │ ├── get-thin-waist-addresses.ts │ ├── global-unicast-ip.ts │ ├── index.ts │ ├── ip-port-to-multiaddr.ts │ ├── is-async-generator.ts │ ├── is-generator.ts │ ├── is-promise.ts │ ├── link-local-ip.ts │ ├── merge-options.ts │ ├── moving-average.ts │ ├── multiaddr │ │ ├── is-global-unicast.ts │ │ ├── is-ip-based.ts │ │ ├── is-link-local.ts │ │ ├── is-loopback.ts │ │ ├── is-network-address.ts │ │ └── is-private.ts │ ├── peer-queue.ts │ ├── priority-queue.ts │ ├── private-ip.ts │ ├── queue │ │ ├── index.ts │ │ ├── job.ts │ │ └── recipient.ts │ ├── rate-limiter.ts │ ├── repeating-task.ts │ ├── stream-to-ma-conn.ts │ ├── tracked-list.ts │ └── tracked-map.ts │ ├── test │ ├── abstract-stream.spec.ts │ ├── adaptive-timeout.spec.ts │ ├── array-equals.spec.ts │ ├── close-source.spec.ts │ ├── close.spec.ts │ ├── debounce.spec.ts │ ├── filter │ │ ├── bloom-filter.spec.ts │ │ ├── cuckoo-filter.spec.ts │ │ └── scalable-cuckoo-filter.spec.ts │ ├── fixtures │ │ └── test-signal.ts │ ├── get-thin-waist-addresses.spec.ts │ ├── global-unicast-ip.spec.ts │ ├── ip-port-to-multiaddr.spec.ts │ ├── is-async-generator.spec.ts │ ├── is-generator.spec.ts │ ├── is-promise.spec.ts │ ├── link-local-ip.spec.ts │ ├── merge-options.spec.ts │ ├── moving-average.spec.ts │ ├── multiaddr │ │ ├── is-global-unicast.spec.ts │ │ ├── is-ip-based.spec.ts │ │ ├── is-link-local.spec.ts │ │ ├── is-loopback.spec.ts │ │ ├── is-network-address.spec.ts │ │ └── is-private.spec.ts │ ├── peer-job-queue.spec.ts │ ├── priority-queue.spec.ts │ ├── private-ip.spec.ts │ ├── queue.spec.ts │ ├── rate-limiter.spec.ts │ ├── repeating-task.spec.ts │ ├── stream-to-ma-conn.spec.ts │ ├── tracked-list.spec.ts │ └── tracked-map.spec.ts │ ├── tsconfig.json │ └── typedoc.json └── typedoc.json /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "./node_modules/aegir/cspell.json" 4 | ], 5 | "dictionaries": ["project"], 6 | "dictionaryDefinitions": [{ 7 | "name": "project", 8 | "path": "./.github/dictionary.txt", 9 | "addWords": true 10 | }] 11 | } 12 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ChromiumDockerfile 2 | Dockerfile 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Technical Questions 4 | url: https://github.com/libp2p/js-libp2p/discussions/new?category=q-a 5 | about: Please ask technical questions in the js-libp2p Github Discussions forum. 6 | - name: Community-wide libp2p Discussion 7 | url: https://discuss.libp2p.io 8 | about: Discussions and questions about the libp2p community. 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 20 9 | commit-message: 10 | prefix: "deps" 11 | prefix-development: "chore" 12 | groups: 13 | libp2p-deps: 14 | patterns: 15 | - "*libp2p*" 16 | - "*multiformats*" 17 | - "*blockstore*" 18 | - "*datastore*" 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | interval: "weekly" 23 | commit-message: 24 | prefix: chore 25 | -------------------------------------------------------------------------------- /.github/dictionary.txt: -------------------------------------------------------------------------------- 1 | setbit 2 | getbit 3 | stopstr 4 | rlflx 5 | incrby 6 | hopr 7 | dout 8 | supercop 9 | nothrow 10 | buildx 11 | blpop 12 | rpush 13 | additionals 14 | SECG 15 | Certicom 16 | RSAES 17 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | name: Automerge 2 | on: [ pull_request ] 3 | 4 | jobs: 5 | automerge: 6 | uses: protocol/.github/.github/workflows/automerge.yml@master 7 | with: 8 | job: 'automerge' 9 | -------------------------------------------------------------------------------- /.github/workflows/generated-pr.yml: -------------------------------------------------------------------------------- 1 | name: Close Generated PRs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1 15 | -------------------------------------------------------------------------------- /.github/workflows/semantic-pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Semantic PR 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-semantic-pull-request.yml@v1 13 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | dist 4 | .docs 5 | .coverage 6 | node_modules 7 | package-lock.json 8 | yarn.lock 9 | .vscode 10 | interop/*-image.json 11 | .tmp-compiled-docs 12 | tsconfig-doc-check.aegir.json 13 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @libp2p/js-libp2p-dev 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | The `js-libp2p` project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | js-libp2p is still in development. This means that there may be problems in our protocols, 4 | or there may be mistakes in our implementations. 5 | 6 | We take security vulnerabilities very seriously. If you discover a security issue, 7 | please bring it to our attention right away! 8 | 9 | ## Reporting a Vulnerability 10 | 11 | If you find a vulnerability that may affect live deployments -- for example, by exposing 12 | a remote execution exploit -- please [**report privately**](https://github.com/libp2p/js-libp2p/security/advisories/new). 13 | 14 | Please **DO NOT file a public issue**. 15 | 16 | If the issue is an implementation weakness that cannot be immediately exploited or 17 | something not yet deployed, just discuss it openly. 18 | 19 | If you need assistance, please reach out to [security@libp2p.io](mailto:security@libp2p.io). 20 | 21 | ## Reporting a non security bug 22 | 23 | For non-security bugs, please simply file a GitHub [issue](https://github.com/libp2p/js-libp2p/issues/new). -------------------------------------------------------------------------------- /doc/API.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | The documentation here has moved to https://libp2p.github.io/js-libp2p - please update your bookmarks! 4 | -------------------------------------------------------------------------------- /doc/migrations/MIGRATION_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | # Migrating to libp2p@__ 3 | 4 | A migration guide for refactoring your application code from libp2p v__ to v__. 5 | 6 | ## Table of Contents 7 | 8 | - [API](#api) 9 | - [Module Updates](#module-updates) 10 | 11 | ## API 12 | 13 | 33 | 34 | ## Module Updates 35 | 36 | With this release you should update the following libp2p modules if you are relying on them: 37 | 38 | 42 | 43 | ```json 44 | 45 | ``` 46 | -------------------------------------------------------------------------------- /doc/migrations/v0.32-v0.33.md: -------------------------------------------------------------------------------- 1 | 2 | # Migrating to libp2p@33 3 | 4 | A migration guide for refactoring your application code from libp2p v0.32.x to v0.33.0. 5 | 6 | ## Table of Contents 7 | 8 | - [Migrating to libp2p@33](#migrating-to-libp2p33) 9 | - [Table of Contents](#table-of-contents) 10 | - [Module Updates](#module-updates) 11 | 12 | ## Module Updates 13 | 14 | Libp2p uses a datastore implementation for PeerStore persistence and for the DHT state. While libp2p defaults to a datastore implementation, it can receive any implementation of a datastore compliant with the [interface-datastore](https://github.com/ipfs/js-ipfs-interfaces/tree/master/packages/interface-datastore) via its configuration. 15 | 16 | In this release, we updated to `interface-datastore@6.0.0`. As a result, libp2p users relying on a configured datastore should update it to a compliant implementation for updating libp2p. 17 | -------------------------------------------------------------------------------- /doc/migrations/v0.40-v0.41.md: -------------------------------------------------------------------------------- 1 | # Migrating to libp2p@41 2 | 3 | A migration guide for refactoring your application code from libp2p v0.40.x to v0.41.0. 4 | 5 | ## Table of Contents 6 | 7 | - [Metrics](#metrics) 8 | 9 | ## Metrics 10 | 11 | libp2p no longer ships a built-in metrics object, allowing the user to configure an implementation of their choice or not at all. 12 | 13 | Currently an [implementation](https://www.npmjs.com/package/@libp2p/prometheus-metrics) exists for [Prometheus](https://prometheus.io/)/[Graphana](https://grafana.com/), others may follow. 14 | 15 | **Before** 16 | 17 | ```js 18 | import { createLibp2p } from 'libp2p' 19 | 20 | const node = await createLibp2p({ 21 | metrics: { 22 | enabled: true, 23 | // ... other options 24 | } 25 | }) 26 | ``` 27 | 28 | **After** 29 | 30 | ```js 31 | import { createLibp2p } from 'libp2p' 32 | import { prometheusMetrics } from '@libp2p/prometheus-metrics' 33 | 34 | const node = await createLibp2p({ 35 | metrics: prometheusMetrics() 36 | }) 37 | ``` 38 | -------------------------------------------------------------------------------- /doc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libp2p/docs", 3 | "version": "1.0.0", 4 | "description": "Docs for libp2p", 5 | "license": "Apache-2.0 OR MIT", 6 | "homepage": "https://github.com/libp2p/js-libp2p/tree/main/doc#readme", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/libp2p/js-libp2p.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/libp2p/js-libp2p/issues" 13 | }, 14 | "type": "module", 15 | "exports": {}, 16 | "scripts": { 17 | "doc-check": "aegir doc-check" 18 | }, 19 | "devDependencies": { 20 | "aegir": "^47.0.14" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /doc/production/DELEGATE_NODES.md: -------------------------------------------------------------------------------- 1 | # Delegate Nodes 2 | 3 | [TODO](https://github.com/libp2p/js-libp2p/pull/718) 4 | -------------------------------------------------------------------------------- /doc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x5a7e7c7acb21521e99021d746740b368801cbfe531301e50bdbaafdc24a0aac5" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /img/js-libp2p-ipfs-browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/js-libp2p-ipfs-browser.png -------------------------------------------------------------------------------- /img/js-libp2p-ipfs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/js-libp2p-ipfs.png -------------------------------------------------------------------------------- /img/js-libp2p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/js-libp2p.png -------------------------------------------------------------------------------- /img/libp2p-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/libp2p-arch.png -------------------------------------------------------------------------------- /img/libp2p-logos.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/libp2p-logos.sketch -------------------------------------------------------------------------------- /img/libp2p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/img/libp2p.png -------------------------------------------------------------------------------- /interop/BrowserDockerfile: -------------------------------------------------------------------------------- 1 | # Workaround: https://github.com/docker/cli/issues/996 2 | ARG BASE_IMAGE=node-js-libp2p-head 3 | FROM ${BASE_IMAGE} 4 | 5 | WORKDIR /app/interop 6 | 7 | # Options: chromium, firefox, webkit 8 | ARG BROWSER=chromium 9 | ENV BROWSER=${BROWSER} 10 | 11 | ENTRYPOINT npm test -- -t browser -- --browser $BROWSER 12 | -------------------------------------------------------------------------------- /interop/Dockerfile: -------------------------------------------------------------------------------- 1 | # install node and browsers 2 | FROM mcr.microsoft.com/playwright:v1.50.1 3 | 4 | WORKDIR /app 5 | 6 | COPY package.json package-lock.json ./ 7 | COPY ./packages ./packages 8 | COPY ./interop ./interop 9 | 10 | # disable coloured output and CLI animation from test runners 11 | ENV CI=true 12 | 13 | # install inside the container so any native deps will have the docker arch 14 | RUN npm ci 15 | 16 | WORKDIR /app/interop 17 | 18 | ENTRYPOINT npm test -- -t node -- --exit 19 | -------------------------------------------------------------------------------- /interop/chromium-version.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "chromium-js-libp2p-head", 3 | "containerImageID": "chromium-js-libp2p-head", 4 | "transports": [ 5 | { 6 | "name": "webtransport", 7 | "onlyDial": true 8 | }, 9 | { 10 | "name": "webrtc-direct", 11 | "onlyDial": true 12 | }, 13 | "webrtc", 14 | { 15 | "name": "wss", 16 | "onlyDial": true 17 | } 18 | ], 19 | "secureChannels": ["noise"], 20 | "muxers": ["yamux", "mplex"] 21 | } 22 | -------------------------------------------------------------------------------- /interop/firefox-version.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "firefox-js-libp2p-head", 3 | "containerImageID": "firefox-js-libp2p-head", 4 | "transports": [ 5 | { 6 | "name": "webrtc-direct", 7 | "onlyDial": true 8 | }, 9 | "webrtc", 10 | { 11 | "name": "wss", 12 | "onlyDial": true 13 | } 14 | ], 15 | "secureChannels": ["noise"], 16 | "muxers": ["yamux", "mplex"] 17 | } 18 | -------------------------------------------------------------------------------- /interop/node-version.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "node-js-libp2p-head", 3 | "containerImageID": "node-js-libp2p-head", 4 | "transports": [ 5 | "tcp", 6 | "ws", 7 | { 8 | "name": "wss", 9 | "onlyDial": true 10 | }, 11 | "webrtc", 12 | "webrtc-direct", 13 | "quic-v1" 14 | ], 15 | "secureChannels": ["noise", "tls"], 16 | "muxers": ["yamux", "mplex"] 17 | } 18 | -------------------------------------------------------------------------------- /interop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@libp2p/transport-interop-libp2p-main", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "clean": "aegir clean", 8 | "build": "aegir build --bundle false", 9 | "test": "aegir test", 10 | "lint": "aegir lint", 11 | "dep-check": "aegir dep-check" 12 | }, 13 | "devDependencies": { 14 | "@chainsafe/libp2p-noise": "^16.1.3", 15 | "@chainsafe/libp2p-quic": "^1.1.1", 16 | "@chainsafe/libp2p-yamux": "^7.0.1", 17 | "@libp2p/circuit-relay-v2": "^3.2.14", 18 | "@libp2p/identify": "^3.0.32", 19 | "@libp2p/interface": "^2.10.2", 20 | "@libp2p/mplex": "^11.0.38", 21 | "@libp2p/ping": "^2.0.32", 22 | "@libp2p/tcp": "^10.1.13", 23 | "@libp2p/tls": "^2.2.3", 24 | "@libp2p/webrtc": "^5.2.15", 25 | "@libp2p/websockets": "^9.2.13", 26 | "@libp2p/webtransport": "^5.0.43", 27 | "@multiformats/multiaddr": "^12.4.0", 28 | "aegir": "^47.0.14", 29 | "libp2p": "^2.8.8", 30 | "p-event": "^6.0.1", 31 | "redis": "^4.7.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /interop/src/index.ts: -------------------------------------------------------------------------------- 1 | // Everything is defined in the test folder 2 | 3 | export { } 4 | -------------------------------------------------------------------------------- /interop/test/fixtures/redis-proxy.ts: -------------------------------------------------------------------------------- 1 | export async function redisProxy (commands: any[]): Promise { 2 | const res = await fetch(`http://localhost:${process.env.REDIS_PROXY_PORT}`, { 3 | method: 'POST', 4 | body: JSON.stringify(commands) 5 | }) 6 | 7 | if (!res.ok) { 8 | throw new Error('Redis command failed') 9 | } 10 | 11 | return res.json() 12 | } 13 | -------------------------------------------------------------------------------- /interop/test/fixtures/relay.ts: -------------------------------------------------------------------------------- 1 | import { noise } from '@chainsafe/libp2p-noise' 2 | import { yamux } from '@chainsafe/libp2p-yamux' 3 | import { circuitRelayServer } from '@libp2p/circuit-relay-v2' 4 | import { identify } from '@libp2p/identify' 5 | import { webSockets } from '@libp2p/websockets' 6 | import { createLibp2p } from 'libp2p' 7 | import type { Libp2p } from '@libp2p/interface' 8 | 9 | export async function createRelay (): Promise { 10 | const server = await createLibp2p({ 11 | addresses: { 12 | listen: ['/ip4/0.0.0.0/tcp/0/ws'] 13 | }, 14 | transports: [ 15 | webSockets() 16 | ], 17 | connectionGater: { 18 | denyDialMultiaddr: () => false 19 | }, 20 | connectionEncrypters: [noise()], 21 | streamMuxers: [yamux()], 22 | services: { 23 | identify: identify(), 24 | relay: circuitRelayServer({ 25 | reservations: { 26 | maxReservations: Infinity, 27 | applyDefaultLimit: false 28 | } 29 | }) 30 | } 31 | }) 32 | 33 | return server 34 | } 35 | -------------------------------------------------------------------------------- /interop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../packages/connection-encrypter-tls" 13 | }, 14 | { 15 | "path": "../packages/interface" 16 | }, 17 | { 18 | "path": "../packages/libp2p" 19 | }, 20 | { 21 | "path": "../packages/protocol-identify" 22 | }, 23 | { 24 | "path": "../packages/protocol-ping" 25 | }, 26 | { 27 | "path": "../packages/stream-multiplexer-mplex" 28 | }, 29 | { 30 | "path": "../packages/transport-circuit-relay-v2" 31 | }, 32 | { 33 | "path": "../packages/transport-tcp" 34 | }, 35 | { 36 | "path": "../packages/transport-webrtc" 37 | }, 38 | { 39 | "path": "../packages/transport-websockets" 40 | }, 41 | { 42 | "path": "../packages/transport-webtransport" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /interop/webkit-version.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "webkit-js-libp2p-head", 3 | "containerImageID": "webkit-js-libp2p-head", 4 | "transports": [ 5 | { 6 | "name": "webrtc-direct", 7 | "onlyDial": true 8 | }, 9 | "webrtc", 10 | { 11 | "name": "wss", 12 | "onlyDial": true 13 | } 14 | ], 15 | "secureChannels": ["noise"], 16 | "muxers": ["yamux", "mplex"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/config/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/config/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../keychain" 19 | }, 20 | { 21 | "path": "../logger" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/config/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/connection-encrypter-plaintext/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/connection-encrypter-plaintext/src/pb/proto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Exchange { 4 | optional bytes id = 1; 5 | optional PublicKey pubkey = 2; 6 | } 7 | 8 | enum KeyType { 9 | RSA = 0; 10 | Ed25519 = 1; 11 | secp256k1 = 2; 12 | ECDSA = 3; 13 | } 14 | 15 | message PublicKey { 16 | optional KeyType Type = 1; 17 | bytes Data = 2; 18 | } 19 | -------------------------------------------------------------------------------- /packages/connection-encrypter-plaintext/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../logger" 19 | }, 20 | { 21 | "path": "../peer-id" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/connection-encrypter-plaintext/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The handshake timed out 3 | */ 4 | export class HandshakeTimeoutError extends Error { 5 | constructor (message = 'Handshake timeout') { 6 | super(message) 7 | this.name = 'HandshakeTimeoutError' 8 | } 9 | } 10 | 11 | /** 12 | * The certificate was invalid 13 | */ 14 | export class InvalidCertificateError extends Error { 15 | constructor (message = 'Invalid certificate') { 16 | super(message) 17 | this.name = 'InvalidCertificateError' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * 4 | * Implements the spec at https://github.com/libp2p/specs/blob/master/tls/tls.md 5 | * 6 | * @example 7 | * 8 | * ```typescript 9 | * import { createLibp2p } from 'libp2p' 10 | * import { tls } from '@libp2p/tls' 11 | * 12 | * const node = await createLibp2p({ 13 | * // ...other options 14 | * connectionEncrypters: [ 15 | * tls() 16 | * ] 17 | * }) 18 | * ``` 19 | */ 20 | 21 | import { TLS } from './tls.js' 22 | import type { ComponentLogger, ConnectionEncrypter, Metrics, PrivateKey, Upgrader } from '@libp2p/interface' 23 | 24 | export const PROTOCOL = '/tls/1.0.0' 25 | 26 | export interface TLSComponents { 27 | privateKey: PrivateKey 28 | logger: ComponentLogger 29 | upgrader: Upgrader 30 | metrics?: Metrics 31 | } 32 | 33 | export function tls (): (components: TLSComponents) => ConnectionEncrypter { 34 | return (components) => new TLS(components) 35 | } 36 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/src/pb/index.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | enum KeyType { 4 | RSA = 0; 5 | Ed25519 = 1; 6 | secp256k1 = 2; 7 | ECDSA = 3; 8 | } 9 | 10 | message PublicKey { 11 | optional KeyType type = 1; 12 | optional bytes data = 2; 13 | } 14 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../logger" 19 | }, 20 | { 21 | "path": "../peer-id" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/connection-encrypter-tls/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/crypto/.aegir.js: -------------------------------------------------------------------------------- 1 | 2 | /** @type {import('aegir/types').PartialOptions} */ 3 | export default { 4 | build: { 5 | bundlesizeMax: '70kB' 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/crypto/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/crypto/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/crypto/benchmark/ed25519/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libp2p-crypto-ed25519-benchmarks", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "start": "node .", 8 | "compat": "node compat.js" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "@stablelib/ed25519": "^2.0.1", 13 | "benchmark": "^2.1.4", 14 | "ed25519": "^0.0.5", 15 | "ed25519-wasm-pro": "^1.1.1", 16 | "node-forge": "^1.0.0", 17 | "supercop.wasm": "^5.0.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/crypto/benchmark/ephemeral-keys.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const crypto = require('../dist/src/index.js') 3 | 4 | const Benchmark = require('benchmark') 5 | 6 | const suite = new Benchmark.Suite('ephemeral-keys') 7 | 8 | const secrets = [] 9 | const curves = ['P-256', 'P-384', 'P-521'] 10 | 11 | curves.forEach((curve) => { 12 | suite.add(`ephemeral key with secrect ${curve}`, async (d) => { 13 | const res = await crypto.keys.generateEphemeralKeyPair('P-256') 14 | const secret = await res.genSharedKey(res.key) 15 | secrets.push(secret) 16 | d.resolve() 17 | }, { defer: true }) 18 | }) 19 | 20 | suite 21 | .on('cycle', (event) => console.log(String(event.target))) 22 | .run({ async: true }) 23 | -------------------------------------------------------------------------------- /packages/crypto/benchmark/key-stretcher.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const crypto = require('../dist/src/index.js') 3 | 4 | const Benchmark = require('benchmark') 5 | 6 | const suite = new Benchmark.Suite('key-stretcher') 7 | 8 | const keys = [] 9 | 10 | const ciphers = ['AES-128', 'AES-256', 'Blowfish'] 11 | const hashes = ['SHA1', 'SHA256', 'SHA512'] 12 | 13 | ;(async () => { 14 | const res = await crypto.keys.generateEphemeralKeyPair('P-256') 15 | const secret = await res.genSharedKey(res.key) 16 | 17 | ciphers.forEach((cipher) => hashes.forEach((hash) => { 18 | setup(cipher, hash, secret) 19 | })) 20 | 21 | suite 22 | .on('cycle', (event) => console.log(String(event.target))) 23 | .run({ async: true }) 24 | })() 25 | 26 | function setup (cipher, hash, secret) { 27 | suite.add(`keyStretcher ${cipher} ${hash}`, async (d) => { 28 | const k = await crypto.keys.keyStretcher(cipher, hash, secret) 29 | keys.push(k) 30 | d.resolve() 31 | }, { defer: true }) 32 | } 33 | -------------------------------------------------------------------------------- /packages/crypto/benchmark/rsa.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const crypto = require('../dist/src/index.js') 3 | 4 | const Benchmark = require('benchmark') 5 | 6 | const suite = new Benchmark.Suite('rsa') 7 | 8 | const keys = [] 9 | const bits = [1024, 2048, 4096] 10 | 11 | bits.forEach((bit) => { 12 | suite.add(`generateKeyPair ${bit}bits`, async (d) => { 13 | const key = await crypto.keys.generateKeyPair('RSA', bit) 14 | keys.push(key) 15 | d.resolve() 16 | }, { 17 | defer: true 18 | }) 19 | }) 20 | 21 | suite.add('sign and verify', async (d) => { 22 | const key = keys[0] 23 | const text = key.genSecret() 24 | 25 | const sig = await key.sign(text) 26 | const res = await key.public.verify(text, sig) 27 | 28 | if (res !== true) { throw new Error('failed to verify') } 29 | d.resolve() 30 | }, { 31 | defer: true 32 | }) 33 | 34 | suite 35 | .on('cycle', (event) => console.log(String(event.target))) 36 | .run({ async: true }) 37 | -------------------------------------------------------------------------------- /packages/crypto/src/ciphers/index.ts: -------------------------------------------------------------------------------- 1 | export * as AES_GCM from './aes-gcm.js' 2 | -------------------------------------------------------------------------------- /packages/crypto/src/ciphers/interface.ts: -------------------------------------------------------------------------------- 1 | export interface CreateAESCipherOptions { 2 | algorithm?: string 3 | nonceLength?: number 4 | keyLength?: number 5 | digest?: string 6 | saltLength?: number 7 | iterations?: number 8 | algorithmTagLength?: number 9 | } 10 | 11 | export interface AESCipher { 12 | encrypt(data: Uint8Array, password: string | Uint8Array): Promise 13 | decrypt(data: Uint8Array, password: string | Uint8Array): Promise 14 | } 15 | -------------------------------------------------------------------------------- /packages/crypto/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Signing a message failed 3 | */ 4 | export class SigningError extends Error { 5 | constructor (message = 'An error occurred while signing a message') { 6 | super(message) 7 | this.name = 'SigningError' 8 | } 9 | } 10 | 11 | /** 12 | * Verifying a message signature failed 13 | */ 14 | export class VerificationError extends Error { 15 | constructor (message = 'An error occurred while verifying a message') { 16 | super(message) 17 | this.name = 'VerificationError' 18 | } 19 | } 20 | 21 | /** 22 | * WebCrypto was not available in the current context 23 | */ 24 | export class WebCryptoMissingError extends Error { 25 | constructor (message = 'Missing Web Crypto API') { 26 | super(message) 27 | this.name = 'WebCryptoMissingError' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/crypto/src/hmac/index.browser.ts: -------------------------------------------------------------------------------- 1 | import webcrypto from '../webcrypto/index.js' 2 | import lengths from './lengths.js' 3 | 4 | const hashTypes = { 5 | SHA1: 'SHA-1', 6 | SHA256: 'SHA-256', 7 | SHA512: 'SHA-512' 8 | } 9 | 10 | const sign = async (key: CryptoKey, data: Uint8Array): Promise => { 11 | const buf = await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data) 12 | return new Uint8Array(buf, 0, buf.byteLength) 13 | } 14 | 15 | export async function create (hashType: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise<{ digest(data: Uint8Array): Promise, length: number }> { 16 | const hash = hashTypes[hashType] 17 | 18 | const key = await webcrypto.get().subtle.importKey( 19 | 'raw', 20 | secret, 21 | { 22 | name: 'HMAC', 23 | hash: { name: hash } 24 | }, 25 | false, 26 | ['sign'] 27 | ) 28 | 29 | return { 30 | async digest (data: Uint8Array) { 31 | return sign(key, data) 32 | }, 33 | length: lengths[hashType] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/crypto/src/hmac/lengths.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | SHA1: 20, 3 | SHA256: 32, 4 | SHA512: 64 5 | } 6 | -------------------------------------------------------------------------------- /packages/crypto/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * 4 | * The `libp2p-crypto` library depends on the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in the browser. Web Crypto is available in all modern browsers, however browsers restrict its usage to [Secure Contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). 5 | * 6 | * This means you will not be able to use some `@libp2p/crypto` functions in the browser when the page is served over HTTP.* 7 | * 8 | * To enable the Web Crypto API and allow `@libp2p/crypto` to work fully, please serve your page over HTTPS. 9 | */ 10 | 11 | import * as hmac from './hmac/index.js' 12 | import * as keys from './keys/index.js' 13 | import pbkdf2 from './pbkdf2.js' 14 | import randomBytes from './random-bytes.js' 15 | 16 | export { hmac } 17 | export { keys } 18 | export { randomBytes } 19 | export { pbkdf2 } 20 | -------------------------------------------------------------------------------- /packages/crypto/src/keys/ephemeral-keys.ts: -------------------------------------------------------------------------------- 1 | import { generateEphemeralKeyPair } from './ecdh/index.js' 2 | 3 | /** 4 | * Generates an ephemeral public key and returns a function that will compute 5 | * the shared secret key. 6 | * 7 | * Focuses only on ECDH now, but can be made more general in the future. 8 | */ 9 | export default generateEphemeralKeyPair 10 | -------------------------------------------------------------------------------- /packages/crypto/src/keys/interface.ts: -------------------------------------------------------------------------------- 1 | export interface JWKKeyPair { 2 | privateKey: JsonWebKey 3 | publicKey: JsonWebKey 4 | } 5 | 6 | export interface Uint8ArrayKeyPair { 7 | privateKey: Uint8Array 8 | publicKey: Uint8Array 9 | } 10 | 11 | export interface ECDHKeyPair { 12 | private: Uint8Array 13 | public: Uint8Array 14 | } 15 | 16 | export interface ECDHKey { 17 | key: Uint8Array 18 | genSharedKey(theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise 19 | } 20 | 21 | export interface JWKEncodedPublicKey { kty: string, crv: 'P-256' | 'P-384' | 'P-521', x: string, y: string, ext: boolean } 22 | 23 | export interface JWKEncodedPrivateKey extends JWKEncodedPublicKey { d: string } 24 | 25 | export interface EnhancedKey { 26 | iv: Uint8Array 27 | cipherKey: Uint8Array 28 | macKey: Uint8Array 29 | } 30 | 31 | export interface EnhancedKeyPair { 32 | k1: EnhancedKey 33 | k2: EnhancedKey 34 | } 35 | -------------------------------------------------------------------------------- /packages/crypto/src/random-bytes.ts: -------------------------------------------------------------------------------- 1 | import { InvalidParametersError } from '@libp2p/interface' 2 | import { randomBytes as randB } from '@noble/hashes/utils' 3 | 4 | /** 5 | * Generates a Uint8Array with length `number` populated by random bytes 6 | */ 7 | export default function randomBytes (length: number): Uint8Array { 8 | if (isNaN(length) || length <= 0) { 9 | throw new InvalidParametersError('random bytes length must be a Number bigger than 0') 10 | } 11 | return randB(length) 12 | } 13 | -------------------------------------------------------------------------------- /packages/crypto/src/util.ts: -------------------------------------------------------------------------------- 1 | import { concat as uint8ArrayConcat } from 'uint8arrays/concat' 2 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 3 | 4 | export function base64urlToBuffer (str: string, len?: number): Uint8Array { 5 | let buf = uint8ArrayFromString(str, 'base64urlpad') 6 | 7 | if (len != null) { 8 | if (buf.length > len) { 9 | throw new Error('byte array longer than desired length') 10 | } 11 | 12 | buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf]) 13 | } 14 | 15 | return buf 16 | } 17 | 18 | export function isPromise (thing: any): thing is Promise { 19 | if (thing == null) { 20 | return false 21 | } 22 | 23 | return typeof thing.then === 'function' && 24 | typeof thing.catch === 'function' && 25 | typeof thing.finally === 'function' 26 | } 27 | -------------------------------------------------------------------------------- /packages/crypto/src/webcrypto/index.ts: -------------------------------------------------------------------------------- 1 | import webcrypto from './webcrypto.js' 2 | 3 | export default webcrypto 4 | -------------------------------------------------------------------------------- /packages/crypto/src/webcrypto/webcrypto.browser.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import { WebCryptoMissingError } from '../errors.js' 4 | 5 | // Check native crypto exists and is enabled (In insecure context `self.crypto` 6 | // exists but `self.crypto.subtle` does not). 7 | export default { 8 | get (win = globalThis) { 9 | const nativeCrypto = win.crypto 10 | 11 | if (nativeCrypto?.subtle == null) { 12 | throw new WebCryptoMissingError( 13 | 'Missing Web Crypto API. ' + 14 | 'The most likely cause of this error is that this page is being accessed ' + 15 | 'from an insecure context (i.e. not HTTPS). For more information and ' + 16 | 'possible resolutions see ' + 17 | 'https://github.com/libp2p/js-libp2p/blob/main/packages/crypto/README.md#web-crypto-api' 18 | ) 19 | } 20 | 21 | return nativeCrypto 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/crypto/src/webcrypto/webcrypto.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import { webcrypto } from 'crypto' 4 | 5 | // globalThis `SubtleCrypto` shipped in node.js 19.x, Electron currently uses 6 | // v18.x so this override file is necessary until Electron updates 7 | export default { 8 | get (win = globalThis) { 9 | return webcrypto 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/crypto/test/fixtures/ecdsa.ts: -------------------------------------------------------------------------------- 1 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 2 | 3 | export default { 4 | // protobuf marshaled key pair generated with libp2p-crypto-ecdsa 5 | // and marshaled with libp2p-crypto.marshalPublicKey / marshalPrivateKey 6 | pbmPrivateKey: uint8ArrayFromString('08031279307702010104203E5B1FE9712E6C314942A750BD67485DE3C1EFE85B1BFB520AE8F9AE3DFA4A4CA00A06082A8648CE3D030107A14403420004DE3D300FA36AE0E8F5D530899D83ABAB44ABF3161F162A4BC901D8E6ECDA020E8B6D5F8DA30525E71D6851510C098E5C47C646A597FB4DCEC034E9F77C409E62', 'base16upper'), 7 | pbmPublicKey: uint8ArrayFromString('0803125b3059301306072a8648ce3d020106082a8648ce3d03010703420004de3d300fa36ae0e8f5d530899d83abab44abf3161f162a4bc901d8e6ecda020e8b6d5f8da30525e71d6851510c098e5c47c646a597fb4dcec034e9f77c409e62', 'base16') 8 | } 9 | -------------------------------------------------------------------------------- /packages/crypto/test/fixtures/secp256k1.ts: -------------------------------------------------------------------------------- 1 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 2 | 3 | export default { 4 | // protobuf marshaled key pair generated with libp2p-crypto-secp256k1 5 | // and marshaled with libp2p-crypto.marshalPublicKey / marshalPrivateKey 6 | pbmPrivateKey: uint8ArrayFromString('08021220e0600103010000000100000000000000be1dc82c2e000000e8d6030301000000', 'base16'), 7 | pbmPublicKey: uint8ArrayFromString('0802122103a9a7272a726fa083abf31ba44037f8347fbc5e5d3113d62a7c6bc26752fd8ee1', 'base16') 8 | } 9 | -------------------------------------------------------------------------------- /packages/crypto/test/hmac/hmac.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint max-nested-callbacks: ["error", 8] */ 2 | /* eslint-env mocha */ 3 | import { expect } from 'aegir/chai' 4 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 5 | import * as crypto from '../../src/index.js' 6 | 7 | const hashes = ['SHA1', 'SHA256', 'SHA512'] as ['SHA1', 'SHA256', 'SHA512'] 8 | 9 | describe('HMAC', () => { 10 | hashes.forEach((hash) => { 11 | it(`${hash} - sign and verify`, async () => { 12 | const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret')) 13 | const sig = await hmac.digest(uint8ArrayFromString('hello world')) 14 | expect(sig).to.have.length(hmac.length) 15 | }) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /packages/crypto/test/random-bytes.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | import { expect } from 'aegir/chai' 3 | import randomBytes from '../src/random-bytes.js' 4 | 5 | describe('randomBytes', () => { 6 | it('produces random bytes', () => { 7 | expect(randomBytes(16)).to.have.length(16) 8 | }) 9 | 10 | it('throws if length is 0', () => { 11 | expect(() => randomBytes(0)).to.throw(Error).with.property('name', 'InvalidParametersError') 12 | }) 13 | 14 | it('throws if length is < 0', () => { 15 | expect(() => randomBytes(-1)).to.throw(Error).with.property('name', 'InvalidParametersError') 16 | }) 17 | 18 | it('throws if length is not a number', () => { 19 | // @ts-expect-error invalid params 20 | expect(() => randomBytes('hi')).to.throw(Error).with.property('name', 'InvalidParametersError') 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /packages/crypto/test/util.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint max-nested-callbacks: ["error", 8] */ 2 | /* eslint-env mocha */ 3 | import { expect } from 'aegir/chai' 4 | import * as util from '../src/util.js' 5 | 6 | describe('Util', () => { 7 | it('should convert base64url encoded string to Uint8Array with padding', () => { 8 | const buf = util.base64urlToBuffer('AP8', 2) 9 | expect(Uint8Array.from([0, 255])).to.eql(buf) 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /packages/crypto/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/crypto/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts", 5 | "./src/ciphers/index.ts", 6 | "./src/hmac/index.ts", 7 | "./src/keys/index.ts", 8 | "./src/webcrypto/index.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/integration-tests/LICENSE: -------------------------------------------------------------------------------- 1 | This project is dual licensed under MIT and Apache-2.0. 2 | 3 | MIT: https://www.opensource.org/licenses/mit 4 | Apache-2.0: https://www.apache.org/licenses/license-2.0 5 | -------------------------------------------------------------------------------- /packages/integration-tests/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 2 | 3 | http://www.apache.org/licenses/LICENSE-2.0 4 | 5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 6 | -------------------------------------------------------------------------------- /packages/integration-tests/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * 4 | * The tests in this module ensure the various parts of libp2p work together as intended. 5 | * 6 | * They generally require starting one or more libp2p nodes so are here to prevent circular dependencies forming between modules. 7 | */ 8 | 9 | export {} 10 | -------------------------------------------------------------------------------- /packages/integration-tests/test/compliance/connection-encryption/plaintext.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { generateKeyPair } from '@libp2p/crypto/keys' 4 | import suite from '@libp2p/interface-compliance-tests/connection-encryption' 5 | import { defaultLogger } from '@libp2p/logger' 6 | import { plaintext } from '@libp2p/plaintext' 7 | 8 | describe('plaintext connection encrypter interface compliance', () => { 9 | suite({ 10 | async setup (opts) { 11 | return plaintext()({ 12 | privateKey: opts?.privateKey ?? await generateKeyPair('Ed25519'), 13 | logger: defaultLogger() 14 | }) 15 | }, 16 | async teardown () { 17 | 18 | } 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /packages/integration-tests/test/compliance/connection-encryption/tls.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { generateKeyPair } from '@libp2p/crypto/keys' 4 | import suite from '@libp2p/interface-compliance-tests/connection-encryption' 5 | import { defaultLogger } from '@libp2p/logger' 6 | import { tls } from '@libp2p/tls' 7 | import { stubInterface } from 'sinon-ts' 8 | import { isBrowser, isWebWorker } from 'wherearewe' 9 | import type { StreamMuxerFactory, Upgrader } from '@libp2p/interface' 10 | 11 | describe('tls connection encrypter interface compliance', () => { 12 | if (isBrowser || isWebWorker) { 13 | return 14 | } 15 | 16 | suite({ 17 | async setup (opts) { 18 | return tls()({ 19 | privateKey: opts?.privateKey ?? await generateKeyPair('Ed25519'), 20 | logger: defaultLogger(), 21 | upgrader: stubInterface({ 22 | getStreamMuxers () { 23 | return new Map([['/test/muxer', stubInterface()]]) 24 | } 25 | }) 26 | }) 27 | }, 28 | async teardown () { 29 | 30 | } 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /packages/integration-tests/test/fixtures/slow-muxer.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { yamux } from '@chainsafe/libp2p-yamux' 4 | import delay from 'delay' 5 | import map from 'it-map' 6 | import type { StreamMuxerFactory } from '@libp2p/interface' 7 | 8 | /** 9 | * Creates a muxer with a delay between each sent packet 10 | */ 11 | export function slowMuxer (packetDelay: number): ((components: any) => StreamMuxerFactory) { 12 | return (components) => { 13 | const muxerFactory = yamux()(components) 14 | const originalCreateStreamMuxer = muxerFactory.createStreamMuxer.bind(muxerFactory) 15 | 16 | muxerFactory.createStreamMuxer = (init) => { 17 | const muxer = originalCreateStreamMuxer(init) 18 | muxer.source = map(muxer.source, async (buf) => { 19 | await delay(packetDelay) 20 | return buf 21 | }) 22 | 23 | return muxer 24 | } 25 | 26 | return muxerFactory 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/integration-tests/test/lifecycle.spec.ts: -------------------------------------------------------------------------------- 1 | import { multiaddr } from '@multiformats/multiaddr' 2 | import { createLibp2p } from 'libp2p' 3 | import { createBaseOptions } from './fixtures/base-options.js' 4 | import type { Libp2p } from '@libp2p/interface' 5 | 6 | describe('life cycle', () => { 7 | let peer: Libp2p 8 | 9 | afterEach(async () => { 10 | await peer?.stop() 11 | }) 12 | 13 | it('can dial a node after restarting', async () => { 14 | const ma = multiaddr(process.env.RELAY_MULTIADDR) 15 | 16 | peer = await createLibp2p(createBaseOptions()) 17 | 18 | await peer.dial(ma) 19 | 20 | // stop and restart peer 21 | await peer.stop() 22 | await peer.start() 23 | 24 | // once started, attempt to dial again 25 | await peer.dial(ma) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /packages/integration-tests/test/node.ts: -------------------------------------------------------------------------------- 1 | import './circuit-relay-discovery.node.js' 2 | import './circuit-relay.node.js' 3 | import './dcutr.node.js' 4 | import './identify.node.js' 5 | import './mdns.node.js' 6 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/connection-encryption/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { logger } from '@libp2p/logger' 2 | import { multiaddr } from '@multiformats/multiaddr' 3 | import { duplexPair } from 'it-pair/duplex' 4 | import type { MultiaddrConnection } from '@libp2p/interface' 5 | import type { Duplex, Source } from 'it-stream-types' 6 | import type { Uint8ArrayList } from 'uint8arraylist' 7 | 8 | export function createMaConnPair (): [MultiaddrConnection, MultiaddrConnection] { 9 | const [local, remote] = duplexPair() 10 | 11 | function duplexToMaConn (duplex: Duplex, Source, Promise>): MultiaddrConnection { 12 | const output: MultiaddrConnection = { 13 | ...duplex, 14 | close: async () => {}, 15 | abort: () => {}, 16 | remoteAddr: multiaddr('/ip4/127.0.0.1/tcp/4001'), 17 | timeline: { 18 | open: Date.now() 19 | }, 20 | log: logger('duplex-maconn') 21 | } 22 | 23 | return output 24 | } 25 | 26 | return [duplexToMaConn(local), duplexToMaConn(remote)] 27 | } 28 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/index.ts: -------------------------------------------------------------------------------- 1 | export interface TestSetup> { 2 | setup(args?: SetupArgs): Promise 3 | teardown(): Promise 4 | } 5 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/is-valid-tick.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A tick is considered valid if it happened between now 3 | * and `ms` milliseconds ago 4 | */ 5 | export function isValidTick (date?: number, ms: number = 5000): boolean { 6 | if (date == null) { 7 | throw new Error('date must be a number') 8 | } 9 | 10 | const now = Date.now() 11 | 12 | if (date > now - ms && date <= now) { 13 | return true 14 | } 15 | 16 | return false 17 | } 18 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/matchers.ts: -------------------------------------------------------------------------------- 1 | import Sinon from 'sinon' 2 | import type { PeerId } from '@libp2p/interface' 3 | import type { Multiaddr } from '@multiformats/multiaddr' 4 | import type { SinonMatcher } from 'sinon' 5 | 6 | /** 7 | * @deprecated PeerIds can be passed to sinon matchers directly 8 | */ 9 | export function matchPeerId (peerId: PeerId): SinonMatcher { 10 | return Sinon.match(p => p.toString() === peerId.toString()) 11 | } 12 | 13 | /** 14 | * @deprecated Multiaddrs can be passed to sinon matchers directly 15 | */ 16 | export function matchMultiaddr (ma: Multiaddr): SinonMatcher { 17 | return Sinon.match(m => m.toString() === ma.toString()) 18 | } 19 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/mocks/duplex.ts: -------------------------------------------------------------------------------- 1 | import type { Duplex, Source } from 'it-stream-types' 2 | import type { Uint8ArrayList } from 'uint8arraylist' 3 | 4 | export function mockDuplex (): Duplex, Source, Promise> { 5 | return { 6 | source: (async function * () { 7 | yield * [] 8 | }()), 9 | sink: async () => {} 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/mocks/index.ts: -------------------------------------------------------------------------------- 1 | export { mockConnectionManager, mockNetwork } from './connection-manager.js' 2 | export { mockConnection, mockStream, streamPair, connectionPair } from './connection.js' 3 | export { mockMultiaddrConnection, mockMultiaddrConnPair } from './multiaddr-connection.js' 4 | export { mockMuxer } from './muxer.js' 5 | export { mockRegistrar } from './registrar.js' 6 | export { mockUpgrader } from './upgrader.js' 7 | export { mockDuplex } from './duplex.js' 8 | export type { MockUpgraderInit } from './upgrader.js' 9 | export type { MockNetworkComponents, MockConnectionManagerComponents, MockNetwork } from './connection-manager.js' 10 | export type { MockConnectionOptions, StreamInit, StreamPairInit } from './connection.js' 11 | export type { MockMultiaddrConnPairOptions } from './multiaddr-connection.js' 12 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/stream-muxer/fixtures/pb/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Message { 4 | string message = 1; 5 | uint32 value = 2; 6 | bool flag = 3; 7 | } 8 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/stream-muxer/index.ts: -------------------------------------------------------------------------------- 1 | import baseTest from './base-test.js' 2 | import closeTest from './close-test.js' 3 | import megaStressTest from './mega-stress-test.js' 4 | import stressTest from './stress-test.js' 5 | import type { TestSetup } from '../index.js' 6 | import type { StreamMuxerFactory } from '@libp2p/interface' 7 | 8 | export default (common: TestSetup): void => { 9 | describe('interface-stream-muxer', () => { 10 | baseTest(common) 11 | closeTest(common) 12 | stressTest(common) 13 | megaStressTest(common) 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/src/stream-muxer/mega-stress-test.ts: -------------------------------------------------------------------------------- 1 | import spawn from './spawner.js' 2 | import type { TestSetup } from '../index.js' 3 | import type { StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface' 4 | 5 | export default (common: TestSetup): void => { 6 | const createMuxer = async (init?: StreamMuxerInit): Promise => { 7 | const factory = await common.setup() 8 | return factory.createStreamMuxer(init) 9 | } 10 | 11 | describe.skip('mega stress test', function () { 12 | it('10,000 streams with 10,000 msg', async () => { await spawn(createMuxer, 10000, 10000, 5000) }) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/test/mocks/muxer.spec.ts: -------------------------------------------------------------------------------- 1 | import { mockMuxer } from '../../src/mocks/muxer.js' 2 | import tests from '../../src/stream-muxer/index.js' 3 | 4 | describe('mock stream muxer compliance tests', () => { 5 | tests({ 6 | async setup () { 7 | return mockMuxer() 8 | }, 9 | async teardown () { 10 | 11 | } 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../connection-encrypter-plaintext" 13 | }, 14 | { 15 | "path": "../crypto" 16 | }, 17 | { 18 | "path": "../interface" 19 | }, 20 | { 21 | "path": "../interface-internal" 22 | }, 23 | { 24 | "path": "../libp2p" 25 | }, 26 | { 27 | "path": "../logger" 28 | }, 29 | { 30 | "path": "../multistream-select" 31 | }, 32 | { 33 | "path": "../peer-collections" 34 | }, 35 | { 36 | "path": "../peer-id" 37 | }, 38 | { 39 | "path": "../protocol-echo" 40 | }, 41 | { 42 | "path": "../transport-memory" 43 | }, 44 | { 45 | "path": "../utils" 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /packages/interface-compliance-tests/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts", 5 | "./src/connection-encryption/index.ts", 6 | "./src/is-valid-tick.ts", 7 | "./src/matchers.ts", 8 | "./src/mocks/index.ts", 9 | "./src/peer-discovery/index.ts", 10 | "./src/pubsub/index.ts", 11 | "./src/stream-muxer/index.ts", 12 | "./src/transport/index.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/interface-internal/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/interface-internal/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * 4 | * This module serves as the entry point for `@libp2p/interface-internal`, 5 | * exporting key components such as `AddressManager`, `ConnectionManager`, 6 | * `RandomWalk`, `Registrar`, and `TransportManager`. 7 | * 8 | * These interfaces and classes define the core internal behaviors of libp2p. 9 | */ 10 | 11 | export * from './address-manager.js' 12 | export * from './connection-manager.js' 13 | export * from './random-walk.js' 14 | export * from './registrar.js' 15 | export * from './transport-manager.js' 16 | -------------------------------------------------------------------------------- /packages/interface-internal/src/random-walk.ts: -------------------------------------------------------------------------------- 1 | import type { AbortOptions, PeerInfo } from '@libp2p/interface' 2 | 3 | /** 4 | * The `RandomWalk` component uses the libp2p peer routing to find arbitrary 5 | * network peers. Consumers may then dial these peers, causing the Identify 6 | * protocol to run and any registered topologies to be notified of their 7 | * supported protocols. 8 | */ 9 | export interface RandomWalk { 10 | /** 11 | * Initiates a random walk for peer discovery. 12 | * 13 | * This method either begins a new random walk or joins an existing one. The process 14 | * continues to find and return random peers until it is aborted. 15 | * 16 | * @param options - Optional `AbortOptions` to allow early termination of the walk. 17 | * @returns An `AsyncGenerator` that yields discovered `PeerInfo` objects. 18 | */ 19 | walk(options?: AbortOptions): AsyncGenerator 20 | } 21 | -------------------------------------------------------------------------------- /packages/interface-internal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src" 8 | ], 9 | "references": [ 10 | { 11 | "path": "../interface" 12 | }, 13 | { 14 | "path": "../peer-collections" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/interface-internal/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/interface/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/interface/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/interface/src/events.browser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Noop for browser compatibility 3 | */ 4 | export function setMaxListeners (): void {} 5 | -------------------------------------------------------------------------------- /packages/interface/src/events.ts: -------------------------------------------------------------------------------- 1 | import { setMaxListeners as nodeSetMaxListeners } from 'node:events' 2 | 3 | /** 4 | * Create a setMaxListeners that doesn't break browser usage 5 | */ 6 | export const setMaxListeners: typeof nodeSetMaxListeners = (n, ...eventTargets) => { 7 | try { 8 | nodeSetMaxListeners(n, ...eventTargets) 9 | } catch { 10 | // swallow error, gulp 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/interface/src/peer-info.ts: -------------------------------------------------------------------------------- 1 | import type { PeerId } from './peer-id.js' 2 | import type { Multiaddr } from '@multiformats/multiaddr' 3 | 4 | /** 5 | * A `PeerInfo` is a lightweight object that represents a remote peer, it can be 6 | * obtained from peer discovery mechanisms, HTTP RPC endpoints, etc. 7 | * 8 | * @see https://docs.libp2p.io/concepts/fundamentals/peers/#peer-info 9 | */ 10 | export interface PeerInfo { 11 | /** 12 | * The identifier of the remote peer 13 | */ 14 | id: PeerId 15 | 16 | /** 17 | * The multiaddrs a peer is listening on 18 | */ 19 | multiaddrs: Multiaddr[] 20 | } 21 | -------------------------------------------------------------------------------- /packages/interface/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/interface/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/kad-dht/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '160KB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/kad-dht/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/kad-dht/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/kad-dht/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An error occurred during a query 3 | */ 4 | export class QueryError extends Error { 5 | constructor (message = 'Query error') { 6 | super(message) 7 | this.name = 'QueryError' 8 | } 9 | } 10 | 11 | /** 12 | * An invalid record was received 13 | */ 14 | export class InvalidRecordError extends Error { 15 | constructor (message = 'Invalid record') { 16 | super(message) 17 | this.name = 'InvalidRecordError' 18 | } 19 | } 20 | 21 | /** 22 | * A selector function was missing 23 | */ 24 | export class MissingSelectorError extends Error { 25 | constructor (message = 'No selector function configured for prefix') { 26 | super(message) 27 | this.name = 'MissingSelectorError' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/kad-dht/src/message/utils.ts: -------------------------------------------------------------------------------- 1 | import { peerIdFromMultihash } from '@libp2p/peer-id' 2 | import { multiaddr } from '@multiformats/multiaddr' 3 | import * as Digest from 'multiformats/hashes/digest' 4 | import type { PeerInfo as PBPeerInfo, ConnectionType } from './dht.js' 5 | import type { PeerInfo } from '@libp2p/interface' 6 | 7 | export function toPbPeerInfo (peer: PeerInfo, connection?: ConnectionType): PBPeerInfo { 8 | const output: PBPeerInfo = { 9 | id: peer.id.toMultihash().bytes, 10 | multiaddrs: (peer.multiaddrs ?? []).map((m) => m.bytes), 11 | connection 12 | } 13 | 14 | return output 15 | } 16 | 17 | export function fromPbPeerInfo (peer: PBPeerInfo): PeerInfo { 18 | if (peer.id == null) { 19 | throw new Error('Invalid peer in message') 20 | } 21 | 22 | const multihash = Digest.decode(peer.id) 23 | 24 | return { 25 | id: peerIdFromMultihash(multihash), 26 | multiaddrs: (peer.multiaddrs ?? []).map((a) => multiaddr(a)) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/kad-dht/src/query/types.ts: -------------------------------------------------------------------------------- 1 | import type { DisjointPath, QueryEvent } from '../index.js' 2 | import type { PeerInfo } from '@libp2p/interface' 3 | 4 | export interface QueryContext { 5 | // the key we are looking up 6 | key: Uint8Array 7 | // the current peer being queried 8 | peer: PeerInfo 9 | // the KAD ID of the peer being queried 10 | peerKadId: Uint8Array 11 | // if this signal emits an 'abort' event, any long-lived processes or requests started as part of this query should be terminated 12 | signal?: AbortSignal 13 | // which disjoint path we are following 14 | path: DisjointPath 15 | // the total number of disjoint paths being executed 16 | numPaths: number 17 | } 18 | 19 | /** 20 | * Query function 21 | */ 22 | export interface QueryFunc { 23 | (context: QueryContext): AsyncIterable 24 | } 25 | -------------------------------------------------------------------------------- /packages/kad-dht/src/rpc/handlers/ping.ts: -------------------------------------------------------------------------------- 1 | import type { Message } from '../../message/dht.js' 2 | import type { DHTMessageHandler } from '../index.js' 3 | import type { ComponentLogger, Logger, PeerId } from '@libp2p/interface' 4 | 5 | export interface PingComponents { 6 | logger: ComponentLogger 7 | } 8 | 9 | export interface PingHandlerInit { 10 | logPrefix: string 11 | } 12 | 13 | export class PingHandler implements DHTMessageHandler { 14 | private readonly log: Logger 15 | 16 | constructor (components: PingComponents, init: PingHandlerInit) { 17 | this.log = components.logger.forComponent(`${init.logPrefix}:rpc:handlers:ping`) 18 | } 19 | 20 | async handle (peerId: PeerId, msg: Message): Promise { 21 | this.log('ping from %p', peerId) 22 | return msg 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-1: -------------------------------------------------------------------------------- 1 | /v/helloP -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-2 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-3: -------------------------------------------------------------------------------- 1 | /v/helloP -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-4 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-5 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-6 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-7 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/msg-8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/kad-dht/test/fixtures/msg-8 -------------------------------------------------------------------------------- /packages/kad-dht/test/fixtures/record/go-key-records.ts: -------------------------------------------------------------------------------- 1 | import { base64pad } from 'multiformats/bases/base64' 2 | 3 | export const publicKey = base64pad.decode( 4 | 'MCAASXjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDjXAQQMal4SB2tSnX6NJIPmC69/BT8A8jc7/gDUZNkEhdhYHvc7k7S4vntV/c92nJGxNdop9fKJyevuNMuXhhHAgMBAAE=' 5 | ) 6 | -------------------------------------------------------------------------------- /packages/kad-dht/test/generate-peers/.gitignore: -------------------------------------------------------------------------------- 1 | generate-peer 2 | -------------------------------------------------------------------------------- /packages/kad-dht/test/utils/create-peer-id.ts: -------------------------------------------------------------------------------- 1 | import { generateKeyPair } from '@libp2p/crypto/keys' 2 | import { peerIdFromPrivateKey } from '@libp2p/peer-id' 3 | import type { PeerId, PrivateKey } from '@libp2p/interface' 4 | 5 | export interface PeerAndKey { 6 | peerId: PeerId 7 | privateKey: PrivateKey 8 | } 9 | 10 | /** 11 | * Creates multiple PeerIds with private keys 12 | */ 13 | export async function createPeerIdsWithPrivateKey (length: number): Promise { 14 | return Promise.all( 15 | new Array(length).fill(0).map(async () => createPeerIdWithPrivateKey()) 16 | ) 17 | } 18 | 19 | /** 20 | * Creates a PeerId with a private key 21 | */ 22 | export async function createPeerIdWithPrivateKey (): Promise { 23 | const privateKey = await generateKeyPair('Ed25519') 24 | const peerId = peerIdFromPrivateKey(privateKey) 25 | 26 | return { 27 | peerId, 28 | privateKey 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/kad-dht/test/utils/create-values.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes } from '@libp2p/crypto' 2 | import { CID } from 'multiformats/cid' 3 | import * as raw from 'multiformats/codecs/raw' 4 | import { sha256 } from 'multiformats/hashes/sha2' 5 | 6 | export interface Value { 7 | cid: CID 8 | value: Uint8Array 9 | } 10 | 11 | export async function createValues (length: number): Promise { 12 | return Promise.all( 13 | Array.from({ length }).map(async () => { 14 | const bytes = randomBytes(32) 15 | const h = await sha256.digest(bytes) 16 | return { 17 | cid: CID.createV1(raw.code, h), 18 | value: bytes 19 | } 20 | }) 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /packages/kad-dht/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../interface-internal" 22 | }, 23 | { 24 | "path": "../logger" 25 | }, 26 | { 27 | "path": "../peer-collections" 28 | }, 29 | { 30 | "path": "../peer-id" 31 | }, 32 | { 33 | "path": "../peer-store" 34 | }, 35 | { 36 | "path": "../protocol-ping" 37 | }, 38 | { 39 | "path": "../record" 40 | }, 41 | { 42 | "path": "../utils" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /packages/kad-dht/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/keychain/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/keychain/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/keychain/doc/private-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/keychain/doc/private-key.png -------------------------------------------------------------------------------- /packages/keychain/src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const SALT_LENGTH = 16 2 | export const KEY_SIZE = 32 3 | export const ITERATIONS = 10000 4 | -------------------------------------------------------------------------------- /packages/keychain/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../logger" 19 | }, 20 | { 21 | "path": "../utils" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/keychain/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/libp2p/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '95KB' 5 | }, 6 | dependencyCheck: { 7 | ignore: [ 8 | 'react-native' 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/libp2p/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/libp2p/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/libp2p/scripts/update-version.js: -------------------------------------------------------------------------------- 1 | import { readFile, writeFile } from 'fs/promises' 2 | 3 | const pkg = JSON.parse( 4 | await readFile( 5 | new URL('../package.json', import.meta.url) 6 | ) 7 | ) 8 | 9 | await writeFile( 10 | new URL('../src/version.ts', import.meta.url), 11 | `export const version = '${pkg.version}' 12 | export const name = 'js-${pkg.name}' 13 | ` 14 | ) 15 | -------------------------------------------------------------------------------- /packages/libp2p/src/config/connection-gater.ts: -------------------------------------------------------------------------------- 1 | import type { ConnectionGater } from '@libp2p/interface' 2 | 3 | /** 4 | * Returns a default connection gater implementation that allows everything 5 | */ 6 | export function connectionGater (gater: ConnectionGater = {}): ConnectionGater { 7 | return { 8 | denyDialPeer: async () => false, 9 | denyDialMultiaddr: async () => false, 10 | denyInboundConnection: async () => false, 11 | denyOutboundConnection: async () => false, 12 | denyInboundEncryptedConnection: async () => false, 13 | denyOutboundEncryptedConnection: async () => false, 14 | denyInboundUpgradedConnection: async () => false, 15 | denyOutboundUpgradedConnection: async () => false, 16 | filterMultiaddrForPeer: async () => true, 17 | ...gater 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/libp2p/src/connection-manager/constants.browser.ts: -------------------------------------------------------------------------------- 1 | export * from './constants.defaults.js' 2 | 3 | /** 4 | * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections 5 | */ 6 | export const MAX_CONNECTIONS = 100 7 | 8 | /** 9 | * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials 10 | */ 11 | export const MAX_PARALLEL_DIALS = 50 12 | -------------------------------------------------------------------------------- /packages/libp2p/src/connection-manager/constants.ts: -------------------------------------------------------------------------------- 1 | export * from './constants.defaults.js' 2 | 3 | /** 4 | * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections 5 | */ 6 | export const MAX_CONNECTIONS = 300 7 | 8 | /** 9 | * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials 10 | */ 11 | export const MAX_PARALLEL_DIALS = 100 12 | -------------------------------------------------------------------------------- /packages/libp2p/src/user-agent.browser.ts: -------------------------------------------------------------------------------- 1 | import * as pkg from './version.js' 2 | 3 | export function userAgent (name?: string, version?: string): string { 4 | return `${name ?? pkg.name}/${version ?? pkg.version} browser/${globalThis.navigator.userAgent}` 5 | } 6 | -------------------------------------------------------------------------------- /packages/libp2p/src/user-agent.react-native.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native' 2 | import * as pkg from './version.js' 3 | 4 | export function userAgent (name?: string, version?: string): string { 5 | return `${name ?? pkg.name}/${version ?? pkg.version} react-native/${Platform.OS}-${`${Platform.Version}`.replaceAll('v', '')}` 6 | } 7 | -------------------------------------------------------------------------------- /packages/libp2p/src/user-agent.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process' 2 | import * as pkg from './version.js' 3 | 4 | export function userAgent (name?: string, version?: string): string { 5 | let platform = 'node' 6 | let platformVersion = process.versions.node 7 | 8 | if (process.versions.deno != null) { 9 | platform = 'deno' 10 | platformVersion = process.versions.deno 11 | } 12 | 13 | if (process.versions.bun != null) { 14 | platform = 'bun' 15 | platformVersion = process.versions.bun 16 | } 17 | 18 | if (process.versions.electron != null) { 19 | platform = 'electron' 20 | platformVersion = process.versions.electron 21 | } 22 | 23 | return `${name ?? pkg.name}/${version ?? pkg.version} ${platform}/${platformVersion.replaceAll('v', '')}` 24 | } 25 | -------------------------------------------------------------------------------- /packages/libp2p/src/version.ts: -------------------------------------------------------------------------------- 1 | export const version = '0.0.0' 2 | export const name = 'js-libp2p' 3 | -------------------------------------------------------------------------------- /packages/libp2p/test/connection/fixtures/pair.ts: -------------------------------------------------------------------------------- 1 | import map from 'it-map' 2 | import defer from 'p-defer' 3 | import { Uint8ArrayList } from 'uint8arraylist' 4 | import type { Source, Duplex } from 'it-stream-types' 5 | 6 | /** 7 | * A pair of streams where one drains from the other 8 | */ 9 | export function pair (): Duplex, Source, Promise> { 10 | const deferred = defer>() 11 | let piped = false 12 | 13 | return { 14 | sink: async source => { 15 | if (piped) { 16 | throw new Error('already piped') 17 | } 18 | 19 | piped = true 20 | deferred.resolve(source) 21 | }, 22 | source: (async function * () { 23 | const source = await deferred.promise 24 | 25 | yield * map(source, (buf) => buf instanceof Uint8Array ? new Uint8ArrayList(buf) : buf) 26 | }()) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/libp2p/test/core/events.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { expect } from 'aegir/chai' 4 | import { pEvent } from 'p-event' 5 | import { createLibp2p } from '../../src/index.js' 6 | import type { Libp2p } from '@libp2p/interface' 7 | 8 | describe('events', () => { 9 | let node: Libp2p 10 | 11 | afterEach(async () => { 12 | if (node != null) { 13 | await node.stop() 14 | } 15 | }) 16 | 17 | it('should emit a start event', async () => { 18 | node = await createLibp2p({ 19 | start: false 20 | }) 21 | 22 | const eventPromise = pEvent<'start', CustomEvent>(node, 'start') 23 | 24 | await node.start() 25 | await expect(eventPromise).to.eventually.have.property('detail', node) 26 | }) 27 | 28 | it('should emit a stop event', async () => { 29 | node = await createLibp2p() 30 | 31 | const eventPromise = pEvent<'stop', CustomEvent>(node, 'stop') 32 | 33 | await node.stop() 34 | await expect(eventPromise).to.eventually.have.property('detail', node) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/libp2p/test/core/peer-id.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { expect } from 'aegir/chai' 4 | import { createLibp2p } from '../../src/index.js' 5 | import type { Libp2p } from '../../src/index.js' 6 | 7 | describe('peer-id', () => { 8 | let libp2p: Libp2p 9 | 10 | afterEach(async () => { 11 | if (libp2p != null) { 12 | await libp2p.stop() 13 | } 14 | }) 15 | 16 | it('should create a PeerId if none is passed', async () => { 17 | libp2p = await createLibp2p() 18 | 19 | expect(libp2p.peerId).to.be.ok() 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/libp2p/test/core/status.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { stop } from '@libp2p/interface' 4 | import { expect } from 'aegir/chai' 5 | import { createLibp2p } from '../../src/index.js' 6 | import type { Libp2p } from '@libp2p/interface' 7 | 8 | describe('status', () => { 9 | let libp2p: Libp2p 10 | 11 | after(async () => { 12 | await stop(libp2p) 13 | }) 14 | 15 | it('should have status', async () => { 16 | libp2p = await createLibp2p({ 17 | start: false 18 | }) 19 | 20 | expect(libp2p).to.have.property('status', 'stopped') 21 | 22 | const startP = libp2p.start() 23 | 24 | expect(libp2p).to.have.property('status', 'starting') 25 | 26 | await startP 27 | 28 | expect(libp2p).to.have.property('status', 'started') 29 | 30 | const stopP = libp2p.stop() 31 | 32 | expect(libp2p).to.have.property('status', 'stopping') 33 | 34 | await stopP 35 | 36 | expect(libp2p).to.have.property('status', 'stopped') 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/libp2p/test/core/user-agent.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'aegir/chai' 2 | import { isNode, isElectronMain, isBrowser, isWebWorker } from 'wherearewe' 3 | import { userAgent } from '../../src/user-agent.js' 4 | 5 | describe('user-agent', () => { 6 | it('should include runtime in user agent', () => { 7 | if (isNode) { 8 | expect(userAgent()).to.include('node/') 9 | } else if (isElectronMain) { 10 | expect(userAgent()).to.include('electron/') 11 | } else if (isBrowser || isWebWorker) { 12 | expect(userAgent()).to.include('browser/') 13 | } 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/libp2p/test/fixtures/get-component.ts: -------------------------------------------------------------------------------- 1 | export function getComponent (libp2p: any, name: string): T { 2 | return libp2p.components[name] 3 | } 4 | -------------------------------------------------------------------------------- /packages/libp2p/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../multistream-select" 25 | }, 26 | { 27 | "path": "../peer-collections" 28 | }, 29 | { 30 | "path": "../peer-id" 31 | }, 32 | { 33 | "path": "../peer-store" 34 | }, 35 | { 36 | "path": "../utils" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /packages/libp2p/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts", 5 | "./src/user-agent.ts", 6 | "./src/version.ts" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/logger/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/logger/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/logger/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { PeerLoggerOptions } from './index.js' 2 | import type { PeerId } from '@libp2p/interface' 3 | 4 | export function truncatePeerId (peerId: PeerId, options: Partial = {}): string { 5 | const prefixLength = options.prefixLength ?? 2 6 | const suffixLength = options.suffixLength ?? 4 7 | 8 | const peerIdString = peerId.toString() 9 | return `${peerIdString.substring(0, prefixLength)}…${peerIdString.substring(peerIdString.length, peerIdString.length - suffixLength)}` 10 | } 11 | -------------------------------------------------------------------------------- /packages/logger/test/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { peerIdFromCID } from '@libp2p/peer-id' 2 | import { expect } from 'aegir/chai' 3 | import { CID } from 'multiformats/cid' 4 | import { truncatePeerId } from '../src/utils.js' 5 | 6 | describe('utils', () => { 7 | it('should truncate a peer id', () => { 8 | const cid = CID.parse('QmZ8eiDPqQqWR17EPxiwCDgrKPVhCHLcyn6xSCNpFAdAZb') 9 | const peerId = peerIdFromCID(cid) 10 | 11 | expect(truncatePeerId(peerId)).to.equal('Qm…dAZb') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/logger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../peer-id" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/logger/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/counter-group.ts: -------------------------------------------------------------------------------- 1 | import type { CounterGroup, StopTimer } from '@libp2p/interface' 2 | import type { UpDownCounter as OTelCounter } from '@opentelemetry/api' 3 | 4 | export class OpenTelemetryCounterGroup implements CounterGroup { 5 | private readonly label: string 6 | private readonly counter: OTelCounter 7 | 8 | constructor (label: string, counter: OTelCounter) { 9 | this.label = label 10 | this.counter = counter 11 | } 12 | 13 | update (values: Record): void { 14 | Object.entries(values).forEach(([key, value]) => { 15 | this.counter.add(value, { 16 | [this.label]: key 17 | }) 18 | }) 19 | } 20 | 21 | increment (values: Record): void { 22 | Object.entries(values).forEach(([key, value]) => { 23 | this.counter.add(value === true ? 1 : value, { 24 | [this.label]: key 25 | }) 26 | }) 27 | } 28 | 29 | reset (): void { 30 | // no-op 31 | } 32 | 33 | timer (key: string): StopTimer { 34 | return () => { 35 | // no-op 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/counter.ts: -------------------------------------------------------------------------------- 1 | import type { Counter } from '@libp2p/interface' 2 | import type { Counter as OTelCounter } from '@opentelemetry/api' 3 | 4 | export class OpenTelemetryCounter implements Counter { 5 | private readonly counter: OTelCounter 6 | 7 | constructor (counter: OTelCounter) { 8 | this.counter = counter 9 | } 10 | 11 | increment (value?: number): void { 12 | this.counter.add(value ?? 1) 13 | } 14 | 15 | reset (): void { 16 | // no-op 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/histogram-group.ts: -------------------------------------------------------------------------------- 1 | import type { HistogramGroup, StopTimer } from '@libp2p/interface' 2 | import type { Histogram as OTelHistogram } from '@opentelemetry/api' 3 | 4 | export class OpenTelemetryHistogramGroup implements HistogramGroup { 5 | private readonly label: string 6 | private readonly histogram: OTelHistogram 7 | 8 | constructor (label: string, histogram: OTelHistogram) { 9 | this.label = label 10 | this.histogram = histogram 11 | } 12 | 13 | observe (values: Record): void { 14 | Object.entries(values).forEach(([key, value]) => { 15 | this.histogram.record(value, { 16 | [this.label]: key 17 | }) 18 | }) 19 | } 20 | 21 | reset (): void { 22 | this.histogram.record(0) 23 | } 24 | 25 | timer (key: string): StopTimer { 26 | const start = Date.now() 27 | 28 | return () => { 29 | this.histogram.record(Date.now() - start, { 30 | [this.label]: key 31 | }) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/histogram.ts: -------------------------------------------------------------------------------- 1 | import type { Histogram, StopTimer } from '@libp2p/interface' 2 | import type { Histogram as OTelHistogram } from '@opentelemetry/api' 3 | 4 | export class OpenTelemetryHistogram implements Histogram { 5 | private readonly histogram: OTelHistogram 6 | 7 | constructor (histogram: OTelHistogram) { 8 | this.histogram = histogram 9 | } 10 | 11 | observe (value: number): void { 12 | this.histogram.record(value) 13 | } 14 | 15 | reset (): void { 16 | this.histogram.record(0) 17 | } 18 | 19 | timer (): StopTimer { 20 | const start = Date.now() 21 | 22 | return () => { 23 | this.observe(Date.now() - start) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/summary.ts: -------------------------------------------------------------------------------- 1 | import type { StopTimer, Summary } from '@libp2p/interface' 2 | import type { Gauge } from '@opentelemetry/api' 3 | 4 | export class OpenTelemetrySummary implements Summary { 5 | private readonly gauge: Gauge 6 | 7 | constructor (gauge: Gauge) { 8 | this.gauge = gauge 9 | } 10 | 11 | observe (value: number): void { 12 | this.gauge.record(value) 13 | } 14 | 15 | reset (): void { 16 | this.gauge.record(0) 17 | } 18 | 19 | timer (): StopTimer { 20 | const start = Date.now() 21 | 22 | return () => { 23 | this.observe(Date.now() - start) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/src/system-metrics.browser.ts: -------------------------------------------------------------------------------- 1 | export function collectSystemMetrics (): void { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test", 9 | "../../otel-test.js" 10 | ], 11 | "references": [ 12 | { 13 | "path": "../interface" 14 | }, 15 | { 16 | "path": "../utils" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /packages/metrics-opentelemetry/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundle: false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/src/utils.ts: -------------------------------------------------------------------------------- 1 | export const ONE_SECOND = 1000 2 | export const ONE_MINUTE = 60 * ONE_SECOND 3 | 4 | /** 5 | * See https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels 6 | * for rules on valid naming 7 | */ 8 | export function normalizeString (str: string): string { 9 | return str 10 | .replace(/[^a-zA-Z0-9_]/g, '_') 11 | .replace(/_+/g, '_') 12 | } 13 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/test/fixtures/random-metric-name.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Prometheus metric names are global and can only contain 3 | * a limited set of, at least /a-z_0-9/i 4 | */ 5 | export function randomMetricName (key = ''): string { 6 | return `my_metric_${key}${Math.random().toString().split('.').pop() ?? ''}` 7 | } 8 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/test/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { start, stop } from '@libp2p/interface' 2 | import { defaultLogger } from '@libp2p/logger' 3 | import { expect } from 'aegir/chai' 4 | import { prometheusMetrics } from '../src/index.js' 5 | import type { Metrics } from '@libp2p/interface' 6 | 7 | describe('simple-metrics', () => { 8 | let metrics: Metrics 9 | 10 | afterEach(async () => { 11 | if (metrics != null) { 12 | await stop(metrics) 13 | } 14 | }) 15 | 16 | it('should retain metrics after stop', async () => { 17 | metrics = prometheusMetrics()({ 18 | logger: defaultLogger() 19 | }) 20 | 21 | await start(metrics) 22 | 23 | const m1 = metrics.registerCounterGroup('test_metric') 24 | const m2 = metrics.registerCounterGroup('test_metric') 25 | 26 | expect(m1).to.equal(m2, 'did not re-use metric') 27 | 28 | await stop(metrics) 29 | 30 | await start(metrics) 31 | 32 | const m3 = metrics.registerCounterGroup('test_metric') 33 | 34 | expect(m3).to.equal(m1, 'did not re-use metric') 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/test/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'aegir/chai' 2 | import { normalizeString } from '../src/utils.js' 3 | 4 | describe('utils', () => { 5 | describe('normalizeString', () => { 6 | it('should normalize string', () => { 7 | expect(normalizeString('hello-world')).to.equal('hello_world') 8 | expect(normalizeString('hello---world')).to.equal('hello_world') 9 | expect(normalizeString('hello-world_0.0.0.0:1234-some-metric')).to.equal('hello_world_0_0_0_0_1234_some_metric') 10 | }) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/metrics-prometheus/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/metrics-simple/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/metrics-simple/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/metrics-simple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../logger" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/metrics-simple/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/multistream-select/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/multistream-select/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const PROTOCOL_ID = '/multistream/1.0.0' 2 | 3 | // Conforming to go-libp2p 4 | // See https://github.com/multiformats/go-multistream/blob/master/multistream.go#L297 5 | export const MAX_PROTOCOL_LENGTH = 1024 6 | -------------------------------------------------------------------------------- /packages/multistream-select/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../logger" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/multistream-select/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-collections/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-collections/test/filter.spec.ts: -------------------------------------------------------------------------------- 1 | import { generateKeyPair } from '@libp2p/crypto/keys' 2 | import { peerIdFromPrivateKey } from '@libp2p/peer-id' 3 | import { expect } from 'aegir/chai' 4 | import { PeerFilter } from '../src/index.js' 5 | 6 | describe('peer-filter', () => { 7 | it('should filter a peer', async () => { 8 | const filter = new PeerFilter(1024) 9 | const peer = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) 10 | 11 | expect(filter.has(peer)).to.be.false() 12 | 13 | filter.add(peer) 14 | 15 | expect(filter.has(peer)).to.be.true() 16 | 17 | filter.remove(peer) 18 | 19 | expect(filter.has(peer)).to.be.false() 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/peer-collections/test/map.spec.ts: -------------------------------------------------------------------------------- 1 | import { generateKeyPair } from '@libp2p/crypto/keys' 2 | import { peerIdFromMultihash, peerIdFromPrivateKey } from '@libp2p/peer-id' 3 | import { expect } from 'aegir/chai' 4 | import { PeerMap } from '../src/index.js' 5 | 6 | describe('peer-map', () => { 7 | it('should return a map', async () => { 8 | const map = new PeerMap() 9 | const value = 5 10 | const peer = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) 11 | 12 | map.set(peer, value) 13 | 14 | const peer2 = peerIdFromMultihash(peer.toMultihash()) 15 | 16 | expect(map.get(peer2)).to.equal(value) 17 | }) 18 | 19 | it('should create a map with contents', async () => { 20 | const map1 = new PeerMap() 21 | const value = 5 22 | const peer = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) 23 | 24 | map1.set(peer, value) 25 | 26 | const map2 = new PeerMap(map1) 27 | 28 | expect(map2.get(peer)).to.equal(value) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/peer-collections/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../peer-id" 19 | }, 20 | { 21 | "path": "../utils" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/peer-collections/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/test/compliance.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import tests from '@libp2p/interface-compliance-tests/peer-discovery' 4 | import { defaultLogger } from '@libp2p/logger' 5 | import { stubInterface } from 'sinon-ts' 6 | import { bootstrap } from '../src/index.js' 7 | import peerList from './fixtures/default-peers.js' 8 | import type { PeerStore } from '@libp2p/interface' 9 | import type { ConnectionManager } from '@libp2p/interface-internal' 10 | 11 | describe('compliance tests', () => { 12 | tests({ 13 | async setup () { 14 | const components = { 15 | peerStore: stubInterface(), 16 | logger: defaultLogger(), 17 | connectionManager: stubInterface() 18 | } 19 | 20 | return bootstrap({ 21 | list: peerList, 22 | timeout: 100 23 | })(components) 24 | }, 25 | async teardown () {} 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/test/fixtures/default-peers.ts: -------------------------------------------------------------------------------- 1 | const peers: string[] = [ 2 | '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', 3 | '/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN', 4 | '/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa', 5 | '/dnsaddr/bootstrap.libp2p.io/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', 6 | '/dnsaddr/bootstrap.libp2p.io/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt', 7 | '/dnsaddr/bootstrap.libp2p.io/ipfs/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp' 8 | ] 9 | 10 | export default peers 11 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/test/fixtures/some-invalid-peers.ts: -------------------------------------------------------------------------------- 1 | const peers: string[] = [ 2 | // @ts-expect-error this is an invalid peer 3 | null, 4 | '/ip4/104.236.151.122/tcp/4001/ipfs/malformed-peer-id', 5 | '/ip4/bad.ip.addr/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', 6 | '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx' 7 | ] 8 | 9 | export default peers 10 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../interface-compliance-tests" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/peer-discovery-bootstrap/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-discovery-mdns/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | config: { 5 | platform: 'node' 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/peer-discovery-mdns/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-discovery-mdns/src/utils.ts: -------------------------------------------------------------------------------- 1 | export function stringGen (len: number): string { 2 | let text = '' 3 | 4 | const charset = 'abcdefghijklmnopqrstuvwxyz0123456789' 5 | 6 | for (let i = 0; i < len; i++) { text += charset.charAt(Math.floor(Math.random() * charset.length)) } 7 | 8 | return text 9 | } 10 | -------------------------------------------------------------------------------- /packages/peer-discovery-mdns/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../interface-internal" 22 | }, 23 | { 24 | "path": "../logger" 25 | }, 26 | { 27 | "path": "../peer-id" 28 | }, 29 | { 30 | "path": "../utils" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/peer-discovery-mdns/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-id/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-id/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/peer-id/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/peer-id/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-record/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-record/src/envelope/envelope.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Envelope { 4 | // public_key is the public key of the keypair the enclosed payload was 5 | // signed with. 6 | bytes public_key = 1; 7 | 8 | // payload_type encodes the type of payload, so that it can be deserialized 9 | // deterministically. 10 | bytes payload_type = 2; 11 | 12 | // payload is the actual payload carried inside this envelope. 13 | bytes payload = 3; 14 | 15 | // signature is the signature produced by the private key corresponding to 16 | // the enclosed public key, over the payload, prefixing a domain string for 17 | // additional security. 18 | bytes signature = 5; 19 | } -------------------------------------------------------------------------------- /packages/peer-record/src/envelope/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The key in the record is not valid for the domain 3 | */ 4 | export class InvalidSignatureError extends Error { 5 | constructor (message = 'Invalid signature') { 6 | super(message) 7 | this.name = 'InvalidSignatureError' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/peer-record/src/peer-record/consts.ts: -------------------------------------------------------------------------------- 1 | // The domain string used for peer records contained in a Envelope. 2 | export const ENVELOPE_DOMAIN_PEER_RECORD = 'libp2p-peer-record' 3 | 4 | // The type hint used to identify peer records in a Envelope. 5 | // Defined in https://github.com/multiformats/multicodec/blob/master/table.csv 6 | // with name "libp2p-peer-record" 7 | export const ENVELOPE_PAYLOAD_TYPE_PEER_RECORD = Uint8Array.from([3, 1]) 8 | -------------------------------------------------------------------------------- /packages/peer-record/src/peer-record/peer-record.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message PeerRecord { 4 | // AddressInfo is a wrapper around a binary multiaddr. It is defined as a 5 | // separate message to allow us to add per-address metadata in the future. 6 | message AddressInfo { 7 | bytes multiaddr = 1; 8 | } 9 | 10 | // peer_id contains a libp2p peer id in its binary representation. 11 | bytes peer_id = 1; 12 | 13 | // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. 14 | uint64 seq = 2; 15 | 16 | // addresses is a list of public listen addresses for the peer. 17 | repeated AddressInfo addresses = 3; 18 | } -------------------------------------------------------------------------------- /packages/peer-record/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../peer-id" 19 | }, 20 | { 21 | "path": "../utils" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/peer-record/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/peer-store/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/peer-store/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/peer-store/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const MAX_ADDRESS_AGE = 3_600_000 2 | export const MAX_PEER_AGE = 21_600_000 3 | -------------------------------------------------------------------------------- /packages/peer-store/src/utils/peer-id-to-datastore-key.ts: -------------------------------------------------------------------------------- 1 | import { InvalidParametersError, isPeerId } from '@libp2p/interface' 2 | import { Key } from 'interface-datastore/key' 3 | import type { PeerId } from '@libp2p/interface' 4 | 5 | export const NAMESPACE_COMMON = '/peers/' 6 | 7 | export function peerIdToDatastoreKey (peerId: PeerId): Key { 8 | if (!isPeerId(peerId) || peerId.type == null) { 9 | throw new InvalidParametersError('Invalid PeerId') 10 | } 11 | 12 | const b32key = peerId.toCID().toString() 13 | return new Key(`${NAMESPACE_COMMON}${b32key}`) 14 | } 15 | -------------------------------------------------------------------------------- /packages/peer-store/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "exclude": [ 11 | "src/pb/peer.js" 12 | ], 13 | "references": [ 14 | { 15 | "path": "../crypto" 16 | }, 17 | { 18 | "path": "../interface" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | }, 26 | { 27 | "path": "../peer-record" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /packages/peer-store/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/pnet/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/pnet/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/pnet/src/errors.ts: -------------------------------------------------------------------------------- 1 | export const INVALID_PEER = 'Not a valid peer connection' 2 | export const INVALID_PSK = 'Your private shared key is invalid' 3 | export const NO_LOCAL_ID = 'No local private key provided' 4 | export const NO_HANDSHAKE_CONNECTION = 'No connection for the handshake provided' 5 | export const STREAM_ENDED = 'Stream ended prematurely' 6 | -------------------------------------------------------------------------------- /packages/pnet/src/key-generator.ts: -------------------------------------------------------------------------------- 1 | import { randomBytes } from '@libp2p/crypto' 2 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 3 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string' 4 | 5 | /** 6 | * Generates a PSK that can be used in a libp2p-pnet private network 7 | * 8 | * @param {Uint8Array | NodeJS.WriteStream} bytes - An object to write the psk into 9 | * @returns {void} 10 | */ 11 | export function generateKey (bytes: Uint8Array | NodeJS.WriteStream): void { 12 | const psk = uint8ArrayToString(randomBytes(KEY_LENGTH), 'base16') 13 | const key = uint8ArrayFromString('/key/swarm/psk/1.0.0/\n/base16/\n' + psk) 14 | 15 | if (bytes instanceof Uint8Array) { 16 | bytes.set(key) 17 | } else { 18 | bytes.write(key) 19 | } 20 | } 21 | 22 | export const NONCE_LENGTH = 24 23 | export const KEY_LENGTH = 32 24 | -------------------------------------------------------------------------------- /packages/pnet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/pnet/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-autonat/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-autonat/src/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The prefix to use in the protocol 3 | */ 4 | export const PROTOCOL_PREFIX = 'libp2p' 5 | 6 | /** 7 | * The name to use in the protocol 8 | */ 9 | export const PROTOCOL_NAME = 'autonat' 10 | 11 | /** 12 | * The version to use in the protocol 13 | */ 14 | export const PROTOCOL_VERSION = '1.0.0' 15 | export const TIMEOUT = 30000 16 | export const MAX_INBOUND_STREAMS = 2 17 | export const MAX_OUTBOUND_STREAMS = 20 18 | export const DEFAULT_CONNECTION_THRESHOLD = 80 19 | export const MAX_MESSAGE_SIZE = 8192 20 | -------------------------------------------------------------------------------- /packages/protocol-autonat/src/pb/index.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Message { 4 | enum MessageType { 5 | DIAL = 0; 6 | DIAL_RESPONSE = 1; 7 | } 8 | 9 | enum ResponseStatus { 10 | OK = 0; 11 | E_DIAL_ERROR = 100; 12 | E_DIAL_REFUSED = 101; 13 | E_BAD_REQUEST = 200; 14 | E_INTERNAL_ERROR = 300; 15 | } 16 | 17 | message PeerInfo { 18 | optional bytes id = 1; 19 | repeated bytes addrs = 2; 20 | } 21 | 22 | message Dial { 23 | optional PeerInfo peer = 1; 24 | } 25 | 26 | message DialResponse { 27 | optional ResponseStatus status = 1; 28 | optional string statusText = 2; 29 | optional bytes addr = 3; 30 | } 31 | 32 | optional MessageType type = 1; 33 | optional Dial dial = 2; 34 | optional DialResponse dialResponse = 3; 35 | } 36 | -------------------------------------------------------------------------------- /packages/protocol-autonat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-collections" 25 | }, 26 | { 27 | "path": "../peer-id" 28 | }, 29 | { 30 | "path": "../utils" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/protocol-autonat/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-dcutr/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-dcutr/src/pb/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message HolePunch { 4 | enum Type { 5 | UNUSED = 0; 6 | CONNECT = 100; 7 | SYNC = 300; 8 | } 9 | 10 | optional Type type = 1; 11 | repeated bytes observed_addresses = 2; 12 | } 13 | -------------------------------------------------------------------------------- /packages/protocol-dcutr/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { isPrivateIp } from '@libp2p/utils/private-ip' 2 | import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher' 3 | import type { TransportManager } from '@libp2p/interface-internal' 4 | import type { Multiaddr } from '@multiformats/multiaddr' 5 | 6 | /** 7 | * Returns true if the passed multiaddr is public, not relayed and we have a 8 | * transport that can dial it 9 | */ 10 | export function isPublicAndDialable (ma: Multiaddr, transportManager: TransportManager): boolean { 11 | // ignore circuit relay 12 | if (Circuit.matches(ma)) { 13 | return false 14 | } 15 | 16 | const transport = transportManager.dialTransportForMultiaddr(ma) 17 | 18 | if (transport == null) { 19 | return false 20 | } 21 | 22 | // dns addresses are probably public? 23 | if (DNS.matches(ma)) { 24 | return true 25 | } 26 | 27 | // ensure we have only IPv4/IPv6 addresses 28 | if (!IP.matches(ma)) { 29 | return false 30 | } 31 | 32 | return isPrivateIp(ma.toOptions().host) === false 33 | } 34 | -------------------------------------------------------------------------------- /packages/protocol-dcutr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../interface-internal" 16 | }, 17 | { 18 | "path": "../utils" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/protocol-dcutr/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-echo/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-echo/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const PROTOCOL_VERSION = '1.0.0' 2 | export const PROTOCOL_NAME = 'echo' 3 | -------------------------------------------------------------------------------- /packages/protocol-echo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../interface-internal" 16 | }, 17 | { 18 | "path": "../logger" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/protocol-echo/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-fetch/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-fetch/src/constants.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/libp2p/specs/tree/master/fetch#wire-protocol 2 | export const PROTOCOL_VERSION = '0.0.1' 3 | export const PROTOCOL_NAME = 'fetch' 4 | -------------------------------------------------------------------------------- /packages/protocol-fetch/src/pb/proto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message FetchRequest { 4 | bytes identifier = 1; 5 | } 6 | 7 | message FetchResponse { 8 | enum StatusCode { 9 | OK = 0; 10 | NOT_FOUND = 1; 11 | ERROR = 2; 12 | } 13 | 14 | StatusCode status = 1; 15 | bytes data = 2; 16 | } 17 | -------------------------------------------------------------------------------- /packages/protocol-fetch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/protocol-fetch/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-identify/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-identify/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const PROTOCOL_VERSION = 'ipfs/0.1.0' // deprecated 2 | export const MULTICODEC_IDENTIFY = '/ipfs/id/1.0.0' // deprecated 3 | export const MULTICODEC_IDENTIFY_PUSH = '/ipfs/id/push/1.0.0' // deprecated 4 | 5 | export const IDENTIFY_PROTOCOL_VERSION = '0.1.0' 6 | export const MULTICODEC_IDENTIFY_PROTOCOL_NAME = 'id' 7 | export const MULTICODEC_IDENTIFY_PUSH_PROTOCOL_NAME = 'id/push' 8 | export const MULTICODEC_IDENTIFY_PROTOCOL_VERSION = '1.0.0' 9 | export const MULTICODEC_IDENTIFY_PUSH_PROTOCOL_VERSION = '1.0.0' 10 | 11 | // https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52 12 | export const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8 13 | 14 | // https://github.com/libp2p/go-libp2p/blob/0385ec924bad172f74a74db09939e97c079b1420/p2p/protocol/identify/id.go#L47C7-L47C25 15 | export const MAX_PUSH_CONCURRENCY = 32 16 | -------------------------------------------------------------------------------- /packages/protocol-identify/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | }, 26 | { 27 | "path": "../peer-record" 28 | }, 29 | { 30 | "path": "../utils" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/protocol-identify/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-perf/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-perf/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const PROTOCOL_NAME = '/perf/1.0.0' 2 | export const WRITE_BLOCK_SIZE = 64 << 10 3 | export const MAX_INBOUND_STREAMS = 1 4 | export const MAX_OUTBOUND_STREAMS = 1 5 | export const RUN_ON_LIMITED_CONNECTION = false 6 | -------------------------------------------------------------------------------- /packages/protocol-perf/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../interface-compliance-tests" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/protocol-perf/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/protocol-ping/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/protocol-ping/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const PING_PROTOCOL = '/ipfs/ping/1.0.0' 2 | export const PING_LENGTH = 32 3 | export const PROTOCOL_VERSION = '1.0.0' 4 | export const PROTOCOL_NAME = 'ping' 5 | export const PROTOCOL_PREFIX = 'ipfs' 6 | export const TIMEOUT = 10000 7 | 8 | // See https://github.com/libp2p/specs/blob/d4b5fb0152a6bb86cfd9ea/ping/ping.md?plain=1#L38-L43 9 | // The dialing peer MUST NOT keep more than one outbound stream for the ping protocol per peer. 10 | // The listening peer SHOULD accept at most two streams per peer since cross-stream behavior is 11 | // non-linear and stream writes occur asynchronously. The listening peer may perceive the 12 | // dialing peer closing and opening the wrong streams (for instance, closing stream B and 13 | // opening stream A even though the dialing peer is opening stream B and closing stream A). 14 | export const MAX_INBOUND_STREAMS = 2 15 | export const MAX_OUTBOUND_STREAMS = 1 16 | -------------------------------------------------------------------------------- /packages/protocol-ping/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/protocol-ping/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '109KB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/img/test-cases.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/js-libp2p/6a3ae02f57079bc40181054447586a285c699c48/packages/pubsub-floodsub/img/test-cases.monopic -------------------------------------------------------------------------------- /packages/pubsub-floodsub/src/config.ts: -------------------------------------------------------------------------------- 1 | export const multicodec = '/floodsub/1.0.0' 2 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/test/compliance.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import tests from '@libp2p/interface-compliance-tests/pubsub' 4 | import { floodsub } from '../src/index.js' 5 | 6 | describe('interface compliance', () => { 7 | tests({ 8 | async setup (args) { 9 | if (args == null) { 10 | throw new Error('PubSubOptions is required') 11 | } 12 | 13 | const pubsub = floodsub(args.init)(args.components) 14 | 15 | return pubsub 16 | }, 17 | async teardown () { 18 | 19 | } 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-collections" 25 | }, 26 | { 27 | "path": "../peer-id" 28 | }, 29 | { 30 | "path": "../pubsub" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/pubsub-floodsub/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/pubsub/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/pubsub/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/pubsub/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "exclude": [ 11 | "test/message/rpc.js" 12 | ], 13 | "references": [ 14 | { 15 | "path": "../crypto" 16 | }, 17 | { 18 | "path": "../interface" 19 | }, 20 | { 21 | "path": "../interface-internal" 22 | }, 23 | { 24 | "path": "../logger" 25 | }, 26 | { 27 | "path": "../peer-collections" 28 | }, 29 | { 30 | "path": "../peer-id" 31 | }, 32 | { 33 | "path": "../utils" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /packages/pubsub/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts", 5 | "./src/peer-streams.ts", 6 | "./src/utils.ts" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/record/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/record/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/record/src/record.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // Record represents a dht record that contains a value 4 | // for a key value pair 5 | message Record { 6 | // The key that references this record 7 | bytes key = 1; 8 | 9 | // The actual value this record is storing 10 | bytes value = 2; 11 | 12 | // Note: These fields were removed from the Record message 13 | // hash of the authors public key 14 | // optional bytes author = 3; 15 | // A PKI signature for the key+value+author 16 | // optional bytes signature = 4; 17 | 18 | // Time the record was received, set by receiver 19 | string timeReceived = 5; 20 | } 21 | -------------------------------------------------------------------------------- /packages/record/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/record/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '17KB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/src/errors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * There was an error in the stream input buffer 3 | */ 4 | export class StreamInputBufferError extends Error { 5 | constructor (message = 'Stream input buffer error') { 6 | super(message) 7 | this.name = 'StreamInputBufferError' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/test/compliance.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import tests from '@libp2p/interface-compliance-tests/stream-muxer' 4 | import { defaultLogger } from '@libp2p/logger' 5 | import { mplex } from '../src/index.js' 6 | 7 | describe('compliance', () => { 8 | tests({ 9 | async setup () { 10 | return mplex({ 11 | maxInboundStreams: Infinity, 12 | disconnectThreshold: Infinity 13 | })({ 14 | logger: defaultLogger() 15 | }) 16 | }, 17 | async teardown () {} 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/test/fixtures/decode.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { Decoder, MAX_MSG_QUEUE_SIZE, MAX_MSG_SIZE } from '../../src/decode.js' 4 | import type { Message } from '../../src/message-types.js' 5 | import type { Source } from 'it-stream-types' 6 | import type { Uint8ArrayList } from 'uint8arraylist' 7 | 8 | export function decode (maxMessageSize: number = MAX_MSG_SIZE, maxUnprocessedMessageQueueSize: number = MAX_MSG_QUEUE_SIZE) { 9 | return async function * decodeMessages (source: Source): Source { 10 | const decoder = new Decoder(maxMessageSize, maxUnprocessedMessageQueueSize) 11 | 12 | for await (const chunk of source) { 13 | const msgs = decoder.write(chunk) 14 | 15 | if (msgs.length > 0) { 16 | yield * msgs 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../interface-compliance-tests" 16 | }, 17 | { 18 | "path": "../logger" 19 | }, 20 | { 21 | "path": "../utils" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /packages/stream-multiplexer-mplex/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-circuit-relay-v2/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-circuit-relay-v2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-compliance-tests" 19 | }, 20 | { 21 | "path": "../interface-internal" 22 | }, 23 | { 24 | "path": "../logger" 25 | }, 26 | { 27 | "path": "../peer-collections" 28 | }, 29 | { 30 | "path": "../peer-id" 31 | }, 32 | { 33 | "path": "../peer-record" 34 | }, 35 | { 36 | "path": "../utils" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /packages/transport-circuit-relay-v2/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-memory/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '15KB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-memory/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-memory/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../logger" 16 | }, 17 | { 18 | "path": "../peer-id" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/transport-memory/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-tcp/.aegir.js: -------------------------------------------------------------------------------- 1 | 2 | /** @type {import('aegir').PartialOptions} */ 3 | export default { 4 | build: { 5 | config: { 6 | platform: 'node' 7 | }, 8 | bundlesizeMax: '31KB' 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/transport-tcp/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-tcp/src/constants.ts: -------------------------------------------------------------------------------- 1 | // Time to wait for a connection to close gracefully before destroying it manually 2 | export const CLOSE_TIMEOUT = 500 3 | 4 | // Close the socket if there is no activity after this long in ms 5 | export const SOCKET_TIMEOUT = 2 * 60_000 // 2 mins 6 | -------------------------------------------------------------------------------- /packages/transport-tcp/src/tcp.browser.ts: -------------------------------------------------------------------------------- 1 | import { serviceCapabilities, transportSymbol } from '@libp2p/interface' 2 | import type { TCPDialEvents } from './index.js' 3 | import type { Connection, Transport, Listener } from '@libp2p/interface' 4 | import type { Multiaddr } from '@multiformats/multiaddr' 5 | 6 | export class TCP implements Transport { 7 | constructor () { 8 | throw new Error('TCP connections are not possible in browsers') 9 | } 10 | 11 | readonly [transportSymbol] = true 12 | 13 | readonly [Symbol.toStringTag] = '@libp2p/tcp' 14 | 15 | readonly [serviceCapabilities]: string[] = [ 16 | '@libp2p/transport' 17 | ] 18 | 19 | async dial (): Promise { 20 | throw new Error('TCP connections are not possible in browsers') 21 | } 22 | 23 | createListener (): Listener { 24 | throw new Error('TCP connections are not possible in browsers') 25 | } 26 | 27 | listenFilter (): Multiaddr[] { 28 | return [] 29 | } 30 | 31 | dialFilter (): Multiaddr[] { 32 | return [] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/transport-tcp/src/utils.ts: -------------------------------------------------------------------------------- 1 | import os from 'os' 2 | import path from 'path' 3 | import type { Multiaddr } from '@multiformats/multiaddr' 4 | import type { ListenOptions, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net' 5 | 6 | export type NetConfig = ListenOptions | (IpcSocketConnectOpts & TcpSocketConnectOpts) 7 | 8 | export function multiaddrToNetConfig (addr: Multiaddr, config: NetConfig = {}): NetConfig { 9 | const listenPath = addr.getPath() 10 | 11 | // unix socket listening 12 | if (listenPath != null) { 13 | if (os.platform() === 'win32') { 14 | // Use named pipes on Windows systems. 15 | return { path: path.join('\\\\.\\pipe\\', listenPath) } 16 | } else { 17 | return { path: listenPath } 18 | } 19 | } 20 | 21 | const options = addr.toOptions() 22 | 23 | // tcp listening 24 | return { 25 | ...config, 26 | ...options, 27 | ipv6Only: options.family === 6 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/transport-tcp/test/browser.ts: -------------------------------------------------------------------------------- 1 | import { defaultLogger } from '@libp2p/logger' 2 | import { expect } from 'aegir/chai' 3 | import { isBrowser, isWebWorker } from 'wherearewe' 4 | import { tcp } from '../src/index.js' 5 | 6 | describe('browser non-support', () => { 7 | it('should throw in browsers', function () { 8 | if (!isBrowser && !isWebWorker) { 9 | return this.skip() 10 | } 11 | 12 | expect(() => { 13 | tcp()({ 14 | logger: defaultLogger() 15 | }) 16 | }).to.throw() 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /packages/transport-tcp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../logger" 16 | }, 17 | { 18 | "path": "../utils" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/transport-tcp/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-webrtc/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '117KB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-webrtc/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/private-to-private/pb/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Message { 4 | // Specifies type in `data` field. 5 | enum Type { 6 | // String of `RTCSessionDescription.sdp` 7 | SDP_OFFER = 0; 8 | // String of `RTCSessionDescription.sdp` 9 | SDP_ANSWER = 1; 10 | // String of `RTCIceCandidate.toJSON()` 11 | ICE_CANDIDATE = 2; 12 | } 13 | 14 | optional Type type = 1; 15 | optional string data = 2; 16 | } -------------------------------------------------------------------------------- /packages/transport-webrtc/src/private-to-public/listener.browser.ts: -------------------------------------------------------------------------------- 1 | import { TypedEventEmitter } from '@libp2p/interface' 2 | import { UnimplementedError } from '../error.js' 3 | import type { PeerId, ListenerEvents, Listener } from '@libp2p/interface' 4 | import type { TransportManager } from '@libp2p/interface-internal' 5 | import type { Multiaddr } from '@multiformats/multiaddr' 6 | 7 | export interface WebRTCDirectListenerComponents { 8 | peerId: PeerId 9 | transportManager: TransportManager 10 | } 11 | 12 | export interface WebRTCDirectListenerInit { 13 | shutdownController: AbortController 14 | } 15 | 16 | export class WebRTCDirectListener extends TypedEventEmitter implements Listener { 17 | async listen (): Promise { 18 | throw new UnimplementedError('WebRTCTransport.createListener') 19 | } 20 | 21 | getAddrs (): Multiaddr[] { 22 | return [] 23 | } 24 | 25 | updateAnnounceAddrs (): void { 26 | 27 | } 28 | 29 | async close (): Promise { 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/private-to-public/pb/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message Message { 4 | enum Flag { 5 | // The sender will no longer send messages on the stream. The recipient 6 | // should send a FIN_ACK back to the sender. 7 | FIN = 0; 8 | 9 | // The sender will no longer read messages on the stream. Incoming data is 10 | // being discarded on receipt. 11 | STOP_SENDING = 1; 12 | 13 | // The sender abruptly terminates the sending part of the stream. The 14 | // receiver can discard any data that it already received on that stream. 15 | RESET = 2; 16 | 17 | // The sender previously received a FIN. 18 | // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1484907 19 | FIN_ACK = 3; 20 | } 21 | 22 | optional Flag flag = 1; 23 | 24 | optional bytes message = 2; 25 | } 26 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/private-to-public/utils/generate-certificates.browser.ts: -------------------------------------------------------------------------------- 1 | export async function generateWebTransportCertificate (): Promise { 2 | throw new Error('Not implemented') 3 | } 4 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/private-to-public/utils/pem.ts: -------------------------------------------------------------------------------- 1 | import { privateKeyToCryptoKeyPair } from '@libp2p/crypto/keys' 2 | import { toString as uint8ArrayToString } from 'uint8arrays/to-string' 3 | import type { PrivateKey } from '@libp2p/interface' 4 | 5 | export function toBuffer (uint8Array: Uint8Array): Buffer { 6 | return Buffer.from(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength) 7 | } 8 | 9 | export async function formatAsPem (privateKey: PrivateKey): Promise { 10 | const keyPair = await privateKeyToCryptoKeyPair(privateKey) 11 | const exported = await crypto.subtle.exportKey('pkcs8', keyPair.privateKey) 12 | 13 | return [ 14 | '-----BEGIN PRIVATE KEY-----', 15 | ...uint8ArrayToString(new Uint8Array(exported), 'base64pad').split(/(.{64})/).filter(Boolean), 16 | '-----END PRIVATE KEY-----' 17 | ].join('\n') 18 | } 19 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/webrtc/index.browser.ts: -------------------------------------------------------------------------------- 1 | export const RTCPeerConnection = globalThis.RTCPeerConnection 2 | export const RTCSessionDescription = globalThis.RTCSessionDescription 3 | export const RTCIceCandidate = globalThis.RTCIceCandidate 4 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/webrtc/index.react-native.ts: -------------------------------------------------------------------------------- 1 | export { 2 | RTCIceCandidate, 3 | RTCPeerConnection, 4 | RTCSessionDescription 5 | } from 'react-native-webrtc' 6 | -------------------------------------------------------------------------------- /packages/transport-webrtc/src/webrtc/index.ts: -------------------------------------------------------------------------------- 1 | export { RTCSessionDescription, RTCIceCandidate, RTCPeerConnection } from '@ipshipyard/node-datachannel/polyfill' 2 | -------------------------------------------------------------------------------- /packages/transport-webrtc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test", 9 | "proto_ts" 10 | ], 11 | "references": [ 12 | { 13 | "path": "../crypto" 14 | }, 15 | { 16 | "path": "../interface" 17 | }, 18 | { 19 | "path": "../interface-compliance-tests" 20 | }, 21 | { 22 | "path": "../interface-internal" 23 | }, 24 | { 25 | "path": "../keychain" 26 | }, 27 | { 28 | "path": "../logger" 29 | }, 30 | { 31 | "path": "../peer-id" 32 | }, 33 | { 34 | "path": "../utils" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /packages/transport-webrtc/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-websockets/.aegir.js: -------------------------------------------------------------------------------- 1 | /** @type {import('aegir/types').PartialOptions} */ 2 | export default { 3 | build: { 4 | bundlesizeMax: '18kB' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/transport-websockets/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-websockets/src/constants.ts: -------------------------------------------------------------------------------- 1 | // Time to wait for a connection to close gracefully before destroying it manually 2 | export const CLOSE_TIMEOUT = 500 3 | -------------------------------------------------------------------------------- /packages/transport-websockets/src/listener.browser.ts: -------------------------------------------------------------------------------- 1 | import type { Listener } from '@libp2p/interface' 2 | 3 | export function createListener (): Listener { 4 | throw new Error('WebSocket Servers can not be created in the browser!') 5 | } 6 | -------------------------------------------------------------------------------- /packages/transport-websockets/test/browser.ts: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | import { TypedEventEmitter } from '@libp2p/interface' 4 | import { defaultLogger } from '@libp2p/logger' 5 | import { expect } from 'aegir/chai' 6 | import { webSockets } from '../src/index.js' 7 | 8 | describe('libp2p-websockets', () => { 9 | it('.createServer throws in browser', () => { 10 | expect(webSockets()({ 11 | events: new TypedEventEmitter(), 12 | logger: defaultLogger() 13 | }).createListener).to.throw() 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/transport-websockets/test/fixtures/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICATCCAWoCCQDPufXH86n2QzANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJu 3 | bzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 4 | cyBQdHkgTHRkMB4XDTEyMDEwMTE0NDQwMFoXDTIwMDMxOTE0NDQwMFowRTELMAkG 5 | A1UEBhMCbm8xEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 6 | IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtrQ7 7 | +r//2iV/B6F+4boH0XqFn7alcV9lpjvAmwRXNKnxAoa0f97AjYPGNLKrjpkNXXhB 8 | JROIdbRbZnCNeC5fzX1a+JCo7KStzBXuGSZr27TtFmcV4H+9gIRIcNHtZmJLnxbJ 9 | sIhkGR8yVYdmJZe4eT5ldk1zoB1adgPF1hZhCBMCAwEAATANBgkqhkiG9w0BAQUF 10 | AAOBgQCeWBEHYJ4mCB5McwSSUox0T+/mJ4W48L/ZUE4LtRhHasU9hiW92xZkTa7E 11 | QLcoJKQiWfiLX2ysAro0NX4+V8iqLziMqvswnPzz5nezaOLE/9U/QvH3l8qqNkXu 12 | rNbsW1h/IO6FV8avWFYVFoutUwOaZ809k7iMh2F2JMgXQ5EymQ== 13 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /packages/transport-websockets/test/fixtures/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQC2tDv6v//aJX8HoX7hugfReoWftqVxX2WmO8CbBFc0qfEChrR/ 3 | 3sCNg8Y0squOmQ1deEElE4h1tFtmcI14Ll/NfVr4kKjspK3MFe4ZJmvbtO0WZxXg 4 | f72AhEhw0e1mYkufFsmwiGQZHzJVh2Yll7h5PmV2TXOgHVp2A8XWFmEIEwIDAQAB 5 | AoGAAlVY8sHi/aE+9xT77twWX3mGHV0SzdjfDnly40fx6S1Gc7bOtVdd9DC7pk6l 6 | 3ENeJVR02IlgU8iC5lMHq4JEHPE272jtPrLlrpWLTGmHEqoVFv9AITPqUDLhB9Kk 7 | Hjl7h8NYBKbr2JHKICr3DIPKOT+RnXVb1PD4EORbJ3ooYmkCQQDfknUnVxPgxUGs 8 | ouABw1WJIOVgcCY/IFt4Ihf6VWTsxBgzTJKxn3HtgvE0oqTH7V480XoH0QxHhjLq 9 | DrgobWU9AkEA0TRJ8/ouXGnFEPAXjWr9GdPQRZ1Use2MrFjneH2+Sxc0CmYtwwqL 10 | Kr5kS6mqJrxprJeluSjBd+3/ElxURrEXjwJAUvmlN1OPEhXDmRHd92mKnlkyKEeX 11 | OkiFCiIFKih1S5Y/sRJTQ0781nyJjtJqO7UyC3pnQu1oFEePL+UEniRztQJAMfav 12 | AtnpYKDSM+1jcp7uu9BemYGtzKDTTAYfoiNF42EzSJiGrWJDQn4eLgPjY0T0aAf/ 13 | yGz3Z9ErbhMm/Ysl+QJBAL4kBxRT8gM4ByJw4sdOvSeCCANFq8fhbgm8pGWlCPb5 14 | JGmX3/GHFM8x2tbWMGpyZP1DLtiNEFz7eCGktWK5rqE= 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /packages/transport-websockets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../interface" 13 | }, 14 | { 15 | "path": "../logger" 16 | }, 17 | { 18 | "path": "../utils" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/transport-websockets/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts", 5 | "./src/filters.ts" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /packages/transport-webtransport/.gitignore: -------------------------------------------------------------------------------- 1 | go-libp2p-webtransport-server/main 2 | -------------------------------------------------------------------------------- /packages/transport-webtransport/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/transport-webtransport/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Running tests 4 | 5 | Run `npm run test`. 6 | 7 | ### Running tests without IPv6 8 | 9 | If you try to run these tests locally, and your machine does not support IPv6, 10 | the tests will hang waiting on an ip6 address from the 11 | `go-libp2p-webtransport-server`. 12 | 13 | To get around this, you can set the environment variable `DISABLE_IPV6` to `true` 14 | to prevent those tests from running. e.g. `DISABLE_IPV6=true npm run test` 15 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const MAX_INBOUND_STREAMS = 1_000 2 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/listener.browser.ts: -------------------------------------------------------------------------------- 1 | import type { CreateListenerOptions, Listener } from '@libp2p/interface' 2 | 3 | export default function createListener (options: CreateListenerOptions): Listener { 4 | throw new Error('Not implemented') 5 | } 6 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/listener.ts: -------------------------------------------------------------------------------- 1 | import type { WebTransportCertificate } from './index.js' 2 | import type { Connection, Upgrader, Listener, CreateListenerOptions, PeerId, ComponentLogger, Metrics } from '@libp2p/interface' 3 | 4 | export interface WebTransportListenerComponents { 5 | peerId: PeerId 6 | logger: ComponentLogger 7 | metrics?: Metrics 8 | } 9 | 10 | export interface WebTransportListenerInit extends CreateListenerOptions { 11 | handler?(conn: Connection): void 12 | upgrader: Upgrader 13 | certificates?: WebTransportCertificate[] 14 | maxInboundStreams?: number 15 | } 16 | 17 | export default function createListener (components: WebTransportListenerComponents, options: WebTransportListenerInit): Listener { 18 | throw new Error('Only supported in browsers') 19 | } 20 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/utils/generate-certificates.browser.ts: -------------------------------------------------------------------------------- 1 | export async function generateWebTransportCertificates (): Promise { 2 | throw new Error('Not implemented') 3 | } 4 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/utils/generate-certificates.ts: -------------------------------------------------------------------------------- 1 | import type { WebTransportCertificate } from '../../src/index.js' 2 | 3 | export interface GenerateWebTransportCertificateOptions { 4 | days: number 5 | start?: Date 6 | extensions?: any[] 7 | } 8 | 9 | export async function generateWebTransportCertificates (options: GenerateWebTransportCertificateOptions[] = []): Promise { 10 | throw new Error('Not implemented') 11 | } 12 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/utils/inert-duplex.ts: -------------------------------------------------------------------------------- 1 | import type { Duplex, Source } from 'it-stream-types' 2 | 3 | // Duplex that does nothing. Needed to fulfill the interface 4 | export function inertDuplex (): Duplex { 5 | return { 6 | source: { 7 | [Symbol.asyncIterator] () { 8 | return { 9 | async next () { 10 | // This will never resolve 11 | return new Promise(() => { }) 12 | } 13 | } 14 | } 15 | }, 16 | sink: async (source: Source) => { 17 | // This will never resolve 18 | return new Promise(() => { }) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/utils/is-subset.ts: -------------------------------------------------------------------------------- 1 | import { equals as uint8ArrayEquals } from 'uint8arrays/equals' 2 | 3 | /** 4 | * Determines if `maybeSubset` is a subset of `set`. This means that all byte 5 | * arrays in `maybeSubset` are present in `set`. 6 | */ 7 | export function isSubset (set: Uint8Array[], maybeSubset: Uint8Array[]): boolean { 8 | const intersection = maybeSubset.filter(byteArray => { 9 | return Boolean(set.find((otherByteArray: Uint8Array) => uint8ArrayEquals(byteArray, otherByteArray))) 10 | }) 11 | return (intersection.length === maybeSubset.length) 12 | } 13 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/webtransport.browser.ts: -------------------------------------------------------------------------------- 1 | // exporting property of globalThis allows us to fail gracefully in browsers 2 | // without WebTransport support 3 | export default globalThis.WebTransport 4 | -------------------------------------------------------------------------------- /packages/transport-webtransport/src/webtransport.ts: -------------------------------------------------------------------------------- 1 | export default class WebTransport { 2 | constructor (url: string | URL, options?: WebTransportOptions) { 3 | throw new Error('Only supported in browsers') 4 | } 5 | 6 | close (): void { 7 | throw new Error('Only supported in browsers') 8 | } 9 | 10 | async createBidirectionalStream (): Promise { 11 | throw new Error('Only supported in browsers') 12 | } 13 | 14 | public closed = Promise.reject(new Error('Only supported in browsers')) 15 | public ready = Promise.reject(new Error('Only supported in browsers')) 16 | public incomingBidirectionalStreams: ReadableStream 17 | } 18 | -------------------------------------------------------------------------------- /packages/transport-webtransport/test/fixtures/random-bytes.ts: -------------------------------------------------------------------------------- 1 | import { InvalidParametersError } from '@libp2p/interface' 2 | import { randomBytes as randB } from '@noble/hashes/utils' 3 | 4 | /** 5 | * Generates a Uint8Array with length `number` populated by random bytes 6 | */ 7 | export function randomBytes (length: number): Uint8Array { 8 | if (isNaN(length) || length <= 0) { 9 | throw new InvalidParametersError('random bytes length must be a Number bigger than 0') 10 | } 11 | 12 | return randB(length) 13 | } 14 | -------------------------------------------------------------------------------- /packages/transport-webtransport/test/utils/is-subset.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'aegir/chai' 2 | import { isSubset } from '../../src/utils/is-subset.js' 3 | 4 | describe('test helpers', () => { 5 | it('correctly checks subsets', () => { 6 | const testCases = [ 7 | { a: [[1, 2, 3]], b: [[4, 5, 6]], isSubset: false }, 8 | { a: [[1, 2, 3], [4, 5, 6]], b: [[1, 2, 3]], isSubset: true }, 9 | { a: [[1, 2, 3], [4, 5, 6]], b: [], isSubset: true }, 10 | { a: [], b: [[1, 2, 3]], isSubset: false }, 11 | { a: [], b: [], isSubset: true }, 12 | { a: [[1, 2, 3]], b: [[1, 2, 3], [4, 5, 6]], isSubset: false }, 13 | { a: [[1, 2, 3]], b: [[1, 2]], isSubset: false } 14 | ] 15 | 16 | for (const tc of testCases) { 17 | expect(isSubset(tc.a.map(b => new Uint8Array(b)), tc.b.map(b => new Uint8Array(b)))).to.equal(tc.isSubset) 18 | } 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /packages/transport-webtransport/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../libp2p" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | }, 26 | { 27 | "path": "../protocol-ping" 28 | }, 29 | { 30 | "path": "../utils" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/transport-webtransport/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/upnp-nat/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/upnp-nat/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/upnp-nat/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_INITIAL_GATEWAY_SEARCH_INTERVAL = 5_000 2 | export const DEFAULT_INITIAL_GATEWAY_SEARCH_TIMEOUT = 5_000 3 | export const DEFAULT_INITIAL_GATEWAY_SEARCH_MESSAGE_INTERVAL = 1_000 4 | 5 | export const DEFAULT_GATEWAY_SEARCH_TIMEOUT = 60_000 6 | export const DEFAULT_GATEWAY_SEARCH_INTERVAL = 300_000 7 | export const DEFAULT_GATEWAY_SEARCH_MESSAGE_INTERVAL = 10_000 8 | -------------------------------------------------------------------------------- /packages/upnp-nat/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class DoubleNATError extends Error { 2 | constructor (message = 'Double NAT detected') { 3 | super(message) 4 | this.name = 'DoubleNATError' 5 | } 6 | } 7 | 8 | export class InvalidIPAddressError extends Error { 9 | static name = 'InvalidIPAddressError' 10 | name = 'InvalidIPAddressError' 11 | } 12 | -------------------------------------------------------------------------------- /packages/upnp-nat/src/upnp-nat.browser.ts: -------------------------------------------------------------------------------- 1 | import { serviceCapabilities, serviceDependencies } from '@libp2p/interface' 2 | import type { UPnPNATClient, UPnPNAT as UPnPNATInterface } from './index.js' 3 | 4 | export class UPnPNAT implements UPnPNATInterface { 5 | public portMappingClient: UPnPNATClient 6 | 7 | constructor () { 8 | throw new Error('UPnPNAT is not supported in browsers') 9 | } 10 | 11 | readonly [Symbol.toStringTag] = '@libp2p/upnp-nat' 12 | 13 | readonly [serviceCapabilities]: string[] = [ 14 | '@libp2p/nat-traversal' 15 | ] 16 | 17 | get [serviceDependencies] (): string[] { 18 | return [] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/upnp-nat/test/browser.ts: -------------------------------------------------------------------------------- 1 | import { generateKeyPair } from '@libp2p/crypto/keys' 2 | import { TypedEventEmitter } from '@libp2p/interface' 3 | import { defaultLogger } from '@libp2p/logger' 4 | import { peerIdFromPrivateKey } from '@libp2p/peer-id' 5 | import { expect } from 'aegir/chai' 6 | import { stubInterface } from 'sinon-ts' 7 | import { isBrowser, isWebWorker } from 'wherearewe' 8 | import { uPnPNAT } from '../src/index.js' 9 | import type { AddressManager } from '@libp2p/interface-internal' 10 | 11 | describe('browser non-support', () => { 12 | it('should throw in browsers', async function () { 13 | if (!isBrowser && !isWebWorker) { 14 | return this.skip() 15 | } 16 | 17 | const components = { 18 | peerId: peerIdFromPrivateKey(await generateKeyPair('Ed25519')), 19 | nodeInfo: { name: 'test', version: 'test', userAgent: 'test' }, 20 | logger: defaultLogger(), 21 | addressManager: stubInterface(), 22 | events: new TypedEventEmitter() 23 | } 24 | 25 | expect(() => { 26 | uPnPNAT()(components) 27 | }).to.throw() 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /packages/upnp-nat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../interface-internal" 19 | }, 20 | { 21 | "path": "../logger" 22 | }, 23 | { 24 | "path": "../peer-id" 25 | }, 26 | { 27 | "path": "../utils" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /packages/upnp-nat/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": "none", 3 | "entryPoints": [ 4 | "./src/index.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/utils/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) 4 | -------------------------------------------------------------------------------- /packages/utils/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /packages/utils/benchmark/filter/bloom-filter.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const Benchmark = require('benchmark') 3 | 4 | const suite = new Benchmark.Suite('bloom-filter') 5 | 6 | const bits = [8, 64, 512, 4096, 32768, 262144, 2097152, 251658240] 7 | 8 | bits.forEach((bit) => { 9 | suite.add(`Loop ${bit}bits`, () => { 10 | let pos = 0 11 | let shift = bit 12 | while (shift > 7) { 13 | pos++ 14 | shift -= 8 15 | } 16 | }) 17 | 18 | suite.add(`Math Ops ${bit}bits`, () => { 19 | _ = Math.floor(bit / 8) 20 | _ = bit % 8 21 | }) 22 | }) 23 | 24 | suite 25 | .on('cycle', (event) => console.log(String(event.target))) 26 | .run({ async: true }) 27 | -------------------------------------------------------------------------------- /packages/utils/src/abort-options.ts: -------------------------------------------------------------------------------- 1 | import { setMaxListeners } from '@libp2p/interface' 2 | import { anySignal } from 'any-signal' 3 | import type { AbortOptions } from '@libp2p/interface' 4 | import type { ClearableSignal } from 'any-signal' 5 | 6 | export function createTimeoutOptions (timeout: number): AbortOptions 7 | export function createTimeoutOptions (timeout: number, ...existingSignals: AbortSignal[]): { signal: ClearableSignal } 8 | export function createTimeoutOptions (timeout: number, ...existingSignals: AbortSignal[]): AbortOptions { 9 | let signal = AbortSignal.timeout(timeout) 10 | setMaxListeners(Infinity, signal) 11 | 12 | if (existingSignals.length > 0) { 13 | signal = anySignal([signal, ...existingSignals]) 14 | setMaxListeners(Infinity, signal) 15 | } 16 | 17 | return { 18 | signal 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/utils/src/array-equals.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @packageDocumentation 3 | * 4 | * Provides strategies ensure arrays are equivalent. 5 | * 6 | * @example 7 | * 8 | * ```typescript 9 | * import { arrayEquals } from '@libp2p/utils/array-equals' 10 | * import { multiaddr } from '@multformats/multiaddr' 11 | * 12 | * const ma1 = multiaddr('/ip4/127.0.0.1/tcp/9000'), 13 | * const ma2 = multiaddr('/ip4/82.41.53.1/tcp/9000') 14 | * 15 | * console.info(arrayEquals([ma1], [ma1])) // true 16 | * console.info(arrayEquals([ma1], [ma2])) // false 17 | * ``` 18 | */ 19 | 20 | /** 21 | * Verify if two arrays of non primitive types with the "equals" function are equal. 22 | * Compatible with multiaddr, peer-id and others. 23 | */ 24 | export function arrayEquals (a: any[], b: any[]): boolean { 25 | const sort = (a: any, b: any): number => a.toString().localeCompare(b.toString()) 26 | 27 | if (a.length !== b.length) { 28 | return false 29 | } 30 | 31 | b.sort(sort) 32 | 33 | return a.sort(sort).every((item, index) => b[index].equals(item)) 34 | } 35 | -------------------------------------------------------------------------------- /packages/utils/src/close-source.ts: -------------------------------------------------------------------------------- 1 | import { getIterator } from 'get-iterator' 2 | import { isPromise } from './is-promise.js' 3 | import type { Logger } from '@libp2p/logger' 4 | import type { Source } from 'it-stream-types' 5 | 6 | export function closeSource (source: Source, log: Logger): void { 7 | const res = getIterator(source).return?.() 8 | 9 | if (isPromise(res)) { 10 | res.catch(err => { 11 | log.error('could not cause iterator to return', err) 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/utils/src/debounce.ts: -------------------------------------------------------------------------------- 1 | import type { Startable } from '@libp2p/interface' 2 | 3 | export interface DebouncedFunction extends Startable { 4 | (): void 5 | } 6 | 7 | /** 8 | * Returns a function wrapper that will only call the passed function once 9 | * 10 | * Important - the passed function should not throw or reject 11 | */ 12 | export function debounce (func: () => void | Promise, wait: number): DebouncedFunction { 13 | let timeout: ReturnType | undefined 14 | 15 | const output = function (): void { 16 | const later = function (): void { 17 | timeout = undefined 18 | void func() 19 | } 20 | 21 | clearTimeout(timeout) 22 | timeout = setTimeout(later, wait) 23 | } 24 | output.start = (): void => {} 25 | output.stop = (): void => { 26 | clearTimeout(timeout) 27 | } 28 | 29 | return output 30 | } 31 | -------------------------------------------------------------------------------- /packages/utils/src/errors.ts: -------------------------------------------------------------------------------- 1 | import type { RateLimiterResult } from './rate-limiter.js' 2 | 3 | /** 4 | * A rate limit was hit 5 | */ 6 | export class RateLimitError extends Error { 7 | remainingPoints: number 8 | msBeforeNext: number 9 | consumedPoints: number 10 | isFirstInDuration: boolean 11 | 12 | constructor (message = 'Rate limit exceeded', props: RateLimiterResult) { 13 | super(message) 14 | this.name = 'RateLimitError' 15 | this.remainingPoints = props.remainingPoints 16 | this.msBeforeNext = props.msBeforeNext 17 | this.consumedPoints = props.consumedPoints 18 | this.isFirstInDuration = props.isFirstInDuration 19 | } 20 | } 21 | 22 | export class QueueFullError extends Error { 23 | static name = 'QueueFullError' 24 | 25 | constructor (message: string = 'The queue was full') { 26 | super(message) 27 | this.name = 'QueueFullError' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/utils/src/filters/hashes.ts: -------------------------------------------------------------------------------- 1 | import fnv1aHash from '@sindresorhus/fnv1a' 2 | import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' 3 | 4 | export interface Hash { 5 | hash(input: Uint8Array, seed: number): number 6 | hashV(input: Uint8Array, seed: number): Uint8Array 7 | } 8 | 9 | export const fnv1a: Hash = { 10 | hash: (input) => { 11 | return Number(fnv1aHash(input, { 12 | size: 32 13 | })) 14 | }, 15 | hashV: (input, seed) => { 16 | return numberToBuffer(fnv1a.hash(input, seed)) 17 | } 18 | } 19 | 20 | export function numberToBuffer (num: bigint | number): Uint8Array { 21 | let hex = num.toString(16) 22 | 23 | if (hex.length % 2 === 1) { 24 | hex = `0${hex}` 25 | } 26 | 27 | return uint8ArrayFromString(hex, 'base16') 28 | } 29 | -------------------------------------------------------------------------------- /packages/utils/src/filters/index.ts: -------------------------------------------------------------------------------- 1 | export { BloomFilter, createBloomFilter, type BloomFilterOptions } from './bloom-filter.js' 2 | export { CuckooFilter, createCuckooFilter, type CuckooFilterInit } from './cuckoo-filter.js' 3 | export { ScalableCuckooFilter, createScalableCuckooFilter, type ScalableCuckooFilterInit } from './scalable-cuckoo-filter.js' 4 | export type { Bucket } from './bucket.js' 5 | export type { Fingerprint } from './fingerprint.js' 6 | export type { Hash } from './hashes.js' 7 | 8 | export interface Filter { 9 | add(item: Uint8Array | string): void 10 | has(item: Uint8Array | string): boolean 11 | remove?(buf: Uint8Array | string): boolean 12 | } 13 | -------------------------------------------------------------------------------- /packages/utils/src/filters/utils.ts: -------------------------------------------------------------------------------- 1 | export function getRandomInt (min: number, max: number): number { 2 | return Math.floor(Math.random() * (max - min)) + min 3 | } 4 | -------------------------------------------------------------------------------- /packages/utils/src/get-thin-waist-addresses.browser.ts: -------------------------------------------------------------------------------- 1 | import { multiaddr } from '@multiformats/multiaddr' 2 | import type { Multiaddr } from '@multiformats/multiaddr' 3 | 4 | /** 5 | * Get all thin waist addresses on the current host that match the family of the 6 | * passed multiaddr and optionally override the port. 7 | * 8 | * Wildcard IP4/6 addresses will be expanded into all available interfaces. 9 | */ 10 | export function getThinWaistAddresses (ma?: Multiaddr, port?: number): Multiaddr[] { 11 | if (ma == null) { 12 | return [] 13 | } 14 | 15 | const options = ma.toOptions() 16 | 17 | return [ 18 | multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${port ?? options.port}`) 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/utils/src/global-unicast-ip.ts: -------------------------------------------------------------------------------- 1 | import { isIPv6 } from '@chainsafe/is-ip' 2 | import { cidrContains } from '@chainsafe/netmask' 3 | 4 | export function isGlobalUnicastIp (ip: string): boolean { 5 | if (isIPv6(ip)) { 6 | return cidrContains('2000::/3', ip) 7 | } 8 | 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/src/ip-port-to-multiaddr.ts: -------------------------------------------------------------------------------- 1 | import { isIPv4, isIPv6 } from '@chainsafe/is-ip' 2 | import { InvalidParametersError } from '@libp2p/interface' 3 | import { multiaddr } from '@multiformats/multiaddr' 4 | import type { Multiaddr } from '@multiformats/multiaddr' 5 | 6 | /** 7 | * Transform an IP, Port pair into a multiaddr 8 | */ 9 | export function ipPortToMultiaddr (ip: string, port: number | string): Multiaddr { 10 | if (typeof ip !== 'string') { 11 | throw new InvalidParametersError(`invalid ip provided: ${ip}`) 12 | } 13 | 14 | if (typeof port === 'string') { 15 | port = parseInt(port) 16 | } 17 | 18 | if (isNaN(port)) { 19 | throw new InvalidParametersError(`invalid port provided: ${port}`) 20 | } 21 | 22 | if (isIPv4(ip)) { 23 | return multiaddr(`/ip4/${ip}/tcp/${port}`) 24 | } 25 | 26 | if (isIPv6(ip)) { 27 | return multiaddr(`/ip6/${ip}/tcp/${port}`) 28 | } 29 | 30 | throw new InvalidParametersError(`invalid ip:port for creating a multiaddr: ${ip}:${port}`) 31 | } 32 | -------------------------------------------------------------------------------- /packages/utils/src/is-async-generator.ts: -------------------------------------------------------------------------------- 1 | export function isAsyncGenerator (obj: unknown): obj is AsyncGenerator { 2 | if (obj == null) { 3 | return false 4 | } 5 | 6 | const asyncIterator = (obj as { [Symbol.asyncIterator]?: unknown })?.[ 7 | Symbol.asyncIterator 8 | ] 9 | 10 | if (typeof asyncIterator !== 'function') { 11 | return false 12 | } 13 | 14 | const instance = obj as { next?: unknown } 15 | return typeof instance.next === 'function' 16 | } 17 | -------------------------------------------------------------------------------- /packages/utils/src/is-generator.ts: -------------------------------------------------------------------------------- 1 | export function isGenerator (obj: unknown): obj is Generator { 2 | if (obj == null) { 3 | return false 4 | } 5 | 6 | const iterator = (obj as { [Symbol.iterator]?: unknown })?.[Symbol.iterator] 7 | 8 | if (typeof iterator !== 'function') { 9 | return false 10 | } 11 | 12 | const instance = obj as { next?: unknown } 13 | 14 | return typeof instance.next === 'function' 15 | } 16 | -------------------------------------------------------------------------------- /packages/utils/src/is-promise.ts: -------------------------------------------------------------------------------- 1 | export function isPromise (thing: any): thing is Promise { 2 | if (thing == null) { 3 | return false 4 | } 5 | 6 | return typeof thing.then === 'function' && 7 | typeof thing.catch === 'function' && 8 | typeof thing.finally === 'function' 9 | } 10 | -------------------------------------------------------------------------------- /packages/utils/src/link-local-ip.ts: -------------------------------------------------------------------------------- 1 | export function isLinkLocalIp (ip: string): boolean { 2 | if (ip.startsWith('169.254.')) { 3 | return true 4 | } 5 | 6 | if (ip.toLowerCase().startsWith('fe80')) { 7 | return true 8 | } 9 | 10 | return false 11 | } 12 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-global-unicast.ts: -------------------------------------------------------------------------------- 1 | import { cidrContains } from '@chainsafe/netmask' 2 | import type { Multiaddr } from '@multiformats/multiaddr' 3 | 4 | const CODEC_IP6 = 0x29 5 | 6 | /** 7 | * Check if a given multiaddr is an IPv6 global unicast address 8 | */ 9 | export function isGlobalUnicast (ma: Multiaddr): boolean { 10 | try { 11 | const [[codec, value]] = ma.stringTuples() 12 | 13 | if (value == null) { 14 | return false 15 | } 16 | 17 | if (codec === CODEC_IP6) { 18 | return cidrContains('2000::/3', value) 19 | } 20 | } catch { 21 | 22 | } 23 | 24 | return false 25 | } 26 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-ip-based.ts: -------------------------------------------------------------------------------- 1 | import type { Multiaddr } from '@multiformats/multiaddr' 2 | 3 | const CODEC_IP4 = 0x04 4 | const CODEC_IP6 = 0x29 5 | 6 | /** 7 | * Check if a given multiaddr is IP-based 8 | */ 9 | export function isIpBased (ma: Multiaddr): boolean { 10 | try { 11 | const [[codec]] = ma.stringTuples() 12 | 13 | return codec === CODEC_IP4 || codec === CODEC_IP6 14 | } catch { 15 | 16 | } 17 | 18 | return false 19 | } 20 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-link-local.ts: -------------------------------------------------------------------------------- 1 | import type { Multiaddr } from '@multiformats/multiaddr' 2 | 3 | const CODEC_IP4 = 0x04 4 | const CODEC_IP6 = 0x29 5 | 6 | /** 7 | * Check if a given multiaddr is a link-local address 8 | */ 9 | export function isLinkLocal (ma: Multiaddr): boolean { 10 | try { 11 | const [[codec, value]] = ma.stringTuples() 12 | 13 | if (value == null) { 14 | return false 15 | } 16 | 17 | if (codec === CODEC_IP4) { 18 | return value.startsWith('169.254.') 19 | } 20 | 21 | if (codec === CODEC_IP6) { 22 | return value.toLowerCase().startsWith('fe80') 23 | } 24 | } catch { 25 | 26 | } 27 | 28 | return false 29 | } 30 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-loopback.ts: -------------------------------------------------------------------------------- 1 | import { isLoopbackAddr } from 'is-loopback-addr' 2 | import { isIpBased } from './is-ip-based.js' 3 | import type { Multiaddr } from '@multiformats/multiaddr' 4 | 5 | /** 6 | * Check if a given multiaddr is a loopback address. 7 | */ 8 | export function isLoopback (ma: Multiaddr): boolean { 9 | if (!isIpBased(ma)) { 10 | // not an IP based multiaddr, cannot be private 11 | return false 12 | } 13 | 14 | const { address } = ma.nodeAddress() 15 | 16 | return isLoopbackAddr(address) 17 | } 18 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-network-address.ts: -------------------------------------------------------------------------------- 1 | import type { Multiaddr } from '@multiformats/multiaddr' 2 | 3 | const CODEC_IP4 = 0x04 4 | const CODEC_IP6 = 0x29 5 | const CODEC_DNS = 0x35 6 | const CODEC_DNS4 = 0x36 7 | const CODEC_DNS6 = 0x37 8 | const CODEC_DNSADDR = 0x38 9 | 10 | const NETWORK_CODECS = [ 11 | CODEC_IP4, 12 | CODEC_IP6, 13 | CODEC_DNS, 14 | CODEC_DNS4, 15 | CODEC_DNS6, 16 | CODEC_DNSADDR 17 | ] 18 | 19 | /** 20 | * Check if a given multiaddr is a network address 21 | */ 22 | export function isNetworkAddress (ma: Multiaddr): boolean { 23 | try { 24 | const [[codec]] = ma.stringTuples() 25 | 26 | return NETWORK_CODECS.includes(codec) 27 | } catch { 28 | 29 | } 30 | 31 | return false 32 | } 33 | -------------------------------------------------------------------------------- /packages/utils/src/multiaddr/is-private.ts: -------------------------------------------------------------------------------- 1 | import { isPrivateIp } from '../private-ip.js' 2 | import { isIpBased } from './is-ip-based.js' 3 | import type { Multiaddr } from '@multiformats/multiaddr' 4 | 5 | /** 6 | * Check if a given multiaddr starts with a private address 7 | */ 8 | export function isPrivate (ma: Multiaddr): boolean { 9 | try { 10 | if (!isIpBased(ma)) { 11 | // not an IP based multiaddr, cannot be private 12 | return false 13 | } 14 | 15 | const [[, value]] = ma.stringTuples() 16 | 17 | if (value == null) { 18 | return false 19 | } 20 | 21 | return isPrivateIp(value) ?? false 22 | } catch { 23 | 24 | } 25 | 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /packages/utils/src/peer-queue.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from './queue/index.js' 2 | import type { Job } from './queue/job.js' 3 | import type { AbortOptions, PeerId } from '@libp2p/interface' 4 | 5 | export interface PeerQueueJobOptions extends AbortOptions { 6 | peerId: PeerId 7 | } 8 | 9 | /** 10 | * Extends Queue to add support for querying queued jobs by peer id 11 | */ 12 | export class PeerQueue extends Queue { 13 | has (peerId: PeerId): boolean { 14 | return this.find(peerId) != null 15 | } 16 | 17 | find (peerId: PeerId): Job | undefined { 18 | return this.queue.find(job => { 19 | return peerId.equals(job.options.peerId) 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/utils/src/priority-queue.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from './queue/index.js' 2 | import type { QueueInit } from './queue/index.js' 3 | import type { AbortOptions } from '@libp2p/interface' 4 | 5 | export interface PriorityQueueJobOptions extends AbortOptions { 6 | priority: number 7 | } 8 | 9 | export class PriorityQueue extends Queue { 10 | constructor (init: QueueInit = {}) { 11 | super({ 12 | ...init, 13 | sort: (a, b) => { 14 | if (a.options.priority > b.options.priority) { 15 | return -1 16 | } 17 | 18 | if (a.options.priority < b.options.priority) { 19 | return 1 20 | } 21 | 22 | return 0 23 | } 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/utils/src/queue/recipient.ts: -------------------------------------------------------------------------------- 1 | import { AbortError } from '@libp2p/interface' 2 | import pDefer from 'p-defer' 3 | import type { DeferredPromise } from 'p-defer' 4 | 5 | export class JobRecipient { 6 | public deferred: DeferredPromise 7 | public signal?: AbortSignal 8 | 9 | constructor (signal?: AbortSignal) { 10 | this.signal = signal 11 | this.deferred = pDefer() 12 | 13 | this.onAbort = this.onAbort.bind(this) 14 | this.signal?.addEventListener('abort', this.onAbort) 15 | } 16 | 17 | onAbort (): void { 18 | this.deferred.reject(this.signal?.reason ?? new AbortError()) 19 | } 20 | 21 | cleanup (): void { 22 | this.signal?.removeEventListener('abort', this.onAbort) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/utils/src/tracked-list.ts: -------------------------------------------------------------------------------- 1 | import type { Metrics } from '@libp2p/interface' 2 | 3 | export interface CreateTrackedListInit { 4 | /** 5 | * The metric name to use 6 | */ 7 | name: string 8 | 9 | /** 10 | * A metrics implementation 11 | */ 12 | metrics?: Metrics 13 | } 14 | 15 | export function trackedList (config: CreateTrackedListInit): V[] { 16 | const { name, metrics } = config 17 | const list: V[] = [] 18 | 19 | metrics?.registerMetric(name, { 20 | calculate: () => { 21 | return list.length 22 | } 23 | }) 24 | 25 | return list 26 | } 27 | -------------------------------------------------------------------------------- /packages/utils/test/close-source.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'aegir/chai' 2 | import { stubInterface } from 'sinon-ts' 3 | import { closeSource } from '../src/close-source.js' 4 | import type { Logger } from '@libp2p/interface' 5 | 6 | describe('close source', () => { 7 | it('should close an async iterable', async () => { 8 | let count = 0 9 | const iterable = (async function * (): AsyncGenerator { 10 | while (true) { 11 | yield count++ 12 | } 13 | })() 14 | 15 | const val = await iterable.next() 16 | expect(val).to.have.property('done', false) 17 | expect(val).to.have.property('value', 0) 18 | 19 | closeSource(iterable, stubInterface()) 20 | 21 | const last = await iterable.next() 22 | expect(last).to.have.property('done', true) 23 | expect(last).to.have.property('value', undefined) 24 | expect(count).to.equal(1) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /packages/utils/test/debounce.spec.ts: -------------------------------------------------------------------------------- 1 | import { stop } from '@libp2p/interface' 2 | import { expect } from 'aegir/chai' 3 | import delay from 'delay' 4 | import { debounce } from '../src/debounce.js' 5 | 6 | describe('debounce', () => { 7 | it('should debounce function', async () => { 8 | let invocations = 0 9 | const fn = (): void => { 10 | invocations++ 11 | } 12 | 13 | const debounced = debounce(fn, 10) 14 | 15 | debounced() 16 | debounced() 17 | debounced() 18 | debounced() 19 | debounced() 20 | 21 | await delay(500) 22 | 23 | expect(invocations).to.equal(1) 24 | }) 25 | 26 | it('should cancel debounced function', async () => { 27 | let invocations = 0 28 | const fn = (): void => { 29 | invocations++ 30 | } 31 | 32 | const debounced = debounce(fn, 10000) 33 | 34 | debounced() 35 | debounced() 36 | debounced() 37 | debounced() 38 | debounced() 39 | 40 | await stop(debounced) 41 | 42 | await delay(500) 43 | 44 | expect(invocations).to.equal(0) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/utils/test/fixtures/test-signal.ts: -------------------------------------------------------------------------------- 1 | import { TypedEventEmitter } from '@libp2p/interface' 2 | 3 | export interface TestSignalEvents { 4 | abort: CustomEvent 5 | } 6 | 7 | export class TestSignal extends TypedEventEmitter { 8 | public aborted: boolean 9 | public reason: any 10 | 11 | constructor () { 12 | super() 13 | 14 | this.aborted = false 15 | } 16 | 17 | throwIfAborted (): void { 18 | 19 | } 20 | 21 | onabort (): void { 22 | 23 | } 24 | 25 | abort (reason?: any): void { 26 | this.aborted = true 27 | this.reason = reason 28 | this.safeDispatchEvent('abort') 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/utils/test/priority-queue.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'aegir/chai' 2 | import { PriorityQueue } from '../src/priority-queue.js' 3 | 4 | describe('priority-queue', () => { 5 | it('adds with priority', async () => { 6 | const result: number[] = [] 7 | const queue = new PriorityQueue({ concurrency: 1 }) 8 | void queue.add(async () => result.push(1), { priority: 1 }) 9 | void queue.add(async () => result.push(0), { priority: 0 }) 10 | void queue.add(async () => result.push(1), { priority: 1 }) 11 | void queue.add(async () => result.push(2), { priority: 1 }) 12 | void queue.add(async () => result.push(3), { priority: 2 }) 13 | void queue.add(async () => result.push(0), { priority: -1 }) 14 | 15 | await queue.onEmpty() 16 | 17 | expect(result).to.deep.equal([1, 3, 1, 2, 0, 0]) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "aegir/src/config/tsconfig.aegir.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": [ 7 | "src", 8 | "test" 9 | ], 10 | "references": [ 11 | { 12 | "path": "../crypto" 13 | }, 14 | { 15 | "path": "../interface" 16 | }, 17 | { 18 | "path": "../logger" 19 | }, 20 | { 21 | "path": "../peer-id" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://typedoc.org/schema.json", 3 | "name": "libp2p", 4 | "readme": "./README.md", 5 | "headings": { 6 | "readme": false, 7 | "document": false 8 | }, 9 | "exclude": [ 10 | "doc", 11 | "interop", 12 | "packages/integration-tests" 13 | ] 14 | } 15 | --------------------------------------------------------------------------------