is-ipfs
Advanced tools
Comparing version 0.6.3 to 1.0.0
@@ -0,1 +1,56 @@ | ||
<a name="1.0.0"></a> | ||
# [1.0.0](https://github.com/ipfs/is-ipfs/compare/v0.6.3...v1.0.0) (2020-04-05) | ||
### Features | ||
* support subdomains in isIPFS.url(url) ([#32](https://github.com/ipfs/is-ipfs/issues/32)) ([22d001d](https://github.com/ipfs/is-ipfs/commit/22d001d)), closes [/github.com/ipfs/is-ipfs/pull/32#discussion_r396161665](https://github.com//github.com/ipfs/is-ipfs/pull/32/issues/discussion_r396161665) | ||
### BREAKING CHANGES | ||
* `isIPFS.subdomain` now returns true for <domain.tld>.ipns.localhost | ||
* `isIPFS.subdomainPattern` changed | ||
* test: support peer multiaddr with /p2p/ | ||
Context: https://github.com/libp2p/libp2p/issues/79 | ||
* fix: explicitly ignore URL param and hash | ||
.url and .path now return true when validating: | ||
https://ipfs.io/ipfs/<CID>?filename=name.png#foo | ||
* refactor: simplify dnslinkSubdomain | ||
License: MIT | ||
Signed-off-by: Marcin Rataj <lidel@lidel.org> | ||
* fix: url() check should include subdomain() | ||
When .url was created we only had path gateways. When .subdomain was | ||
added, we did not update .url to test for subdomain gateways, which in | ||
the long run will confuse people and feels like a bug. | ||
Let's fix this: .url() will now check for both subdomain and path gateways | ||
* .url(url) now returns true if .subdomain(url) is true | ||
* refactor: merge DNSLink check into ipnsSubdomain() | ||
This makes subdomain checks follow what path gateway checks do, removing | ||
confusion. | ||
In both cases (IPNS and DNSLink) user needs to perform online record | ||
check, so this is just a handy way of detecting potential matches. | ||
* docs: update examples | ||
* refactor: switch to iso-url | ||
* refactor: lint-package-json | ||
* chore: update deps | ||
License: MIT | ||
Signed-off-by: Marcin Rataj <lidel@lidel.org> | ||
<a name="0.6.3"></a> | ||
@@ -2,0 +57,0 @@ ## [0.6.3](https://github.com/ipfs/is-ipfs/compare/v0.6.1...v0.6.3) (2020-01-07) |
{ | ||
"name": "is-ipfs", | ||
"version": "0.6.3", | ||
"description": "A set of utilities to help identify IPFS resources", | ||
"version": "1.0.0", | ||
"description": "A set of utilities to help identify IPFS resources on the web", | ||
"keywords": [ | ||
"js-ipfs", | ||
"ipns", | ||
"gateway", | ||
"dnslink", | ||
"ipfs" | ||
], | ||
"homepage": "https://github.com/ipfs/is-ipfs", | ||
"bugs": { | ||
"url": "https://github.com/ipfs/is-ipfs/issues" | ||
}, | ||
"license": "MIT", | ||
"author": "Francisco Dias <francisco@baiodias.com> (http://franciscodias.net/)", | ||
"leadMaintainer": "Marcin Rataj <lidel@lidel.org>", | ||
"files": [ | ||
"src", | ||
"dist" | ||
], | ||
"main": "src/index.js", | ||
@@ -10,2 +27,6 @@ "browser": { | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/ipfs/is-ipfs.git" | ||
}, | ||
"scripts": { | ||
@@ -15,3 +36,3 @@ "test:node": "aegir test --target node", | ||
"test": "aegir test", | ||
"lint": "aegir lint", | ||
"lint": "aegir lint && aegir lint-package-json", | ||
"release": "aegir release", | ||
@@ -24,41 +45,32 @@ "release-minor": "aegir release --type minor", | ||
}, | ||
"pre-commit": [ | ||
"test", | ||
"lint" | ||
], | ||
"keywords": [ | ||
"js-ipfs", | ||
"ipfs" | ||
], | ||
"author": "Francisco Dias <francisco@baiodias.com> (http://franciscodias.net/)", | ||
"license": "MIT", | ||
"dependencies": { | ||
"bs58": "^4.0.1", | ||
"cids": "~0.7.0", | ||
"mafmt": "^7.0.0", | ||
"multiaddr": "^7.2.1", | ||
"multibase": "~0.6.0", | ||
"multihashes": "~0.4.13" | ||
"cids": "~0.8.0", | ||
"iso-url": "~0.4.7", | ||
"mafmt": "^7.1.0", | ||
"multiaddr": "^7.4.3", | ||
"multibase": "~0.7.0", | ||
"multihashes": "~0.4.19" | ||
}, | ||
"devDependencies": { | ||
"aegir": "^20.5.0", | ||
"aegir": "^21.4.5", | ||
"chai": "^4.2.0", | ||
"pre-commit": "^1.2.2" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/ipfs/is-ipfs.git" | ||
"engines": { | ||
"node": ">=10.0.0", | ||
"npm": ">=6.0.0" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/ipfs/is-ipfs/issues" | ||
}, | ||
"homepage": "https://github.com/ipfs/is-ipfs", | ||
"pre-commit": [ | ||
"test", | ||
"lint" | ||
], | ||
"contributors": [ | ||
"Marcin Rataj <lidel@lidel.org>", | ||
"Francisco Baio Dias <xicombd@gmail.com>", | ||
"David Dias <daviddias.p@gmail.com>", | ||
"Alan Shaw <alan.shaw@protocol.ai>", | ||
"David Dias <daviddias.p@gmail.com>", | ||
"Francisco Baio Dias <xicombd@gmail.com>", | ||
"Henrique Dias <hacdias@gmail.com>", | ||
"Marcin Rataj <lidel@lidel.org>", | ||
"nginnever <ginneversource@gmail.com>" | ||
"nginnever <ginneversource@gmail.com>", | ||
"Henrique Dias <hacdias@gmail.com>" | ||
] | ||
} |
@@ -26,3 +26,3 @@ is-ipfs 🕵️ | ||
```js | ||
var isIPFS = require('is-ipfs') | ||
const isIPFS = require('is-ipfs') | ||
``` | ||
@@ -57,3 +57,6 @@ | ||
isIPFS.url('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true | ||
isIPFS.url('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?filename=guardian.jpg') // true | ||
isIPFS.url('https://ipfs.io/ipns/github.com') // true | ||
isIPFS.url('https://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true | ||
isIPFS.url('http://en.wikipedia-on-ipfs.org.ipfs.localhost:8080') // true | ||
isIPFS.url('https://github.com/ipfs/js-ipfs/blob/master/README.md') // false | ||
@@ -63,2 +66,3 @@ isIPFS.url('https://google.com') // false | ||
isIPFS.path('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true | ||
isIPFS.path('/ipfs/QmbcBPAwCDxRMB1Qe7CRQmxdrTSkxKwM9y6rZw2FjGtbsb/?weird-filename=test.jpg') // true | ||
isIPFS.path('/ipns/github.com') // true | ||
@@ -71,2 +75,3 @@ isIPFS.path('/ipfs/js-ipfs/blob/master/README.md') // false | ||
isIPFS.urlOrPath('/ipns/github.com') // true | ||
isIPFS.urlOrPath('https://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true | ||
isIPFS.urlOrPath('https://google.com') // false | ||
@@ -103,3 +108,4 @@ | ||
isIPFS.ipnsSubdomain('http://QmcNioXSC1bfJj1dcFErhUfyjFzoX2HodkRccsFFVJJvg8.ipns.dweb.link') // false | ||
isIPFS.ipnsSubdomain('http://foo-bar.ipns.dweb.link') // false (not a PeerID) | ||
isIPFS.ipnsSubdomain('http://en.wikipedia-on-ipfs.org.ipns.localhost:8080') // true (assuming DNSLink) | ||
isIPFS.ipnsSubdomain('http://hostname-without-tld.ipns.dweb.link') // false (missing TLD) | ||
@@ -112,5 +118,6 @@ isIPFS.multiaddr('/ip4/127.0.0.1/udp/1234') // true | ||
isIPFS.peerMultiaddr('/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4') // true | ||
isIPFS.peerMultiaddr('/ip4/127.0.0.1/tcp/1234/ws/ipfs/QmUjNmr8TgJCn1Ao7DvMy4cjoZU15b9bwSCBLE3vwXiwgj') // true | ||
isIPFS.peerMultiaddr('/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4/p2p-circuit/ipfs/QmUjNmr8TgJCn1Ao7DvMy4cjoZU15b9bwSCBLE3vwXiwgj') // true | ||
isIPFS.peerMultiaddr('/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4') // true | ||
isIPFS.peerMultiaddr('/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4') // true (legacy notation) | ||
isIPFS.peerMultiaddr('/ip4/127.0.0.1/tcp/1234/ws/p2p/QmUjNmr8TgJCn1Ao7DvMy4cjoZU15b9bwSCBLE3vwXiwgj') // true | ||
isIPFS.peerMultiaddr('/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4/p2p-circuit/p2p/QmUjNmr8TgJCn1Ao7DvMy4cjoZU15b9bwSCBLE3vwXiwgj') // true | ||
isIPFS.peerMultiaddr('/ip4/127.0.0.1/udp/1234') // false | ||
@@ -124,6 +131,5 @@ ``` | ||
Detection of IPFS Paths and identifiers in URLs is a two-stage process: | ||
1. `urlPattern`/`pathPattern`/`subdomainPattern` regex is applied to quickly identify potential candidates | ||
1. `pathPattern`/`pathGatewayPattern`/`subdomainGatewayPattern` regex is applied to quickly identify potential candidates | ||
2. proper CID validation is applied to remove false-positives | ||
## Content Identifiers | ||
@@ -188,12 +194,22 @@ | ||
Returns `true` if the provided string includes a valid IPFS or IPNS subdomain or `false` otherwise. | ||
Returns `true` if the provided `url` string includes a valid IPFS, looks like IPNS/DNSLink subdomain or `false` otherwise. | ||
### `isIPFS.ipfsSubdomain(url)` | ||
Returns `true` if the provided string includes a valid IPFS subdomain or `false` otherwise. | ||
Returns `true` if the provided `url` string includes a valid IPFS subdomain (case-insensitive CIDv1) or `false` otherwise. | ||
### `isIPFS.ipnsSubdomain(url)` | ||
Returns `true` if the provided string includes a valid IPNS subdomain or `false` otherwise. | ||
Returns `true` if the provided `url` string looks like a valid IPNS subdomain | ||
(CIDv1 with `libp2p-key` multicodec or something that looks like a FQDN, for example `en.wikipedia-on-ipfs.org.ipns.localhost:8080`) or `false` | ||
otherwise. | ||
**Note:** `ipnsSubdomain` method works in offline mode: it does not perform | ||
actual IPNS record lookup over DHT or other content routing method. It may | ||
return false-positives: | ||
- To ensure IPNS record exists, make a call to `/api/v0/name/resolve?arg=<ipnsid>` | ||
- To ensure DNSLink exists, make a call to `/api/v0/dns?arg=<fqdn>` | ||
## Multiaddrs | ||
@@ -200,0 +216,0 @@ |
@@ -9,12 +9,17 @@ 'use strict' | ||
const CID = require('cids') | ||
const { URL } = require('iso-url') | ||
const urlPattern = /^https?:\/\/[^/]+\/(ip(f|n)s)\/((\w+).*)/ | ||
const pathPattern = /^\/(ip(f|n)s)\/((\w+).*)/ | ||
const pathGatewayPattern = /^https?:\/\/[^/]+\/(ip[fn]s)\/([^/?#]+)/ | ||
const pathPattern = /^\/(ip[fn]s)\/([^/?#]+)/ | ||
const defaultProtocolMatch = 1 | ||
const defaultHashMath = 4 | ||
const defaultHashMath = 2 | ||
const fqdnPattern = /^https?:\/\/([^/]+)\.(ip(?:f|n)s)\.[^/]+/ | ||
const fqdnHashMatch = 1 | ||
const fqdnProtocolMatch = 2 | ||
// CID, libp2p-key or DNSLink | ||
const subdomainGatewayPattern = /^https?:\/\/([^/]+)\.(ip[fn]s)\.[^/?]+/ | ||
const subdomainIdMatch = 1 | ||
const subdomainProtocolMatch = 2 | ||
// Fully qualified domain name (FQDN) that has an explicit .tld suffix | ||
const fqdnWithTld = /^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)+([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$/ | ||
function isMultihash (hash) { | ||
@@ -80,3 +85,3 @@ const formatted = convertToString(hash) | ||
if (hash && pattern === fqdnPattern) { | ||
if (hash && pattern === subdomainGatewayPattern) { | ||
// when doing checks for subdomain context | ||
@@ -105,9 +110,20 @@ // ensure hash is case-insensitive | ||
if (hashMatch && pattern === fqdnPattern) { | ||
let hash = match[hashMatch] | ||
let ipnsId = match[hashMatch] | ||
if (ipnsId && pattern === subdomainGatewayPattern) { | ||
// when doing checks for subdomain context | ||
// ensure hash is case-insensitive | ||
// ensure ipnsId is case-insensitive | ||
// (browsers force-lowercase authority compotent anyway) | ||
hash = hash.toLowerCase() | ||
return isCID(hash) | ||
ipnsId = ipnsId.toLowerCase() | ||
// Check if it is cidv1 | ||
if (isCID(ipnsId)) return true | ||
// Check if it looks like FQDN | ||
try { | ||
// URL implementation in web browsers forces lowercase of the hostname | ||
const { hostname } = new URL(`http://${ipnsId}`) // eslint-disable-line no-new | ||
// Check if potential FQDN has an explicit TLD | ||
return fqdnWithTld.test(hostname) | ||
} catch (e) { | ||
return false | ||
} | ||
} | ||
@@ -134,5 +150,12 @@ | ||
const ipfsSubdomain = (url) => isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch) | ||
const ipnsSubdomain = (url) => isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch) | ||
const ipfsSubdomain = (url) => isIpfs(url, subdomainGatewayPattern, subdomainProtocolMatch, subdomainIdMatch) | ||
const ipnsSubdomain = (url) => isIpns(url, subdomainGatewayPattern, subdomainProtocolMatch, subdomainIdMatch) | ||
const subdomain = (url) => ipfsSubdomain(url) || ipnsSubdomain(url) | ||
const ipfsUrl = (url) => isIpfs(url, pathGatewayPattern) || ipfsSubdomain(url) | ||
const ipnsUrl = (url) => isIpns(url, pathGatewayPattern) || ipnsSubdomain(url) | ||
const url = (url) => ipfsUrl(url) || ipnsUrl(url) || subdomain(url) | ||
const path = (path) => isIpfs(path, pathPattern) || isIpns(path, pathPattern) | ||
module.exports = { | ||
@@ -144,16 +167,16 @@ multihash: isMultihash, | ||
base32cid: (cid) => (isMultibase(cid) === 'base32' && isCID(cid)), | ||
ipfsSubdomain: ipfsSubdomain, | ||
ipnsSubdomain: ipnsSubdomain, | ||
subdomain: (url) => (ipfsSubdomain(url) || ipnsSubdomain(url)), | ||
subdomainPattern: fqdnPattern, | ||
ipfsUrl: (url) => isIpfs(url, urlPattern), | ||
ipnsUrl: (url) => isIpns(url, urlPattern), | ||
url: (url) => (isIpfs(url, urlPattern) || isIpns(url, urlPattern)), | ||
urlPattern: urlPattern, | ||
ipfsSubdomain, | ||
ipnsSubdomain, | ||
subdomain, | ||
subdomainGatewayPattern, | ||
ipfsUrl, | ||
ipnsUrl, | ||
url, | ||
pathGatewayPattern: pathGatewayPattern, | ||
ipfsPath: (path) => isIpfs(path, pathPattern), | ||
ipnsPath: (path) => isIpns(path, pathPattern), | ||
path: (path) => (isIpfs(path, pathPattern) || isIpns(path, pathPattern)), | ||
pathPattern: pathPattern, | ||
urlOrPath: (x) => (isIpfs(x, urlPattern) || isIpns(x, urlPattern) || isIpfs(x, pathPattern) || isIpns(x, pathPattern)), | ||
path, | ||
pathPattern, | ||
urlOrPath: (x) => url(x) || path(x), | ||
cidPath: path => isString(path) && !isCID(path) && isIpfs(`/ipfs/${path}`, pathPattern) | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
SPDX disjunction
LicenseSPDX disjunction for an artifact's license information
Found 1 instance in 1 package
SPDX disjunction
LicenseSPDX disjunction for an artifact's license information
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found
Found 1 instance in 1 package
1
100
0
224
763920
7
10
6112
+ Addediso-url@~0.4.7
+ Addediso-url@0.4.7(transitive)
- Removedcids@0.7.5(transitive)
- Removedmultibase@0.6.1(transitive)
Updatedcids@~0.8.0
Updatedmafmt@^7.1.0
Updatedmultiaddr@^7.4.3
Updatedmultibase@~0.7.0
Updatedmultihashes@~0.4.19