diff --git a/.gitignore b/.gitignore index f115d26..325f8ec 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ yarn.lock .vscode .tmp-compiled-docs tsconfig-doc-check.aegir.json +test-results diff --git a/examples/serving-websites-from-web-browsers/test-results/.last-run.json b/examples/serving-websites-from-web-browsers/test-results/.last-run.json deleted file mode 100644 index cbcc1fb..0000000 --- a/examples/serving-websites-from-web-browsers/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "passed", - "failedTests": [] -} \ No newline at end of file diff --git a/packages/http-peer-id-auth/test/index.spec.ts b/packages/http-peer-id-auth/test/index.spec.ts index 9d799b9..e4e0ec8 100644 --- a/packages/http-peer-id-auth/test/index.spec.ts +++ b/packages/http-peer-id-auth/test/index.spec.ts @@ -2,10 +2,10 @@ import { generateKeyPair, privateKeyFromProtobuf } from '@libp2p/crypto/keys' import { peerIdFromPrivateKey } from '@libp2p/peer-id' import { expect } from 'aegir/chai' -import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' +import { fromString as uint8ArrayFromString } from 'uint8arrays' import { ClientInitiatedHandshake, ServerInitiatedHandshake } from '../src/client.js' import { PEER_ID_AUTH_SCHEME, createServerChallenge, serverResponds } from '../src/index.js' -import { sign } from '../src/utils.js' +import { sign, verify } from '../src/utils.js' import type { PeerId, PrivateKey } from '@libp2p/interface' describe('@libp2p/http-peer-id-auth', () => { @@ -96,6 +96,27 @@ describe('@libp2p/http-peer-id-auth', () => { ['client-public-key', clientPubKeyEncoded], ['hostname', 'example.com'] ]) - expect(uint8ArrayToString(serverSig, 'base64urlpad')).to.equal('UA88qZbLUzmAxrD9KECbDCgSKAUBAvBHrOCF2X0uPLR1uUCF7qGfLPc7dw3Olo-LaFCDpk5sXN7TkLWPVvuXAA==') + + await expect(verify(serverKey.publicKey, PEER_ID_AUTH_SCHEME, [ + // cspell:disable-next-line + ['challenge-server', 'ERERERERERERERERERERERERERERERERERERERERERE='], + ['client-public-key', clientPubKeyEncoded], + ['hostname', 'example.com'] + ], serverSig)).to.eventually.be.true() + + await expect(verify(serverKey.publicKey, PEER_ID_AUTH_SCHEME, [ + // cspell:disable-next-line + ['challenge-server', 'ERERERERERERERERERERERERERERERERERERERERERE='], + ['client-public-key', clientPubKeyEncoded], + ['hostname', 'example.com'] + ], uint8ArrayFromString('UA88qZbLUzmAxrD9KECbDCgSKAUBAvBHrOCF2X0uPLR1uUCF7qGfLPc7dw3Olo-LaFCDpk5sXN7TkLWPVvuXAA==', 'base64urlpad'))).to.eventually.be.true() + + // TODO: safari generates non-deterministic different signatures? + await expect(verify(serverKey.publicKey, PEER_ID_AUTH_SCHEME, [ + // cspell:disable-next-line + ['challenge-server', 'ERERERERERERERERERERERERERERERERERERERERERE='], + ['client-public-key', clientPubKeyEncoded], + ['hostname', 'example.com'] + ], uint8ArrayFromString('hq3aR3scVMt8VrRopWYJHHJsEerdqnt-f_JvNQJ6R09yRy57Ut9_7G30TRHUqBtJb_Eh5kq3P5VvPWVQW43fBA==', 'base64urlpad'))).to.eventually.be.true() }) }) diff --git a/packages/http-utils/src/constants.ts b/packages/http-utils/src/constants.ts index 72bb937..6429232 100644 --- a/packages/http-utils/src/constants.ts +++ b/packages/http-utils/src/constants.ts @@ -1,15 +1,3 @@ -export const HTTP_PATH_CODEC = 0x01e1 -export const HTTP_CODEC = 0x01e0 -export const DNS_CODEC = 0x35 -export const DNS4_CODEC = 0x36 -export const DNS6_CODEC = 0x37 -export const DNSADDR_CODEC = 0x38 -export const DNS_CODECS = [ - DNS_CODEC, - DNS4_CODEC, - DNS6_CODEC, - DNSADDR_CODEC -] export const STATUS_CODES: Record = { 100: 'Continue', // RFC 7231 6.2.1 101: 'Switching Protocols', // RFC 7231 6.2.2 diff --git a/packages/http-utils/src/index.ts b/packages/http-utils/src/index.ts index e3be58c..60d4ba1 100644 --- a/packages/http-utils/src/index.ts +++ b/packages/http-utils/src/index.ts @@ -7,7 +7,7 @@ import { HTTPParser } from '@achingbrain/http-parser-js' import { InvalidParametersError, isPeerId, ProtocolError } from '@libp2p/interface' import { peerIdFromString } from '@libp2p/peer-id' -import { fromStringTuples, isMultiaddr, multiaddr } from '@multiformats/multiaddr' +import { isMultiaddr, multiaddr } from '@multiformats/multiaddr' import { multiaddrToUri } from '@multiformats/multiaddr-to-uri' import { uriToMultiaddr } from '@multiformats/uri-to-multiaddr' import { queuelessPushable } from 'it-queueless-pushable' @@ -17,11 +17,12 @@ import { base64pad } from 'multiformats/bases/base64' import { sha1 } from 'multiformats/hashes/sha1' import { Uint8ArrayList } from 'uint8arraylist' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import { DNS_CODECS, HTTP_CODEC, HTTP_PATH_CODEC } from './constants.js' import { Request } from './request.js' import type { AbortOptions, PeerId, Stream } from '@libp2p/interface' import type { Multiaddr } from '@multiformats/multiaddr' +const DNS_CODECS = ['dns', 'dns4', 'dns6', 'dnsaddr'] + /** * A subset of options passed to middleware */ @@ -244,9 +245,9 @@ export function toResource (resource: string | URL | PeerId | Multiaddr | Multia // check for `/http/` tuple and transform to URL if present if (Array.isArray(resource)) { for (const ma of resource) { - const stringTuples = ma.stringTuples() + const components = ma.getComponents() - if (stringTuples.find(([codec]) => codec === HTTP_CODEC) != null) { + if (components.some(({ name }) => name === 'http')) { const uri = multiaddrToUri(ma) return new URL(`${uri}${path ?? ''}`) } @@ -315,8 +316,8 @@ export function getHost (addresses: URL | Multiaddr[], headers: Headers): string // try to extract domain from DNS addresses if (!isValidHost(host) && Array.isArray(addresses)) { for (const address of addresses) { - const stringTuples = address.stringTuples() - const filtered = stringTuples.filter(([key]) => DNS_CODECS.includes(key))?.[0]?.[1] + const components = address.getComponents() + const filtered = components.filter(({ name }) => DNS_CODECS.includes(name))?.[0]?.value if (filtered != null) { host = filtered @@ -377,13 +378,14 @@ export function stripHTTPPath (addresses: Multiaddr[]): { httpPath: string, addr // strip http-path tuple but record the value if set let httpPath = '/' addresses = addresses.map(ma => { - return fromStringTuples( - ma.stringTuples().filter(t => { - if (t[0] === HTTP_PATH_CODEC && t[1] != null) { - httpPath = `/${t[1]}` + return multiaddr( + ma.getComponents().filter(component => { + if (component.name === 'http-path') { + httpPath = component.value ?? '/' + return false } - return t[0] !== HTTP_PATH_CODEC + return true }) ) }) diff --git a/packages/http/src/http.browser.ts b/packages/http/src/http.browser.ts index 0b260cb..eb008f1 100644 --- a/packages/http/src/http.browser.ts +++ b/packages/http/src/http.browser.ts @@ -181,11 +181,11 @@ export class HTTP implements HTTPInterface, Startable { private async sendRequest (resource: Multiaddr[] | URL, init: FetchInit): Promise { if (resource instanceof URL) { - this.log('making request with global fetch') + this.log('making request to %s with global fetch') return globalThis.fetch(resource, init) } - this.log('making request with libp2p fetch') + this.log('making request to %s with libp2p fetch', resource) const host = getHost(resource, getHeaders(init)) // strip http-path tuple but record the value if set