@helia/verified-fetch 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/dist/index.min.js +8 -19
- package/dist/src/index.d.ts +29 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +41 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/parse-resource.d.ts +2 -2
- package/dist/src/utils/parse-url-string.d.ts +2 -2
- package/dist/src/utils/parse-url-string.d.ts.map +1 -1
- package/dist/src/utils/parse-url-string.js +33 -4
- package/dist/src/utils/parse-url-string.js.map +1 -1
- package/dist/src/verified-fetch.d.ts +2 -1
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +1 -7
- package/dist/src/verified-fetch.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +49 -8
- package/src/utils/parse-resource.ts +2 -2
- package/src/utils/parse-url-string.ts +39 -7
- package/src/verified-fetch.ts +3 -8
|
@@ -2,7 +2,7 @@ import { peerIdFromString } from '@libp2p/peer-id'
|
|
|
2
2
|
import { CID } from 'multiformats/cid'
|
|
3
3
|
import { TLRU } from './tlru.js'
|
|
4
4
|
import type { RequestFormatShorthand } from '../types.js'
|
|
5
|
-
import type { IPNS,
|
|
5
|
+
import type { IPNS, ResolveDNSLinkProgressEvents, ResolveResult } from '@helia/ipns'
|
|
6
6
|
import type { ComponentLogger } from '@libp2p/interface'
|
|
7
7
|
import type { ProgressOptions } from 'progress-events'
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ export interface ParseUrlStringInput {
|
|
|
13
13
|
ipns: IPNS
|
|
14
14
|
logger: ComponentLogger
|
|
15
15
|
}
|
|
16
|
-
export interface ParseUrlStringOptions extends ProgressOptions<
|
|
16
|
+
export interface ParseUrlStringOptions extends ProgressOptions<ResolveDNSLinkProgressEvents> {
|
|
17
17
|
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -33,7 +33,7 @@ export interface ParsedUrlStringResults {
|
|
|
33
33
|
const URL_REGEX = /^(?<protocol>ip[fn]s):\/\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/
|
|
34
34
|
const PATH_REGEX = /^\/(?<protocol>ip[fn]s)\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/
|
|
35
35
|
const PATH_GATEWAY_REGEX = /^https?:\/\/(.*[^/])\/(?<protocol>ip[fn]s)\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/
|
|
36
|
-
const SUBDOMAIN_GATEWAY_REGEX = /^https?:\/\/(?<cidOrPeerIdOrDnsLink>[
|
|
36
|
+
const SUBDOMAIN_GATEWAY_REGEX = /^https?:\/\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\.(?<protocol>ip[fn]s)\.([^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/
|
|
37
37
|
|
|
38
38
|
function matchURLString (urlString: string): Record<string, string> {
|
|
39
39
|
for (const pattern of [URL_REGEX, PATH_REGEX, PATH_GATEWAY_REGEX, SUBDOMAIN_GATEWAY_REGEX]) {
|
|
@@ -47,6 +47,34 @@ function matchURLString (urlString: string): Record<string, string> {
|
|
|
47
47
|
throw new TypeError(`Invalid URL: ${urlString}, please use ipfs://, ipns://, or gateway URLs only`)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* For dnslinks see https://specs.ipfs.tech/http-gateways/subdomain-gateway/#host-request-header
|
|
52
|
+
* DNSLink names include . which means they must be inlined into a single DNS label to provide unique origin and work with wildcard TLS certificates.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
// DNS label can have up to 63 characters, consisting of alphanumeric
|
|
56
|
+
// characters or hyphens -, but it must not start or end with a hyphen.
|
|
57
|
+
const dnsLabelRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Checks if label looks like inlined DNSLink.
|
|
61
|
+
* (https://specs.ipfs.tech/http-gateways/subdomain-gateway/#host-request-header)
|
|
62
|
+
*/
|
|
63
|
+
function isInlinedDnsLink (label: string): boolean {
|
|
64
|
+
return dnsLabelRegex.test(label) && label.includes('-') && !label.includes('.')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* DNSLink label decoding
|
|
69
|
+
* * Every standalone - is replaced with .
|
|
70
|
+
* * Every remaining -- is replaced with -
|
|
71
|
+
*
|
|
72
|
+
* @example en-wikipedia--on--ipfs-org.ipns.example.net -> example.net/ipns/en.wikipedia-on-ipfs.org
|
|
73
|
+
*/
|
|
74
|
+
function dnsLinkLabelDecoder (linkLabel: string): string {
|
|
75
|
+
return linkLabel.replace(/--/g, '%').replace(/-/g, '.').replace(/%/g, '-')
|
|
76
|
+
}
|
|
77
|
+
|
|
50
78
|
/**
|
|
51
79
|
* A function that parses ipfs:// and ipns:// URLs, returning an object with easily recognizable properties.
|
|
52
80
|
*
|
|
@@ -80,7 +108,6 @@ export async function parseUrlString ({ urlString, ipns, logger }: ParseUrlStrin
|
|
|
80
108
|
// protocol is ipns
|
|
81
109
|
log.trace('Attempting to resolve PeerId for %s', cidOrPeerIdOrDnsLink)
|
|
82
110
|
let peerId = null
|
|
83
|
-
|
|
84
111
|
try {
|
|
85
112
|
peerId = peerIdFromString(cidOrPeerIdOrDnsLink)
|
|
86
113
|
resolveResult = await ipns.resolve(peerId, { onProgress: options?.onProgress })
|
|
@@ -99,13 +126,18 @@ export async function parseUrlString ({ urlString, ipns, logger }: ParseUrlStrin
|
|
|
99
126
|
}
|
|
100
127
|
|
|
101
128
|
if (cid == null) {
|
|
102
|
-
|
|
129
|
+
let decodedDnsLinkLabel = cidOrPeerIdOrDnsLink
|
|
130
|
+
if (isInlinedDnsLink(cidOrPeerIdOrDnsLink)) {
|
|
131
|
+
decodedDnsLinkLabel = dnsLinkLabelDecoder(cidOrPeerIdOrDnsLink)
|
|
132
|
+
log.trace('decoded dnslink from "%s" to "%s"', cidOrPeerIdOrDnsLink, decodedDnsLinkLabel)
|
|
133
|
+
}
|
|
134
|
+
log.trace('Attempting to resolve DNSLink for %s', decodedDnsLinkLabel)
|
|
103
135
|
|
|
104
136
|
try {
|
|
105
|
-
resolveResult = await ipns.
|
|
137
|
+
resolveResult = await ipns.resolveDNSLink(decodedDnsLinkLabel, { onProgress: options?.onProgress })
|
|
106
138
|
cid = resolveResult?.cid
|
|
107
139
|
resolvedPath = resolveResult?.path
|
|
108
|
-
log.trace('resolved %s to %c',
|
|
140
|
+
log.trace('resolved %s to %c', decodedDnsLinkLabel, cid)
|
|
109
141
|
ipnsCache.set(cidOrPeerIdOrDnsLink, resolveResult, 60 * 1000 * 2)
|
|
110
142
|
} catch (err: any) {
|
|
111
143
|
log.error('Could not resolve DnsLink for "%s"', cidOrPeerIdOrDnsLink, err)
|
package/src/verified-fetch.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { car } from '@helia/car'
|
|
2
|
-
import { ipns as heliaIpns, type
|
|
3
|
-
import { dnsJsonOverHttps } from '@helia/ipns/dns-resolvers'
|
|
2
|
+
import { ipns as heliaIpns, type IPNS } from '@helia/ipns'
|
|
4
3
|
import { unixfs as heliaUnixFs, type UnixFS as HeliaUnixFs, type UnixFSStats } from '@helia/unixfs'
|
|
5
4
|
import * as ipldDagCbor from '@ipld/dag-cbor'
|
|
6
5
|
import * as ipldDagJson from '@ipld/dag-json'
|
|
@@ -29,6 +28,7 @@ import type { CIDDetail, ContentTypeParser, Resource, VerifiedFetchInit as Verif
|
|
|
29
28
|
import type { RequestFormatShorthand } from './types.js'
|
|
30
29
|
import type { Helia } from '@helia/interface'
|
|
31
30
|
import type { AbortOptions, Logger, PeerId } from '@libp2p/interface'
|
|
31
|
+
import type { DNSResolver } from '@multiformats/dns/resolvers'
|
|
32
32
|
import type { UnixFSEntry } from 'ipfs-unixfs-exporter'
|
|
33
33
|
import type { CID } from 'multiformats/cid'
|
|
34
34
|
|
|
@@ -126,12 +126,7 @@ export class VerifiedFetch {
|
|
|
126
126
|
constructor ({ helia, ipns, unixfs }: VerifiedFetchComponents, init?: VerifiedFetchInit) {
|
|
127
127
|
this.helia = helia
|
|
128
128
|
this.log = helia.logger.forComponent('helia:verified-fetch')
|
|
129
|
-
this.ipns = ipns ?? heliaIpns(helia
|
|
130
|
-
resolvers: init?.dnsResolvers ?? [
|
|
131
|
-
dnsJsonOverHttps('https://mozilla.cloudflare-dns.com/dns-query'),
|
|
132
|
-
dnsJsonOverHttps('https://dns.google/resolve')
|
|
133
|
-
]
|
|
134
|
-
})
|
|
129
|
+
this.ipns = ipns ?? heliaIpns(helia)
|
|
135
130
|
this.unixfs = unixfs ?? heliaUnixFs(helia)
|
|
136
131
|
this.contentTypeParser = init?.contentTypeParser
|
|
137
132
|
this.log.trace('created VerifiedFetch instance')
|