Skip to content

Commit

Permalink
chore: upgrade libp2p
Browse files Browse the repository at this point in the history
  • Loading branch information
achingbrain committed Mar 12, 2024
1 parent f950a79 commit 41befc7
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/helia/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"interface-blockstore": "^5.2.10",
"interface-datastore": "^8.2.11",
"ipns": "^9.0.0",
"libp2p": "^1.2.4",
"libp2p": "^1.3.0",
"multiformats": "^13.1.0"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/helia/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export async function createHelia (init: Partial<HeliaInit> = {}): Promise<Helia
libp2p = await createLibp2p<DefaultLibp2pServices>({
...init,
libp2p: {
dns: init.dns,
...init.libp2p,

// ignore the libp2p start parameter as it should be on the main init
Expand Down
1 change: 1 addition & 0 deletions packages/helia/src/utils/libp2p-defaults.browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface DefaultLibp2pServices extends Record<string, unknown> {
export function libp2pDefaults (options: Libp2pDefaultsOptions = {}): Libp2pOptions<DefaultLibp2pServices> {
return {
peerId: options.peerId,
dns: options.dns,
addresses: {
listen: [
'/webrtc'
Expand Down
1 change: 1 addition & 0 deletions packages/helia/src/utils/libp2p-defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface DefaultLibp2pServices extends Record<string, unknown> {
export function libp2pDefaults (options: Libp2pDefaultsOptions = {}): Libp2pOptions<DefaultLibp2pServices> {
return {
peerId: options.peerId,
dns: options.dns,
addresses: {
listen: [
'/ip4/0.0.0.0/tcp/0',
Expand Down
2 changes: 2 additions & 0 deletions packages/helia/src/utils/libp2p.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { libp2pDefaults } from './libp2p-defaults.js'
import type { DefaultLibp2pServices } from './libp2p-defaults.js'
import type { ComponentLogger, Libp2p, PeerId } from '@libp2p/interface'
import type { Keychain, KeychainInit } from '@libp2p/keychain'
import type { DNS } from '@multiformats/dns'
import type { Datastore } from 'interface-datastore'
import type { Libp2pOptions } from 'libp2p'

Expand All @@ -20,6 +21,7 @@ export interface CreateLibp2pOptions<T extends Record<string, unknown>> {
export interface Libp2pDefaultsOptions {
peerId?: PeerId
keychain?: KeychainInit
dns?: DNS
}

export async function createLibp2p <T extends Record<string, unknown> = DefaultLibp2pServices> (options: CreateLibp2pOptions<T>): Promise<Libp2p<T>> {
Expand Down
28 changes: 28 additions & 0 deletions packages/interop/src/ipns-dnslink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-env mocha */

import { ipns } from '@helia/ipns'
import { createHeliaNode } from './fixtures/create-helia.js'
import type { IPNS } from '@helia/ipns'
import type { HeliaLibp2p } from 'helia'

describe.only('@helia/ipns - dnslink', () => {
let helia: HeliaLibp2p
let name: IPNS

beforeEach(async () => {
helia = await createHeliaNode()
name = ipns(helia)
})

afterEach(async () => {
if (helia != null) {
await helia.stop()
}
})

it('should resolve ipfs.io', async () => {
const result = await name.resolveDns('ipfs.io')

console.info(result)
})
})
85 changes: 85 additions & 0 deletions packages/ipns/src/dnslink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { CodeError, type Logger } from '@libp2p/interface'
import { peerIdFromString } from '@libp2p/peer-id'
import { RecordType } from '@multiformats/dns'
import { CID } from 'multiformats/cid'
import type { ResolveDNSOptions } from './index.js'
import type { DNS } from '@multiformats/dns'

const MAX_RECURSIVE_DEPTH = 32

export const recursiveResolveDnslink = async (domain: string, depth: number, dns: DNS, log: Logger, options: ResolveDNSOptions = {}): Promise<string> => {
if (depth === 0) {
throw new Error('recursion limit exceeded')
}

const response = await dns.query(domain, {
...options,
types: [
RecordType.TXT
]
})

// TODO: support multiple dnslink records
for (const answer of response.Answer) {
try {
let result = answer.data

if (!result.startsWith('dnslink=')) {
// invalid record?
continue
}

result = result.replace('dnslink=', '')
// result is now a `/ipfs/<cid>` or `/ipns/<cid>` string
const [, protocol, domainOrCID, ...rest] = result.split('/') // e.g. ["", "ipfs", "<cid>"]

if (protocol === 'ipfs') {
try {
const cid = CID.parse(domainOrCID)

// if the result is a CID, we've reached the end of the recursion
return `/ipfs/${cid}${rest.length > 0 ? `/${rest.join('/')}` : ''}`
} catch {}
} else if (protocol === 'ipns') {
try {
const peerId = peerIdFromString(domainOrCID)

// if the result is a PeerId, we've reached the end of the recursion
return `/ipns/${peerId}${rest.length > 0 ? `/${rest.join('/')}` : ''}`
} catch {}

// if the result was another IPNS domain, try to follow it
return await recursiveResolveDnslink(domainOrCID, depth - 1, dns, log, options)
} else {
throw new CodeError(`Unknown protocol in DNSLink record for domain: ${domain}`, 'ERR_DNSLINK_NOT_FOUND')
}
} catch (err: any) {
log.error('could not parse DNS link record for domain %s, %s', domain, answer.data, err)
}
}

throw new CodeError(`No DNSLink records found for domain: ${domain}`, 'ERR_DNSLINK_NOT_FOUND')
}

export async function resolveDNSLink (domain: string, dns: DNS, log: Logger, options: ResolveDNSOptions = {}): Promise<string> {
try {
return await recursiveResolveDnslink(domain, options.maxRecursiveDepth ?? MAX_RECURSIVE_DEPTH, dns, log, options)
} catch (err: any) {
// If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND or ENODATA then throw the error
if (err.code !== 'ENOTFOUND' && err.code !== 'ERR_DNSLINK_NOT_FOUND' && err.code !== 'ENODATA') {
throw err
}

if (domain.startsWith('_dnslink.')) {
// The supplied domain contains a _dnslink component
// Check the non-_dnslink domain
domain = domain.replace('_dnslink.', '')
} else {
// Check the _dnslink subdomain
domain = `_dnslink.${domain}`
}

// If this throws then we propagate the error
return await recursiveResolveDnslink(domain, options.maxRecursiveDepth ?? MAX_RECURSIVE_DEPTH, dns, log, options)
}
}
1 change: 1 addition & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"@libp2p/logger": "^4.0.7",
"@libp2p/peer-collections": "^5.1.7",
"@libp2p/utils": "^5.2.6",
"@multiformats/dns": "^1.0.1",
"any-signal": "^4.1.1",
"blockstore-core": "^4.4.0",
"cborg": "^4.0.9",
Expand Down

0 comments on commit 41befc7

Please sign in to comment.