diff --git a/.gitignore b/.gitignore
index 578a0d0..858990e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ lib-cov
# Coverage directory used by tools like istanbul
coverage
+.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
diff --git a/.travis.yml b/.travis.yml
index 2af65f7..a46ba0e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,6 @@
language: node_js
node_js:
- - 4
- - 5
- node
# Make sure we have new NPM.
diff --git a/README.md b/README.md
index c06fce5..379254c 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,16 @@
is-ipfs
====
-[](http://travis-ci.org/ipfs/is-ipfs)
-[](https://github.com/dignifiedquire/dignified.js)
+[](https://github.com/ipfs/is-ipfs/releases/latest)
+[](https://webchat.freenode.net/?channels=%23ipfs)
-A set of utilities to help identify [IPFS](https://ipfs.io/) resources.
+> A set of utilities to help identify [IPFS](https://ipfs.io/) resources
+## Lead Maintainer
-## Install
+[Marcin Rataj](https://github.com/lidel)
+
+# Install
### In Node.js through npm
@@ -34,7 +37,7 @@ Loading this module through a script tag will make the ```IsIpfs``` obj availabl
```
-## Usage
+# Usage
```javascript
const isIPFS = require('is-ipfs')
@@ -45,6 +48,9 @@ isIPFS.cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true (CIDv0)
isIPFS.cid('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') // true (CIDv1)
isIPFS.cid('noop') // false
+isIPFS.base32cid('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') // true
+isIPFS.base32cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false
+
isIPFS.url('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true
isIPFS.url('https://ipfs.io/ipns/github.com') // true
isIPFS.url('https://github.com/ipfs/js-ipfs/blob/master/README.md') // false
@@ -71,9 +77,31 @@ isIPFS.ipfsPath('/ipfs/invalid-hash') // false
isIPFS.ipnsPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false
isIPFS.ipnsPath('/ipns/github.com') // true
+
+isIPFS.subdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true
+isIPFS.subdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.ipns.dweb.link') // true
+isIPFS.subdomain('http://www.bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // false
+isIPFS.subdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.dweb.link') // false
+
+isIPFS.ipfsSubdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true
+isIPFS.ipfsSubdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.dweb.link') // false
+
+isIPFS.ipnsSubdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.ipns.dweb.link') // true
+isIPFS.ipnsSubdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.dweb.link') // false
+isIPFS.ipnsSubdomain('http://QmcNioXSC1bfJj1dcFErhUfyjFzoX2HodkRccsFFVJJvg8.ipns.dweb.link') // false
+isIPFS.ipnsSubdomain('http://foo-bar.ipns.dweb.link') // false (not a PeerID)
```
-## API
+# API
+
+A suite of util methods that provides efficient validation.
+
+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
+2. proper CID validation is applied to remove false-positives
+
+
+## Utils
### `isIPFS.multihash(hash)`
@@ -83,17 +111,15 @@ Returns `true` if the provided string is a valid `multihash` or `false` otherwis
Returns `true` if the provided string is a valid `CID` or `false` otherwise.
-### `isIPFS.url(url)`
+### `isIPFS.base32cid(hash)`
-Returns `true` if the provided string is a valid IPFS or IPNS url or `false` otherwise.
+Returns `true` if the provided string is a valid `CID` in Base32 encoding or `false` otherwise.
-### `isIPFS.path(path)`
-
-Returns `true` if the provided string is a valid IPFS or IPNS path or `false` otherwise.
+## URLs
-### `isIPFS.urlOrPath(path)`
+### `isIPFS.url(url)`
-Returns `true` if the provided string is a valid IPFS or IPNS url or path or `false` otherwise.
+Returns `true` if the provided string is a valid IPFS or IPNS url or `false` otherwise.
### `isIPFS.ipfsUrl(url)`
@@ -103,6 +129,19 @@ Returns `true` if the provided string is a valid IPFS url or `false` otherwise.
Returns `true` if the provided string is a valid IPNS url or `false` otherwise.
+## Paths
+
+Standalone validation of IPFS Paths: `/ip(f|n)s//..`
+
+### `isIPFS.path(path)`
+
+Returns `true` if the provided string is a valid IPFS or IPNS path or `false` otherwise.
+
+### `isIPFS.urlOrPath(path)`
+
+Returns `true` if the provided string is a valid IPFS or IPNS url or path or `false` otherwise.
+
+
### `isIPFS.ipfsPath(path)`
Returns `true` if the provided string is a valid IPFS path or `false` otherwise.
@@ -111,10 +150,23 @@ Returns `true` if the provided string is a valid IPFS path or `false` otherwise.
Returns `true` if the provided string is a valid IPNS path or `false` otherwise.
+## Subdomains
+
+Validated subdomain convention: `cidv1b32.ip(f|n)s.domain.tld`
+
+### `isIPFS.subdomain(url)`
+
+Returns `true` if the provided string includes a valid IPFS or IPNS subdomain or `false` otherwise.
+
+### `isIPFS.ipfsSubdomain(url)`
+
+Returns `true` if the provided string includes a valid IPFS subdomain or `false` otherwise.
+
+### `isIPFS.ipnsSubdomain(url)`
-**Note:** the regex used for these checks is also exported as `isIPFS.urlPattern`
+Returns `true` if the provided string includes a valid IPNS subdomain or `false` otherwise.
-## License
+# License
MIT
diff --git a/ci/Jenkinsfile b/ci/Jenkinsfile
new file mode 100644
index 0000000..c1e3f2c
--- /dev/null
+++ b/ci/Jenkinsfile
@@ -0,0 +1 @@
+javascript()
diff --git a/package.json b/package.json
index 2dbcceb..5c3cc26 100644
--- a/package.json
+++ b/package.json
@@ -1,54 +1,56 @@
{
"name": "is-ipfs",
- "version": "0.3.2",
+ "version": "0.4.0",
"description": "A set of utilities to help identify IPFS resources",
"main": "src/index.js",
"browser": {
"fs": false
},
"scripts": {
- "test:node": "aegir-test node",
- "test:browser": "aegir-test browser",
- "test": "aegir-test",
- "lint": "aegir-lint",
- "release": "aegir-release",
- "release-minor": "aegir-release --type minor",
- "release-major": "aegir-release --type major",
- "build": "aegir-build",
- "coverage": "aegir-coverage",
- "coverage-publish": "aegir-coverage publish"
+ "test:node": "aegir test --target node",
+ "test:browser": "aegir test --target browser",
+ "test": "aegir test",
+ "lint": "aegir lint",
+ "release": "aegir release",
+ "release-minor": "aegir release --type minor",
+ "release-major": "aegir release --type major",
+ "build": "aegir build",
+ "coverage": "aegir coverage",
+ "coverage-publish": "aegir coverage --upload"
},
"pre-commit": [
"test",
"lint"
],
"keywords": [
+ "js-ipfs",
"ipfs"
],
"author": "Francisco Dias (http://franciscodias.net/)",
"license": "MIT",
"dependencies": {
- "cids": "~0.5.1",
- "bs58": "^4.0.1",
- "multihashes": "~0.4.9"
+ "bs58": "4.0.1",
+ "cids": "0.5.3",
+ "multibase": "0.4.0",
+ "multihashes": "0.4.13"
},
"devDependencies": {
- "aegir": "^11.0.2",
- "chai": "^4.1.2",
- "pre-commit": "^1.2.2"
+ "aegir": "15.0.1",
+ "chai": "4.1.2",
+ "pre-commit": "1.2.2"
},
"repository": {
"type": "git",
- "url": "https://github.com/xicombd/is-ipfs.git"
+ "url": "https://github.com/ipfs/is-ipfs.git"
},
"bugs": {
- "url": "https://github.com/xicombd/is-ipfs/issues"
+ "url": "https://github.com/ipfs/is-ipfs/issues"
},
- "homepage": "https://github.com/xicombd/is-ipfs",
+ "homepage": "https://github.com/ipfs/is-ipfs",
"contributors": [
"David Dias ",
"Francisco Baio Dias ",
"Marcin Rataj ",
"nginnever "
]
-}
\ No newline at end of file
+}
diff --git a/src/index.js b/src/index.js
index 516b2db..acfef52 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,15 +2,22 @@
const base58 = require('bs58')
const multihash = require('multihashes')
+const multibase = require('multibase')
const CID = require('cids')
const urlPattern = /^https?:\/\/[^/]+\/(ip(f|n)s)\/((\w+).*)/
const pathPattern = /^\/(ip(f|n)s)\/((\w+).*)/
+const defaultProtocolMatch = 1
+const defaultHashMath = 4
+
+const fqdnPattern = /^https?:\/\/([^/]+)\.(ip(?:f|n)s)\.[^/]+/
+const fqdnHashMatch = 1
+const fqdnProtocolMatch = 2
function isMultihash (hash) {
const formatted = convertToString(hash)
try {
- const buffer = new Buffer(base58.decode(formatted))
+ const buffer = Buffer.from(base58.decode(formatted))
multihash.decode(buffer)
return true
} catch (e) {
@@ -18,6 +25,14 @@ function isMultihash (hash) {
}
}
+function isMultibase (hash) {
+ try {
+ return multibase.isEncoded(hash)
+ } catch (e) {
+ return false
+ }
+}
+
function isCID (hash) {
try {
return CID.isCID(new CID(hash))
@@ -26,7 +41,7 @@ function isCID (hash) {
}
}
-function isIpfs (input, pattern) {
+function isIpfs (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch = defaultHashMath) {
const formatted = convertToString(input)
if (!formatted) {
return false
@@ -37,15 +52,23 @@ function isIpfs (input, pattern) {
return false
}
- if (match[1] !== 'ipfs') {
+ if (match[protocolMatch] !== 'ipfs') {
return false
}
- const hash = match[4]
+ let hash = match[hashMatch]
+
+ if (hash && pattern === fqdnPattern) {
+ // when doing checks for subdomain context
+ // ensure hash is case-insensitive
+ // (browsers force-lowercase authority compotent anyway)
+ hash = hash.toLowerCase()
+ }
+
return isCID(hash)
}
-function isIpns (input, pattern) {
+function isIpns (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch) {
const formatted = convertToString(input)
if (!formatted) {
return false
@@ -55,10 +78,19 @@ function isIpns (input, pattern) {
return false
}
- if (match[1] !== 'ipns') {
+ if (match[protocolMatch] !== 'ipns') {
return false
}
+ if (hashMatch && pattern === fqdnPattern) {
+ let hash = match[hashMatch]
+ // when doing checks for subdomain context
+ // ensure hash is case-insensitive
+ // (browsers force-lowercase authority compotent anyway)
+ hash = hash.toLowerCase()
+ return isCID(hash)
+ }
+
return true
}
@@ -74,9 +106,17 @@ function convertToString (input) {
return false
}
+const ipfsSubdomain = (url) => isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch)
+const ipnsSubdomain = (url) => isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch)
+
module.exports = {
multihash: isMultihash,
cid: isCID,
+ 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)),
diff --git a/test/test-cid.spec.js b/test/test-cid.spec.js
index 94f66e6..8243a48 100644
--- a/test/test-cid.spec.js
+++ b/test/test-cid.spec.js
@@ -13,13 +13,13 @@ describe('ipfs cid', () => {
})
it('isIPFS.cid should match a valid CIDv0 (multihash) buffer', (done) => {
- const actual = isIPFS.cid(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.cid(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(true)
done()
})
it('isIPFS.cid should not match a broken CIDv0 buffer', (done) => {
- const actual = isIPFS.cid(new Buffer('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE70'))
+ const actual = isIPFS.cid(Buffer.from('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE70'))
expect(actual).to.equal(false)
done()
})
@@ -36,6 +36,12 @@ describe('ipfs cid', () => {
done()
})
+ it('isIPFS.cid should match a valid CIDv1 in Base32', (done) => {
+ const actual = isIPFS.cid('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va')
+ expect(actual).to.equal(true)
+ done()
+ })
+
it('isIPFS.cid should not match an invalid CIDv1 (with a typo)', (done) => {
const actual = isIPFS.cid('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ')
expect(actual).to.equal(false)
@@ -54,3 +60,41 @@ describe('ipfs cid', () => {
done()
})
})
+
+describe('ipfs base32cid', () => {
+ it('isIPFS.base32cid should not match a valid CIDv0 (multihash in base58btc)', (done) => {
+ const actual = isIPFS.base32cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.base32cid should not match a valid CIDv1 in base58btc', (done) => {
+ const actual = isIPFS.cid('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.base32cid should match a valid URL-safe CIDv1 in Base32', (done) => {
+ const actual = isIPFS.base32cid('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.base32cid should not match an invalid CID (with a typo)', (done) => {
+ const actual = isIPFS.base32cid('afybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.base32cid should not match an invalid CID', (done) => {
+ const actual = isIPFS.base32cid('noop')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.base32cid should not match an invalid CID data type', (done) => {
+ const actual = isIPFS.base32cid(4)
+ expect(actual).to.equal(false)
+ done()
+ })
+})
diff --git a/test/test-multihash.spec.js b/test/test-multihash.spec.js
index 4c23166..d82a823 100644
--- a/test/test-multihash.spec.js
+++ b/test/test-multihash.spec.js
@@ -13,13 +13,13 @@ describe('ipfs multihash', () => {
})
it('isIPFS.multihash should match a valid multihash buffer', (done) => {
- const actual = isIPFS.multihash(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.multihash(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(true)
done()
})
it('isIPFS.multihash should not match a buffer', (done) => {
- const actual = isIPFS.multihash(new Buffer('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE70'))
+ const actual = isIPFS.multihash(Buffer.from('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE70'))
expect(actual).to.equal(false)
done()
})
diff --git a/test/test-path.spec.js b/test/test-path.spec.js
index 87a2b18..e28057a 100644
--- a/test/test-path.spec.js
+++ b/test/test-path.spec.js
@@ -37,7 +37,7 @@ describe('ipfs path', () => {
})
it('isIPFS.ipfsPath should not match a buffer data type', (done) => {
- const actual = isIPFS.ipfsPath(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.ipfsPath(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
@@ -67,7 +67,7 @@ describe('ipfs path', () => {
})
it('isIPFS.ipnsPath should not match a buffer data type', (done) => {
- const actual = isIPFS.ipnsPath(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.ipnsPath(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
@@ -97,7 +97,7 @@ describe('ipfs path', () => {
})
it('isIPFS.path should not match a buffer data type', (done) => {
- const actual = isIPFS.path(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.path(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
@@ -127,7 +127,7 @@ describe('ipfs path', () => {
})
it('isIPFS.urlOrPath should not match a buffer data type', (done) => {
- const actual = isIPFS.ipfsPath(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.ipfsPath(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
diff --git a/test/test-subdomain.spec.js b/test/test-subdomain.spec.js
new file mode 100644
index 0000000..23e0ffe
--- /dev/null
+++ b/test/test-subdomain.spec.js
@@ -0,0 +1,145 @@
+/* eslint-env mocha */
+'use strict'
+
+const base58 = require('bs58')
+const isIPFS = require('../src/index')
+const expect = require('chai').expect
+
+describe('ipfs subdomain', () => {
+ it('isIPFS.ipfsSubdomain should match a cidv1b32', (done) => {
+ const actual = isIPFS.ipfsSubdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.ipfsSubdomain should match a cidv1b32 with complex ipfs path', (done) => {
+ const actual = isIPFS.ipfsSubdomain('http://bafybeidvtwx54qr44kidymvhfzefzxhgkieigwth6oswk75zhlzjdmunoy.ipfs.dweb.link/linkify-demo.html')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.ipfsSubdomain should not match non-cid subdomains', (done) => {
+ const actual = isIPFS.ipfsSubdomain('http://not-a-cid.ipfs.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipfsSubdomain should not match case-sensitive CID subdomains', (done) => {
+ // Origin forces browsers to lowercase the authority component
+ // so QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR
+ // becomes invalid CID: qmbwqxbekc3p8tqskc98xmwnzrzdtrlmimpl8wbutgsmnr
+ const actual = isIPFS.ipfsSubdomain('http://QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR.ipfs.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipfsSubdomain should not match if not under .ipfs. zone', (done) => {
+ // we require explicit convention of putting cidv1b32 under .ipfs. zone
+ // to make it clear content can be safely uplifted and loaded over IPFS
+ const actual = isIPFS.ipfsSubdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipfsSubdomain should not match a buffer data type', (done) => {
+ const actual = isIPFS.ipfsSubdomain(Buffer.from(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR')))
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should not match .ipfs. zone', (done) => {
+ const actual = isIPFS.ipnsSubdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should match a .ipns. zone with cidv1b32', (done) => {
+ const actual = isIPFS.ipnsSubdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.ipns.dweb.link')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should not match case-sensitive CID subdomains', (done) => {
+ // Origin forces browsers to lowercase the authority component
+ // so QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR
+ // becomes invalid CID: qmbwqxbekc3p8tqskc98xmwnzrzdtrlmimpl8wbutgsmnr
+ const actual = isIPFS.ipnsSubdomain('http://QmcNioXSC1bfJj1dcFErhUfyjFzoX2HodkRccsFFVJJvg8.ipns.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should not match .ipns. zone with non-cid subdomain', (done) => {
+ // we do not support opaque strings in subdomains, only peerids
+ const actual = isIPFS.ipnsSubdomain('http://a-dnslink-website.com.ipns.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should not match without .ipns. zone', (done) => {
+ const actual = isIPFS.ipnsSubdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.ipnsSubdomain should not match a buffer data type', (done) => {
+ const actual = isIPFS.ipnsSubdomain(Buffer.from(base58.decode('QmNQuBJ8tg4QN6mSLXHekxBbcToPwKxamWNrDdEugxMTDd')))
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.subdomain should match an ipfs subdomain', (done) => {
+ const actual = isIPFS.subdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.subdomain should match an ipns subdomain with PeerID as cidv1b32', (done) => {
+ const actual = isIPFS.subdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.ipns.dweb.link')
+ expect(actual).to.equal(true)
+ done()
+ })
+
+ it('isIPFS.subdomain should not match if fqdn does not start with cidv1b32', (done) => {
+ const actual = isIPFS.subdomain('http://www.bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.subdomain should not match if no ipfs/ipns zone', (done) => {
+ const actual = isIPFS.subdomain('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.subdomain should not match if ipns peerid is invalid', (done) => {
+ const actual = isIPFS.subdomain('http://not-a-cid.ipns.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.subdomain should not match a buffer data type', (done) => {
+ const actual = isIPFS.subdomain(Buffer.from(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR')))
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ /* We keep subdomain logic separate from legacy urlOrPath checks, below is a fail-safe to ensure we keep that behavior */
+
+ it('isIPFS.urlOrPath should not match ipfs url with cidv1b32 subdomain', (done) => {
+ const actual = isIPFS.urlOrPath('http://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.urlOrPath should not match ipns url', (done) => {
+ const actual = isIPFS.urlOrPath('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j52f6xwc6q.ipns.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+
+ it('isIPFS.urlOrPath should not match ipns in subdomain', (done) => {
+ const actual = isIPFS.urlOrPath('http://a-dnslink-website.com.ipns.dweb.link')
+ expect(actual).to.equal(false)
+ done()
+ })
+})
diff --git a/test/test-url.spec.js b/test/test-url.spec.js
index a0e61eb..dcfaf1c 100644
--- a/test/test-url.spec.js
+++ b/test/test-url.spec.js
@@ -37,7 +37,7 @@ describe('ipfs url', () => {
})
it('isIPFS.ipfsUrl should not match a buffer input', (done) => {
- const actual = isIPFS.ipfsUrl(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.ipfsUrl(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
@@ -67,7 +67,7 @@ describe('ipfs url', () => {
})
it('isIPFS.ipnsUrl should not match a buffer input', (done) => {
- const actual = isIPFS.ipnsUrl(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.ipnsUrl(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})
@@ -97,7 +97,7 @@ describe('ipfs url', () => {
})
it('isIPFS.url should not match a buffer input', (done) => {
- const actual = isIPFS.url(new Buffer(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
+ const actual = isIPFS.url(Buffer.from(base58.decode('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o')))
expect(actual).to.equal(false)
done()
})