Skip to content

Commit 5020d3b

Browse files
lidelElPaisano
authored andcommitted
feat: /how-to/detect-ipfs-on-web
This adds a page with some best practices around detecting IPFS resources on the web, based on recent discussions with Brave team and our effort to streamline implmenetation there.
1 parent c068277 commit 5020d3b

File tree

2 files changed

+149
-2
lines changed

2 files changed

+149
-2
lines changed

Diff for: docs/.vuepress/config.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ module.exports = {
248248
collapsable: true,
249249
children: [
250250
'/how-to/address-ipfs-on-web',
251-
'/how-to/browser-tools-frameworks'
251+
'/how-to/browser-tools-frameworks',
252+
'how-to/detect-ipfs-on-web',
252253
]
253254
},
254255
{
@@ -512,7 +513,25 @@ module.exports = {
512513
],
513514
'vuepress-plugin-chunkload-redirect',
514515
'vuepress-plugin-ipfs',
515-
'vuepress-plugin-mermaidjs',
516+
[
517+
'vuepress-plugin-mermaidjs',
518+
{
519+
securityLevel: 'loose', // safe as we dont allow mermaid in user content. allows for additional interactivity
520+
theme: 'base',
521+
themeVariables: { // values from 'IPFS brand sheet' at https://github.com/ipfs/ipfs-gui#resources
522+
primaryColor: '#D7EDF1',
523+
edgeLabelBackground:'#edf0f4',
524+
tertiaryColor: '#edf0f4'
525+
},
526+
deterministicIds: true,
527+
deterministicIDSeed: DEPLOY_DOMAIN,
528+
flowchart: {
529+
htmlLabels: true,
530+
curve: 'basis',
531+
useMaxWidth: false
532+
}
533+
}
534+
],
516535
'tabs'
517536
],
518537
extraWatchFiles: ['.vuepress/nav/en.js']

Diff for: docs/how-to/detect-ipfs-on-web.md

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
title: Discover IPFS content from Web2
3+
description: Learn how to add support for content-addressed IPFS resources in web browsers and other user agents.
4+
---
5+
6+
# Discover IPFS content from Web2
7+
8+
The goal of this page is to provide some suggestions and best practices for Web 2 web browsers and other [user agents](https://en.wikipedia.org/wiki/User_agent) that are interested in adding support for [content-addressed resources](/how-to/address-ipfs-on-web).
9+
10+
## Detecting content-addressed resources
11+
12+
In many cases, IPFS resources can be detected just by looking at the URI, especially if it is an HTTP URL pointed at a public gateway. This allows a browser to upgrade the transport protocol to IPFS, and removes the need to send an HTTP request to a remote server.
13+
14+
### Methodology
15+
16+
To determine if a resource is an IPFS resource, answer the following questions in order:
17+
18+
1. Does the `URL` follow [path or subdomain gateway](/how-to/address-ipfs-on-web/) convention?
19+
1. If not, does [DNSLink](/concepts/dnslink/) with an IPFS path exist for `URL.hostname`?
20+
21+
If you answered yes to either of the above questions, a user agent should be able to find a content path that can be used for data retrieval over IPFS, as described in the illustration below:
22+
23+
```mermaid
24+
flowchart TD
25+
Start[Top-level navigation event]
26+
IsGateway{Is it a Gateway URL?<br/><code>foo.tld/ipxs/id/..</code><br/><code>id.ipxs.foo.com/..</code>}
27+
28+
Start -->|new URL in address bar| IsGateway
29+
IsGateway ==>|YES| IsPathOrSubdomain
30+
IsPathOrSubdomain -->|Path Gateway| ExtractFromPath
31+
IsPathOrSubdomain -->|Subdomain Gateway| ExtractFromSubdomain
32+
33+
subgraph GwURLToPath [Convert Gateway URL to a Content Path]
34+
IsPathOrSubdomain{Is the Gateway URL 'path' <br/> or 'subdomain' based?}
35+
ExtractFromPath[Extract <br/> <code>URL.pathname</code>]
36+
ExtractFromSubdomain[Read namespace <br/> and <br/>identifier from <br/> <code>URL.hostname</code> and <br/> prepend to <code>URL.pathname</code>. <br/> E.g., turn <br/><code>id.ipxs.foo.com/pathname</code> <br/> into <code>/ipxs/id/pathname</code>]
37+
end
38+
39+
PotentialContentPath[Found a Potential Content Path]
40+
41+
ExtractFromPath --> PotentialContentPath
42+
ExtractFromSubdomain --> PotentialContentPath
43+
PotentialContentPath -->|/ipxs/id/sub/path..| IsIpfsOrIpns
44+
45+
subgraph PathValidation [Is the Content Path valid?]
46+
IsIpfsOrIpns{Is it <code>/ipfs/</code> <br/>or <code>/ipns/</code><br/>?}
47+
ValidateRootCID{Is <code>id</code> <br/>a valid CID?}
48+
ValidateIPNSKey{Is <code>id</code> <br/>a valid CID <br/> with <code>libp2p-key</code> <br/>codec?}
49+
ValidateDNSLink{Is <code>id</code> <br/> a DNSLink name <br/> with TXT record: <br/> <code>dnslink=/ipfs/</code><br/> or <code>=/ipns/</code>}
50+
51+
IsIpfsOrIpns --->|/ipfs/id/..| ValidateRootCID
52+
IsIpfsOrIpns -->|/ipns/id/..| ValidateIPNSKey
53+
ValidateIPNSKey -->|NO| ValidateDNSLink
54+
end
55+
56+
subgraph FoundValidIPFSContent [Confirmed we've found a Valid IPFS Resource]
57+
style FoundValidIPFSContent margin-top: 50
58+
ValidIPFSCID[Valid /ipfs/cid/.. <br/>Content Path]
59+
ValidIPNSKey[Valid /ipns/key/.. <br/>Content Path]
60+
ValidDNSLink[Valid /ipns/dnslink/.. <br/>Content Path]
61+
62+
ValidateRootCID ===>|YES, /ipfs/cid/..| ValidIPFSCID
63+
ValidateIPNSKey ===>|YES, /ipns/key/..| ValidIPNSKey
64+
ValidateDNSLink ===>|YES, /ipfs/dnslink/..| ValidDNSLink
65+
end
66+
67+
subgraph NonGwURLToPath [See if non-Gateway URL has a Content Path]
68+
IsCachedDNSLink{Does <br/> <code>URL.hostname</code> <br/> match a cached <br/> DNSLink name?}
69+
IsHeaderPresent{Is <code>X-Ipfs-Path</code> <br/> header present?}
70+
IsError{Did request fail? <br/> HTTP error>500 <br/> or network error}
71+
IsDNSLinkAtHostname{Does DNSLink exists <br/> for <code>URL.hostname</code>?<br/>}
72+
PathFromHeader[Read value from <code>X-Ipfs-Path</code>]
73+
end
74+
75+
IsGateway -->|NO| IsCachedDNSLink
76+
IsCachedDNSLink ==>|YES| ValidDNSLink
77+
IsCachedDNSLink -->|NO| IsHeaderPresent
78+
IsHeaderPresent ==>|YES| IsDNSLinkAtHostname
79+
IsHeaderPresent -->|NO| IsError
80+
IsError ==>|YES| IsDNSLinkAtHostname
81+
IsDNSLinkAtHostname ==>|YES| ValidDNSLink
82+
IsDNSLinkAtHostname -->|NO| PathFromHeader
83+
PathFromHeader --> PotentialContentPath
84+
```
85+
86+
## What to do with detected paths
87+
88+
What you do with the detected IPFS resource path depends on the type of path.
89+
90+
### Immutable `/ipfs/cid/..`
91+
92+
- Display "Open via IPFS" button in UI
93+
- Clicking it should open `ipfs://cid/path?query#hash` (preserving any `?query` or `#hash` from the original HTTP URL)
94+
- If "IPFS Gateway Redirect / Protocol Upgrade" feature is enabled, and the HTTP URL was a gateway one, redirect automatically to `ipfs://cid/path?query#hash`
95+
96+
### Mutable `/ipns/key/..`
97+
- Display "Open via IPFS" button in UI
98+
- Clicking it should open `ipns://key/path?query#hash` (preserving any `?query` or `#hash` from the original HTTP URL)
99+
- If "IPFS Gateway Redirect / Protocol Upgrade" is enabled, and the original HTTP URL was a gateway one, redirect automatically to `ipns://dnslink/path?query#hash`
100+
101+
### Mutable `/ipns/dnslink/..`
102+
103+
- Display "Open via IPFS" button in UI
104+
- Clicking it should open `ipns://dnslink/path?query#hash` (preserving `?query` or `#hash` from the original HTTP URL)
105+
- If "DNSLink Website Redirect / Protocol Upgrade" is enabled, redirect automatically to `ipns://dnslink/path?query#hash`
106+
- It is a good practice to internally cache the fact that domain has a valid DNSLink.
107+
- TTL from TXT record can be used as a hint when to expire cache entry.
108+
- Performance can be improved further by using cached flag and revalidating it asynchronously, without blocking browser navigation.
109+
110+
## FAQ
111+
112+
**What if a browser does not support `ipfs://` and `ipns://` natively?** Implementations can use an [HTTP Gateway](/reference/http/gateway/) as a fallback, convert ththe path to `//gatewayhost/ipxs/id/..`-type paths, or leverage the built-in URI router at `//gatewayhost/ipfs/?uri=%s`
113+
114+
**Why should `?query` or `#hash` from the original HTTP URL be preserved?** The link could point at specific `#section` of a longer article. It is also common for JavaScript running on a page to use the `?query` and `#hash` for navigation and ad-hoc storage of some state.
115+
116+
**Should a user agent redirect when the URL does not match gateway convention, `URL.hostname` does not have a valid DNSLink, but `X-Ipfs-Path` is present in HTTP response AND points at an immutable `/ipfs/cid`?** This is an edge case, and we've seen that it is often a misconfiguration caused by an invalid or missing DNSLink that could lead to bad UX when automatic redirect is involved. The user ends up on an immutable copy of a website, bookmarks it or keeps tabs open, and misses updates when DNSLink setup is fixed. It is suggested to not redirect this edge case, or provide a setting that controls this type of redirect. Usually, showing "Open via IPFS" in the user interface is enough for this case.
117+
118+
## Implementation examples
119+
120+
### Brave
121+
122+
[Brave has supported IPFS since 2021](https://brave.com/brave-integrates-ipfs/). Current features include `ipfs://` and `ipns://` URI support, ability to resolve this type of address using a public / local gateway, opt-in Gateway and/or DNSLink redirects, and an **Open via IPFS** button in the address bar:
123+
124+
> ![Open via IPFS in Brave address bar](https://user-images.githubusercontent.com/157609/110859368-9a0d7300-82bb-11eb-934d-4e38718dbacb.png)
125+
126+
### IPFS Companion
127+
128+
Firefox and Chromium-based browsers such as Google Chrome or Microsoft Edge can be augumented with [IPFS Companion](/install/ipfs-companion/) browser extension, which allows them to detect IPFS content.

0 commit comments

Comments
 (0)