Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/integration-tests/test/fetch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-env mocha */

import { fetch } from '@libp2p/fetch'
import { identify } from '@libp2p/identify'
import { expect } from 'aegir/chai'
import { createLibp2p } from 'libp2p'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
Expand All @@ -12,7 +13,8 @@ import type { Libp2p } from '@libp2p/interface'
async function createNode (): Promise<Libp2p<{ fetch: Fetch }>> {
return createLibp2p(createBaseOptions({
services: {
fetch: fetch()
fetch: fetch(),
identify: identify()
}
}))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
import { identify } from '@libp2p/identify'
import { mplex } from '@libp2p/mplex'
import { plaintext } from '@libp2p/plaintext'
import { mergeOptions } from '@libp2p/utils'
import { webRTC } from '@libp2p/webrtc'
import { webSockets } from '@libp2p/websockets'
import { yamux } from '@libp2p/yamux'
Expand Down Expand Up @@ -31,9 +30,11 @@ export function createBaseOptions <T extends ServiceMap = Record<string, unknown
connectionGater: {
denyDialMultiaddr: async () => false
},
// @ts-expect-error overrides could cause services to have wrong type
services: {
identify: identify()
}
},
...overrides
}

// WebWorkers cannot do WebRTC so only add support if we are not in a worker
Expand All @@ -43,5 +44,6 @@ export function createBaseOptions <T extends ServiceMap = Record<string, unknown
options.transports?.push(webRTC())
}

return mergeOptions(options, overrides)
// @ts-expect-error overrides could cause services to have wrong type
return options
}
10 changes: 6 additions & 4 deletions packages/integration-tests/test/fixtures/base-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { identify } from '@libp2p/identify'
import { mplex } from '@libp2p/mplex'
import { plaintext } from '@libp2p/plaintext'
import { tcp } from '@libp2p/tcp'
import { mergeOptions } from '@libp2p/utils'
import { webRTC } from '@libp2p/webrtc'
import { webSockets } from '@libp2p/websockets'
import { yamux } from '@libp2p/yamux'
import type { ServiceMap } from '@libp2p/interface'
import type { Libp2pOptions } from 'libp2p'

export function createBaseOptions <T extends ServiceMap = Record<string, unknown>> (...overrides: Array<Libp2pOptions<T>>): Libp2pOptions<T> {
export function createBaseOptions <T extends ServiceMap = Record<string, unknown>> (overrides: Libp2pOptions<T> = {}): Libp2pOptions<T> {
const options: Libp2pOptions = {
addresses: {
listen: [
Expand All @@ -35,10 +34,13 @@ export function createBaseOptions <T extends ServiceMap = Record<string, unknown
connectionEncrypters: [
plaintext()
],
// @ts-expect-error overrides could cause services to have wrong type
services: {
identify: identify()
}
},
...overrides
}

return mergeOptions(options, ...overrides)
// @ts-expect-error overrides could cause services to have wrong type
return options
}
13 changes: 9 additions & 4 deletions packages/integration-tests/test/ping.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-env mocha */

import { identify } from '@libp2p/identify'
import { ping, PING_PROTOCOL } from '@libp2p/ping'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
Expand All @@ -15,17 +16,20 @@ describe('ping', () => {
nodes = await Promise.all([
createLibp2p(createBaseOptions({
services: {
ping: ping()
ping: ping(),
identify: identify()
}
})),
createLibp2p(createBaseOptions({
services: {
ping: ping()
ping: ping(),
identify: identify()
}
})),
createLibp2p(createBaseOptions({
services: {
ping: ping()
ping: ping(),
identify: identify()
}
}))
])
Expand Down Expand Up @@ -80,7 +84,8 @@ describe('ping', () => {
// Allow two outbound ping streams.
// It is not allowed by the spec, but this test needs to open two concurrent streams.
maxOutboundStreams: 2
})
}),
identify: identify()
}
}))
await client.peerStore.patch(remote.peerId, {
Expand Down
1 change: 0 additions & 1 deletion packages/keychain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"dependencies": {
"@libp2p/crypto": "^5.1.8",
"@libp2p/interface": "^2.11.0",
"@libp2p/utils": "^6.7.2",
"@noble/hashes": "^1.8.0",
"asn1js": "^3.0.6",
"interface-datastore": "^8.3.2",
Expand Down
11 changes: 11 additions & 0 deletions packages/keychain/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Default options for key derivation
*
* @see https://cryptosense.com/parametesr-choice-for-pbkdf2/
*/
export const DEK_INIT = {
keyLength: 512 / 8,
iterationCount: 10000,
salt: 'you should override this value with a crypto secure random number',
hash: 'sha2-512'
}
36 changes: 20 additions & 16 deletions packages/keychain/src/keychain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import { pbkdf2, randomBytes } from '@libp2p/crypto'
import { privateKeyToProtobuf } from '@libp2p/crypto/keys'
import { InvalidParametersError, NotFoundError, serviceCapabilities } from '@libp2p/interface'
import { mergeOptions } from '@libp2p/utils'
import { Key } from 'interface-datastore/key'
import { base58btc } from 'multiformats/bases/base58'
import { sha256 } from 'multiformats/hashes/sha2'
import sanitize from 'sanitize-filename'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { DEK_INIT } from './constants.ts'
import { exportPrivateKey } from './utils/export.js'
import { importPrivateKey } from './utils/import.js'
import type { KeychainComponents, KeychainInit, Keychain as KeychainInterface, KeyInfo } from './index.js'
Expand All @@ -26,16 +26,6 @@ const NIST = {
minIterationCount: 1000
}

const defaultOptions = {
// See https://cryptosense.com/parametesr-choice-for-pbkdf2/
dek: {
keyLength: 512 / 8,
iterationCount: 10000,
salt: 'you should override this value with a crypto secure random number',
hash: 'sha2-512'
}
}

function validateKeyName (name: string): boolean {
if (name == null) {
return false
Expand Down Expand Up @@ -101,7 +91,13 @@ export class Keychain implements KeychainInterface {
constructor (components: KeychainComponents, init: KeychainInit) {
this.components = components
this.log = components.logger.forComponent('libp2p:keychain')
this.init = mergeOptions(defaultOptions, init)
this.init = {
...init,
dek: {
...DEK_INIT,
...init.dek
}
}
this.self = init.selfKey ?? 'self'

// Enforce NIST SP 800-132
Expand Down Expand Up @@ -142,9 +138,13 @@ export class Keychain implements KeychainInterface {
* @returns {object}
*/
static generateOptions (): KeychainInit {
const options = Object.assign({}, defaultOptions)
const options = Object.assign({}, this.options)
const saltLength = Math.ceil(NIST.minSaltLength / 3) * 3 // no base64 padding
options.dek.salt = uint8ArrayToString(randomBytes(saltLength), 'base64')

if (options.dek != null) {
options.dek.salt = uint8ArrayToString(randomBytes(saltLength), 'base64')
}

return options
}

Expand All @@ -154,8 +154,12 @@ export class Keychain implements KeychainInterface {
*
* @returns {object}
*/
static get options (): typeof defaultOptions {
return defaultOptions
static get options (): KeychainInit {
return {
dek: {
...DEK_INIT
}
}
}

async findKeyByName (name: string): Promise<KeyInfo> {
Expand Down
28 changes: 3 additions & 25 deletions packages/libp2p/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
import { FaultTolerance, InvalidParametersError } from '@libp2p/interface'
import { mergeOptions } from '@libp2p/utils'
import { dnsaddrResolver } from './connection-manager/resolvers/dnsaddr.ts'
import { InvalidParametersError } from '@libp2p/interface'
import type { Libp2pInit } from './index.js'
import type { ServiceMap } from '@libp2p/interface'
import type { Multiaddr } from '@multiformats/multiaddr'

const DefaultConfig: Libp2pInit = {
addresses: {
listen: [],
announce: [],
noAnnounce: [],
announceFilter: (multiaddrs: Multiaddr[]) => multiaddrs
},
connectionManager: {
resolvers: {
dnsaddr: dnsaddrResolver
}
},
transportManager: {
faultTolerance: FaultTolerance.FATAL_ALL
}
}

export async function validateConfig <T extends ServiceMap = Record<string, unknown>> (opts: Libp2pInit<T>): Promise<Libp2pInit<T>> {
const resultingOptions: Libp2pInit<T> = mergeOptions(DefaultConfig, opts)

if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) {
if (opts.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) {
throw new InvalidParametersError('Private network is enforced, but no protector was provided')
}

return resultingOptions
return opts
}
13 changes: 6 additions & 7 deletions packages/libp2p/src/registrar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { InvalidParametersError } from '@libp2p/interface'
import { mergeOptions, trackedMap } from '@libp2p/utils'
import { trackedMap } from '@libp2p/utils'
import { DuplicateProtocolHandlerError, UnhandledProtocolError } from './errors.js'
import type { IdentifyResult, Libp2pEvents, Logger, PeerUpdate, PeerId, PeerStore, Topology, StreamHandler, StreamHandlerRecord, StreamHandlerOptions, AbortOptions, Metrics, StreamMiddleware } from '@libp2p/interface'
import type { Registrar as RegistrarInterface } from '@libp2p/interface-internal'
Expand Down Expand Up @@ -95,14 +95,13 @@ export class Registrar implements RegistrarInterface {
throw new DuplicateProtocolHandlerError(`Handler already registered for protocol ${protocol}`)
}

const options = mergeOptions.bind({ ignoreUndefined: true })({
maxInboundStreams: DEFAULT_MAX_INBOUND_STREAMS,
maxOutboundStreams: DEFAULT_MAX_OUTBOUND_STREAMS
}, opts)

this.handlers.set(protocol, {
handler,
options
options: {
maxInboundStreams: DEFAULT_MAX_INBOUND_STREAMS,
maxOutboundStreams: DEFAULT_MAX_OUTBOUND_STREAMS,
...opts
}
})

// Add new protocol to self protocols in the peer store
Expand Down
1 change: 0 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"cborg": "^4.2.14",
"delay": "^6.0.0",
"is-loopback-addr": "^2.0.2",
"is-plain-obj": "^4.1.0",
"it-length-prefixed": "^10.0.1",
"it-pipe": "^3.0.1",
"it-pushable": "^3.2.3",
Expand Down
1 change: 0 additions & 1 deletion packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export * from './is-generator.js'
export * from './is-promise.js'
export * from './length-prefixed-decoder.js'
export * from './link-local-ip.js'
export * from './merge-options.js'
export * from './mock-muxer.js'
export * from './mock-stream.js'
export * from './moving-average.js'
Expand Down
Loading
Loading