diff --git a/package.json b/package.json index 77c7a20d3..71538bfc5 100644 --- a/package.json +++ b/package.json @@ -152,9 +152,10 @@ "@ipld/dag-cbor": "^9.0.0", "@ipld/dag-json": "^10.0.0", "@ipld/dag-pb": "^4.0.0", - "@libp2p/interface": "^1.2.0", - "@libp2p/logger": "^4.0.10", - "@libp2p/peer-id": "^4.0.10", + "@libp2p/crypto": "^5.0.0", + "@libp2p/interface": "^2.0.0", + "@libp2p/logger": "^5.0.0", + "@libp2p/peer-id": "^5.0.0", "@multiformats/multiaddr": "^12.2.1", "@multiformats/multiaddr-to-uri": "^10.0.1", "any-signal": "^4.1.1", @@ -184,21 +185,19 @@ }, "devDependencies": { "@ipld/car": "^5.0.3", - "@libp2p/crypto": "^4.0.6", - "@libp2p/peer-id-factory": "^4.0.10", "@types/pako": "^2.0.3", "@types/readable-stream": "^4.0.11", "@types/sinon": "^17.0.3", "@web-std/file": "^3.0.3", "aegir": "^44.0.1", - "blockstore-core": "^4.4.1", + "blockstore-core": "^5.0.0", "buffer": "^6.0.3", "delay": "^6.0.0", "did-jwt": "^8.0.4", "interface-blockstore": "^5.2.10", "ipfs-unixfs-importer": "^15.2.5", - "ipfsd-ctl": "^14.0.0", - "ipns": "^9.1.0", + "ipfsd-ctl": "^14.1.3", + "ipns": "^10.0.0", "is-ipfs": "^8.0.1", "iso-random-stream": "^2.0.2", "it-buffer-stream": "^3.0.0", @@ -237,5 +236,9 @@ "fs/promises": false, "node:fs/promises": false }, - "sideEffects": false + "sideEffects": false, + "overrides": { + "@libp2p/interface": "^2.0.0", + "@libp2p/logger": "^5.0.0" + } } diff --git a/src/lib/errors.ts b/src/lib/errors.ts index c79e60e8b..45c4c3de5 100644 --- a/src/lib/errors.ts +++ b/src/lib/errors.ts @@ -21,3 +21,10 @@ export class HTTPError extends Error { this.response = response } } + +export class InvalidMtimeError extends Error { + constructor (message = 'Invalid mtime') { + super(message) + this.name = 'InvalidMtimeError' + } +} diff --git a/src/lib/files/normalise-content.browser.ts b/src/lib/files/normalise-content.browser.ts index 733199544..a36b32ff0 100644 --- a/src/lib/files/normalise-content.browser.ts +++ b/src/lib/files/normalise-content.browser.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface' +import { InvalidParametersError } from '@libp2p/interface' import browserStreamToIt from 'browser-readablestream-to-it' import all from 'it-all' import itPeekable from 'it-peekable' @@ -59,7 +59,7 @@ export async function normaliseContent (input: ToContent): Promise { } // eslint-disable-next-line @typescript-eslint/no-base-to-string - throw new CodeError(`Unexpected input: ${input}`, 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError(`Unexpected input: ${input}`) } async function itToBlob (stream: AsyncIterable | Iterable): Promise { diff --git a/src/lib/files/normalise-content.ts b/src/lib/files/normalise-content.ts index d592bd039..33ebd2807 100644 --- a/src/lib/files/normalise-content.ts +++ b/src/lib/files/normalise-content.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface' +import { InvalidParametersError } from '@libp2p/interface' import blobToIt from 'blob-to-it' import browserStreamToIt from 'browser-readablestream-to-it' import all from 'it-all' @@ -66,7 +66,7 @@ export async function normaliseContent (input: ToContent): Promise | number[]): Uint8Array { diff --git a/src/lib/files/utils.ts b/src/lib/files/utils.ts index 383af5c4d..55281d6e7 100644 --- a/src/lib/files/utils.ts +++ b/src/lib/files/utils.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface' +import { InvalidMtimeError } from '../errors.js' import type { ImportCandidate } from '../../index.js' import type { Mtime, MtimeLike } from 'ipfs-unixfs' @@ -103,7 +103,7 @@ export function parseMtime (mtime?: MtimeLike): Mtime | undefined { } if (mtime.nsecs != null && (mtime.nsecs < 0 || mtime.nsecs > 999999999)) { - throw new CodeError('mtime-nsecs must be within the range [0,999999999]', 'ERR_INVALID_MTIME_NSECS') + throw new InvalidMtimeError('mtime-nsecs must be within the range [0,999999999]') } return mtime diff --git a/src/lib/glob-source.ts b/src/lib/glob-source.ts index a4818c6c6..90d0650c5 100644 --- a/src/lib/glob-source.ts +++ b/src/lib/glob-source.ts @@ -2,7 +2,7 @@ import fs from 'node:fs' import fsp from 'node:fs/promises' import os from 'node:os' import Path from 'node:path' -import { CodeError } from '@libp2p/interface' +import { InvalidParametersError } from '@libp2p/interface' import glob from 'it-glob' import type { MtimeLike } from 'ipfs-unixfs' import type { Options as GlobOptions } from 'it-glob' @@ -53,7 +53,7 @@ export async function * globSource (cwd: string, pattern: string, options?: Glob options = options ?? {} if (typeof pattern !== 'string') { - throw new CodeError('Pattern must be a string', 'ERR_INVALID_PATH', { pattern }) + throw new InvalidParametersError('Pattern must be a string') } if (!Path.isAbsolute(cwd)) { diff --git a/src/lib/pins/normalise-input.ts b/src/lib/pins/normalise-input.ts index 0f69c8a0e..acaaca67b 100644 --- a/src/lib/pins/normalise-input.ts +++ b/src/lib/pins/normalise-input.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface' +import { InvalidParametersError } from '@libp2p/interface' import { CID } from 'multiformats/cid' export interface Pinnable { @@ -56,7 +56,7 @@ function isCID (thing: any): thing is CID { export async function * normaliseInput (input: Source): AsyncGenerator { // must give us something if (input === null || input === undefined) { - throw new CodeError(`Unexpected input: ${input}`, 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError(`Unexpected input: ${input}`) } // CID @@ -115,7 +115,7 @@ export async function * normaliseInput (input: Source): AsyncGenerator { return } - throw new CodeError(`Unexpected input: ${typeof input}`, 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError(`Unexpected input: ${typeof input}`) } // AsyncIterable @@ -151,17 +151,17 @@ export async function * normaliseInput (input: Source): AsyncGenerator { return } - throw new CodeError(`Unexpected input: ${typeof input}`, 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError(`Unexpected input: ${typeof input}`) } - throw new CodeError(`Unexpected input: ${typeof input}`, 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError(`Unexpected input: ${typeof input}`) } function toPin (input: Pinnable): Pin { const path = input.cid ?? `${input.path}` if (path == null) { - throw new CodeError('Unexpected input: Please path either a CID or an IPFS path', 'ERR_UNEXPECTED_INPUT') + throw new InvalidParametersError('Unexpected input: Please path either a CID or an IPFS path') } const pin: Pin = { diff --git a/src/pubsub/subscribe.ts b/src/pubsub/subscribe.ts index 0c48177a2..5487cdbde 100644 --- a/src/pubsub/subscribe.ts +++ b/src/pubsub/subscribe.ts @@ -1,3 +1,4 @@ +import { publicKeyFromProtobuf } from '@libp2p/crypto/keys' import { logger } from '@libp2p/logger' import { peerIdFromString } from '@libp2p/peer-id' import { textToUrlSafeRpc, rpcToText, rpcToBytes, rpcToBigInt } from '../lib/http-rpc-wire-format.js' @@ -104,7 +105,8 @@ async function readMessages (response: ExtendedResponse, { onMessage, onEnd, onE data: rpcToBytes(msg.data), sequenceNumber: rpcToBigInt(msg.seqno), topic: rpcToText(msg.topicIDs[0]), - key: rpcToBytes(msg.key ?? 'u'), + // @ts-expect-error kubo does not supply the key + key: msg.key != null ? publicKeyFromProtobuf(rpcToBytes(msg.key ?? 'u')) : undefined, signature: rpcToBytes(msg.signature ?? 'u') }) } else { diff --git a/test/interface-tests.spec.ts b/test/interface-tests.spec.ts index 1d6cb57da..e99de974d 100644 --- a/test/interface-tests.spec.ts +++ b/test/interface-tests.spec.ts @@ -1,5 +1,6 @@ /* eslint-env mocha */ +import { path } from 'kubo' import { isWindows, isFirefox, isChrome } from './constants.js' import * as tests from './interface-tests/src/index.js' import { factory } from './utils/factory.js' @@ -261,13 +262,12 @@ function executeTests (commonFactory: Factory): void { describe('kubo-rpc-client tests against kubo', function () { void (async function () { - const { path } = await import('kubo') /** * @type {string|undefined} */ const commonFactory = factory({ type: 'kubo', - bin: path(), + bin: path?.(), test: true }) describe('kubo RPC client interface tests', function () { diff --git a/test/interface-tests/src/key/gen.ts b/test/interface-tests/src/key/gen.ts index a6957e3f1..34858ff39 100644 --- a/test/interface-tests/src/key/gen.ts +++ b/test/interface-tests/src/key/gen.ts @@ -1,6 +1,5 @@ /* eslint-env mocha */ -import { keys } from '@libp2p/crypto' import { expect } from 'aegir/chai' import { nanoid } from 'nanoid' import { getDescribe, getIt, type MochaConfig } from '../utils/mocha.js' @@ -8,14 +7,11 @@ import type { KuboRPCClient } from '../../../../src/index.js' import type { KeyType } from '../../../../src/key/index.js' import type { Factory, KuboNode } from 'ipfsd-ctl' -const { supportedKeys } = keys - interface KeyTest { opts: { type?: KeyType size?: number } - expectedType: any } export function testGen (factory: Factory, options: MochaConfig): void { @@ -25,12 +21,10 @@ export function testGen (factory: Factory, options: MochaConfig): void describe('.key.gen', () => { const keyTypes: KeyTest[] = [ { - opts: { type: 'ed25519' }, - expectedType: supportedKeys.ed25519.Ed25519PrivateKey + opts: { type: 'ed25519' } }, { - opts: { }, - expectedType: supportedKeys.ed25519.Ed25519PrivateKey + opts: { } } ] diff --git a/test/interface-tests/src/key/import.ts b/test/interface-tests/src/key/import.ts index 76958f43d..d7636c8b3 100644 --- a/test/interface-tests/src/key/import.ts +++ b/test/interface-tests/src/key/import.ts @@ -1,11 +1,14 @@ /* eslint-env mocha */ -import { keys } from '@libp2p/crypto' +import { AES_GCM } from '@libp2p/crypto/ciphers' +import { privateKeyToProtobuf, generateKeyPair } from '@libp2p/crypto/keys' import { expect } from 'aegir/chai' +import { base64 } from 'multiformats/bases/base64' import { nanoid } from 'nanoid' import { getDescribe, getIt, type MochaConfig } from '../utils/mocha.js' import type { KuboRPCClient } from '../../../../src/index.js' import type { Factory, KuboNode } from 'ipfsd-ctl' +import type { Multibase } from 'multiformats/bases/interface' export function testImport (factory: Factory, options: MochaConfig): void { const describe = getDescribe(options) @@ -25,8 +28,8 @@ export function testImport (factory: Factory, options: MochaConfig): v it('should import an exported key', async () => { const password = nanoid() - const key = await keys.generateKeyPair('Ed25519') - const exported = await key.export(password) + const key = await generateKeyPair('Ed25519') + const exported = await exporter(privateKeyToProtobuf(key), password) const importedKey = await ipfs.key.import('clone', exported, password) expect(importedKey).to.exist() @@ -35,3 +38,9 @@ export function testImport (factory: Factory, options: MochaConfig): v }) }) } + +async function exporter (privateKey: Uint8Array, password: string): Promise> { + const cipher = AES_GCM.create() + const encryptedKey = await cipher.encrypt(privateKey, password) + return base64.encode(encryptedKey) +} diff --git a/test/interface-tests/src/name-pubsub/cancel.ts b/test/interface-tests/src/name-pubsub/cancel.ts index 9810af79b..2fb3cc4b1 100644 --- a/test/interface-tests/src/name-pubsub/cancel.ts +++ b/test/interface-tests/src/name-pubsub/cancel.ts @@ -1,5 +1,6 @@ /* eslint-env mocha */ -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' import { expect } from 'aegir/chai' import all from 'it-all' import { getDescribe, getIt, type MochaConfig } from '../utils/mocha.js' @@ -37,7 +38,7 @@ export function testCancel (factory: Factory, options: MochaConfig): v it('should cancel a subscription correctly returning true', async function () { this.timeout(300 * 1000) - const peerId = await createEd25519PeerId() + const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) const id = peerId.toString() const ipnsPath = `/ipns/${id}` diff --git a/test/interface-tests/src/name-pubsub/pubsub.ts b/test/interface-tests/src/name-pubsub/pubsub.ts index e990a0e68..7cf3a8c32 100644 --- a/test/interface-tests/src/name-pubsub/pubsub.ts +++ b/test/interface-tests/src/name-pubsub/pubsub.ts @@ -1,9 +1,10 @@ /* eslint-env mocha */ -import { peerIdFromKeys, peerIdFromString } from '@libp2p/peer-id' +import { publicKeyFromProtobuf } from '@libp2p/crypto/keys' +import { peerIdFromPublicKey, peerIdFromString } from '@libp2p/peer-id' import { expect } from 'aegir/chai' import delay from 'delay' -import * as ipns from 'ipns' +import { multihashToIPNSRoutingKey, unmarshalIPNSRecord } from 'ipns' import { ipnsValidator } from 'ipns/validator' import last from 'it-last' import { base58btc } from 'multiformats/bases/base58' @@ -80,7 +81,7 @@ export function testPubsub (factory: Factory, options: MochaConfig): v return subscribed } - const routingKey = ipns.peerIdToRoutingKey(idA.id) + const routingKey = multihashToIPNSRoutingKey(idA.id.toMultihash()) const topic = `${namespace}${uint8ArrayToString(routingKey, 'base64url')}` await expect(last(nodeB.name.resolve(idA.id))) @@ -147,7 +148,7 @@ export function testPubsub (factory: Factory, options: MochaConfig): v 'ipns-base': 'b58mh' }) - const routingKey = ipns.peerIdToRoutingKey(peerIdFromString(testAccount.id)) + const routingKey = multihashToIPNSRoutingKey(peerIdFromString(testAccount.id).toMultihash()) const topic = `${namespace}${uint8ArrayToString(routingKey, 'base64url')}` await nodeB.pubsub.subscribe(topic, checkMessage) @@ -159,7 +160,7 @@ export function testPubsub (factory: Factory, options: MochaConfig): v throw new Error('Pubsub handler not invoked') } - const publishedMessageData = ipns.unmarshal(publishedMessage.data) + const publishedMessageData = unmarshalIPNSRecord(publishedMessage.data) if (publishedMessageData.pubKey == null) { throw new Error('No public key found in message data') @@ -170,7 +171,8 @@ export function testPubsub (factory: Factory, options: MochaConfig): v } const messageKey = publishedMessage.from - const pubKeyPeerId = await peerIdFromKeys(publishedMessageData.pubKey) + const publicKey = publicKeyFromProtobuf(publishedMessageData.pubKey) + const pubKeyPeerId = peerIdFromPublicKey(publicKey) expect(pubKeyPeerId.toString()).not.to.equal(messageKey.toString()) expect(pubKeyPeerId.toString()).to.equal(testAccount.id) diff --git a/test/interface-tests/src/name/publish.ts b/test/interface-tests/src/name/publish.ts index 1aed28859..40d05009a 100644 --- a/test/interface-tests/src/name/publish.ts +++ b/test/interface-tests/src/name/publish.ts @@ -1,8 +1,10 @@ /* eslint-env mocha */ -import { peerIdFromString } from '@libp2p/peer-id' +import { peerIdFromCID } from '@libp2p/peer-id' import { expect } from 'aegir/chai' import last from 'it-last' +import { base36 } from 'multiformats/bases/base36' +import { CID } from 'multiformats/cid' import { nanoid } from 'nanoid' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { getDescribe, getIt, type MochaConfig } from '../utils/mocha.js' @@ -53,7 +55,7 @@ export function testPublish (factory: Factory, options: MochaConfig): const res = await ipfs.name.publish(value, { allowOffline: true }) expect(res).to.exist() - expect(peerIdFromString(res.name).toString()).to.equal(peerIdFromString(self.id).toString()) + expect(peerIdFromCID(CID.parse(res.name, base36)).toString()).to.equal(peerIdFromCID(CID.parse(self.id, base36)).toString()) expect(res.value).to.equal(`/ipfs/${value}`) }) @@ -84,7 +86,7 @@ export function testPublish (factory: Factory, options: MochaConfig): const res = await ipfs.name.publish(value, options) expect(res).to.exist() - expect(peerIdFromString(res.name).toString()).to.equal(peerIdFromString(self.id).toString()) + expect(peerIdFromCID(CID.parse(res.name, base36)).toString()).to.equal(peerIdFromCID(CID.parse(self.id, base36)).toString()) expect(res.value).to.equal(`/ipfs/${value}`) }) @@ -104,7 +106,7 @@ export function testPublish (factory: Factory, options: MochaConfig): const res = await ipfs.name.publish(value, options) expect(res).to.exist() - expect(peerIdFromString(res.name).toString()).to.equal(peerIdFromString(key.id).toString()) + expect(peerIdFromCID(CID.parse(res.name, base36)).toString()).to.equal(peerIdFromCID(CID.parse(key.id, base36)).toString()) expect(res.value).to.equal(`/ipfs/${value}`) }) }) diff --git a/test/interface-tests/src/name/resolve.ts b/test/interface-tests/src/name/resolve.ts index 6a2c7c66c..853cc568d 100644 --- a/test/interface-tests/src/name/resolve.ts +++ b/test/interface-tests/src/name/resolve.ts @@ -59,7 +59,7 @@ export function testResolve (factory: Factory, options: MochaConfig): // Represent Peer ID as CIDv1 Base32 // https://github.com/libp2p/specs/blob/master/RFC/0001-text-peerid-cid.md - const keyCid = CID.createV1(0x72, Digest.decode(peerIdFromString(peerId.toString()).toBytes())) + const keyCid = CID.createV1(0x72, Digest.decode(peerIdFromString(peerId.toString()).toMultihash().bytes)) const resolvedPath = await last(ipfs.name.resolve(`/ipns/${keyCid}`)) expect(resolvedPath).to.equal(`/ipfs/${cid}`) diff --git a/test/interface-tests/src/utils/wait-for.ts b/test/interface-tests/src/utils/wait-for.ts index b115840d2..4aa617592 100644 --- a/test/interface-tests/src/utils/wait-for.ts +++ b/test/interface-tests/src/utils/wait-for.ts @@ -1,4 +1,4 @@ -import { CodeError } from '@libp2p/interface' +import { TimeoutError } from '@libp2p/interface' import delay from 'delay' export interface Test { @@ -25,7 +25,7 @@ export default async function waitFor (test: Test, options?: Options): Promise start + opts.timeout) { - throw new CodeError(`Timed out waiting for ${opts.name}`, 'ERR_TIMEOUT') + throw new TimeoutError(`Timed out waiting for ${opts.name}`) } await delay(opts.interval)