From 6cc856edd6cd5bb645980e91edae5ad1cb5a3986 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 30 Jun 2018 23:24:35 +0200 Subject: [PATCH 1/7] chore: add Jenkins and maintainer --- README.md | 9 ++++++--- ci/Jenkinsfile | 1 + package.json | 11 ++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 ci/Jenkinsfile diff --git a/README.md b/README.md index c06fce5..4144d97 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ is-ipfs ==== -[![build status](https://secure.travis-ci.org/ipfs/is-ipfs.svg)](http://travis-ci.org/ipfs/is-ipfs) -[![dignified.js](https://img.shields.io/badge/follows-dignified.js-blue.svg?style=flat-square)](https://github.com/dignifiedquire/dignified.js) +[![](https://img.shields.io/github/release/ipfs/ipfs-companion.svg)](https://github.com/ipfs/ipfs-companion/releases/latest) +[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](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 + +[Marcin Rataj](https://github.com/lidel) ## Install 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..54bf002 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "is-ipfs", - "version": "0.3.2", + "version": "0.3.3", "description": "A set of utilities to help identify IPFS resources", "main": "src/index.js", "browser": { @@ -23,6 +23,7 @@ "lint" ], "keywords": [ + "js-ipfs", "ipfs" ], "author": "Francisco Dias (http://franciscodias.net/)", @@ -39,16 +40,16 @@ }, "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 +} From ae0f73809dc55989b5465626c30bdd9ad147e4ef Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sun, 1 Jul 2018 18:50:45 +0200 Subject: [PATCH 2/7] fix: release badge in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4144d97..0b2b710 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ is-ipfs ==== -[![](https://img.shields.io/github/release/ipfs/ipfs-companion.svg)](https://github.com/ipfs/ipfs-companion/releases/latest) +[![](https://img.shields.io/github/release/ipfs/is-ipfs.svg)](https://github.com/ipfs/is-ipfs/releases/latest) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs) > A set of utilities to help identify [IPFS](https://ipfs.io/) resources From a793da796d2905d36d6c1041b894c471db36695f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sun, 22 Jul 2018 23:38:47 +0200 Subject: [PATCH 3/7] feat: support cidv1b32 in subdomains Closes https://github.com/ipfs/is-ipfs/issues/19 --- .gitignore | 1 + README.md | 81 +++++++++++++++++--- package.json | 35 ++++----- src/index.js | 48 ++++++++++-- test/test-cid.spec.js | 9 +++ test/test-multibase.spec.js | 73 ++++++++++++++++++ test/test-subdomain.spec.js | 146 ++++++++++++++++++++++++++++++++++++ 7 files changed, 359 insertions(+), 34 deletions(-) create mode 100644 test/test-multibase.spec.js create mode 100644 test/test-subdomain.spec.js 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/README.md b/README.md index 0b2b710..372be34 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ is-ipfs [Marcin Rataj](https://github.com/lidel) -## Install +# Install ### In Node.js through npm @@ -37,17 +37,25 @@ Loading this module through a script tag will make the ```IsIpfs``` obj availabl ``` -## Usage +# Usage ```javascript const isIPFS = require('is-ipfs') isIPFS.multihash('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.multihash('noop') // false +isIPFS.multibase('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') // 'base32' +isIPFS.multibase('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') // 'base58btc' +isIPFS.multibase('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false (no multibase prefix in CIDv0) +isIPFS.multibase('noop') // false + 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 @@ -74,29 +82,52 @@ isIPFS.ipfsPath('/ipfs/invalid-hash') // false isIPFS.ipnsPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false isIPFS.ipnsPath('/ipns/github.com') // 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 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)` Returns `true` if the provided string is a valid `multihash` or `false` otherwise. +### `isIPFS.multibase(cid)` + +Returns a string with multibase name if the provided CID has `multibase` prefix or `false` otherwise. + ### `isIPFS.cid(hash)` 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)` +## URLs -Returns `true` if the provided string is a valid IPFS or IPNS path or `false` otherwise. - -### `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)` @@ -106,6 +137,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. @@ -114,10 +158,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/package.json b/package.json index 54bf002..5c3cc26 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,22 @@ { "name": "is-ipfs", - "version": "0.3.3", + "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", @@ -29,14 +29,15 @@ "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", diff --git a/src/index.js b/src/index.js index 516b2db..be394e7 100644 --- a/src/index.js +++ b/src/index.js @@ -2,10 +2,17 @@ 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) @@ -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 } @@ -76,7 +108,13 @@ function convertToString (input) { module.exports = { multihash: isMultihash, + multibase: isMultibase, cid: isCID, + base32cid: (cid) => (isMultibase(cid) === 'base32' && isCID(cid)), + ipfsSubdomain: (url) => isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch), + ipnsSubdomain: (url) => isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch), + subdomain: (url) => (isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch) || isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch)), + 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..8237d07 100644 --- a/test/test-cid.spec.js +++ b/test/test-cid.spec.js @@ -36,12 +36,19 @@ 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) done() }) + it('isIPFS.cid should not match an invalid CID', (done) => { const actual = isIPFS.cid('noop') expect(actual).to.equal(false) @@ -53,4 +60,6 @@ describe('ipfs cid', () => { expect(actual).to.equal(false) done() }) + + }) diff --git a/test/test-multibase.spec.js b/test/test-multibase.spec.js new file mode 100644 index 0000000..bab9b3f --- /dev/null +++ b/test/test-multibase.spec.js @@ -0,0 +1,73 @@ +/* eslint-env mocha */ +'use strict' + +const base58btc = require('bs58') +const expect = require('chai').expect +const isIPFS = require('../src/index') + +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() + }) + +}) + +describe('ipfs multibase', () => { + it('isIPFS.multibase should return false for a valid CIDv0 (raw multihash in base58btc, nor multibase prefix)', (done) => { + const actual = isIPFS.multibase('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') + expect(actual).to.equal(false) + done() + }) + + it('isIPFS.multibase should match a valid CIDv1 in base58btc', (done) => { + const actual = isIPFS.multibase('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') + expect(actual).to.equal('base58btc') + done() + }) + + it('isIPFS.multibase should match CIDv1 in Base32', (done) => { + const actual = isIPFS.multibase('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') + expect(actual).to.equal('base32') + done() + }) + + it('isIPFS.multibase should not match an invalid CID (with a typo)', (done) => { + const actual = isIPFS.multibase('afybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') + 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..aebacc6 --- /dev/null +++ b/test/test-subdomain.spec.js @@ -0,0 +1,146 @@ +/* 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(new Buffer(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(new Buffer(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(new Buffer(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() + }) + +}) From db6cc3c6af5b363ba74503d6a0999e1dcd2b280c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sun, 22 Jul 2018 23:39:59 +0200 Subject: [PATCH 4/7] refactor: follow new linter rules from latest aegir --- src/index.js | 2 +- test/test-cid.spec.js | 7 ++----- test/test-multibase.spec.js | 4 ---- test/test-multihash.spec.js | 4 ++-- test/test-path.spec.js | 8 ++++---- test/test-subdomain.spec.js | 7 +++---- test/test-url.spec.js | 6 +++--- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/index.js b/src/index.js index be394e7..88624d0 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,7 @@ 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) { diff --git a/test/test-cid.spec.js b/test/test-cid.spec.js index 8237d07..f9607f0 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() }) @@ -48,7 +48,6 @@ describe('ipfs cid', () => { done() }) - it('isIPFS.cid should not match an invalid CID', (done) => { const actual = isIPFS.cid('noop') expect(actual).to.equal(false) @@ -60,6 +59,4 @@ describe('ipfs cid', () => { expect(actual).to.equal(false) done() }) - - }) diff --git a/test/test-multibase.spec.js b/test/test-multibase.spec.js index bab9b3f..c5c5d7c 100644 --- a/test/test-multibase.spec.js +++ b/test/test-multibase.spec.js @@ -1,7 +1,6 @@ /* eslint-env mocha */ 'use strict' -const base58btc = require('bs58') const expect = require('chai').expect const isIPFS = require('../src/index') @@ -30,7 +29,6 @@ describe('ipfs base32cid', () => { done() }) - it('isIPFS.base32cid should not match an invalid CID', (done) => { const actual = isIPFS.base32cid('noop') expect(actual).to.equal(false) @@ -42,7 +40,6 @@ describe('ipfs base32cid', () => { expect(actual).to.equal(false) done() }) - }) describe('ipfs multibase', () => { @@ -69,5 +66,4 @@ describe('ipfs multibase', () => { 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 index aebacc6..23e0ffe 100644 --- a/test/test-subdomain.spec.js +++ b/test/test-subdomain.spec.js @@ -42,7 +42,7 @@ describe('ipfs subdomain', () => { }) it('isIPFS.ipfsSubdomain should not match a buffer data type', (done) => { - const actual = isIPFS.ipfsSubdomain(new Buffer(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR'))) + const actual = isIPFS.ipfsSubdomain(Buffer.from(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR'))) expect(actual).to.equal(false) done() }) @@ -82,7 +82,7 @@ describe('ipfs subdomain', () => { }) it('isIPFS.ipnsSubdomain should not match a buffer data type', (done) => { - const actual = isIPFS.ipnsSubdomain(new Buffer(base58.decode('QmNQuBJ8tg4QN6mSLXHekxBbcToPwKxamWNrDdEugxMTDd'))) + const actual = isIPFS.ipnsSubdomain(Buffer.from(base58.decode('QmNQuBJ8tg4QN6mSLXHekxBbcToPwKxamWNrDdEugxMTDd'))) expect(actual).to.equal(false) done() }) @@ -118,7 +118,7 @@ describe('ipfs subdomain', () => { }) it('isIPFS.subdomain should not match a buffer data type', (done) => { - const actual = isIPFS.subdomain(new Buffer(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR'))) + const actual = isIPFS.subdomain(Buffer.from(base58.decode('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR'))) expect(actual).to.equal(false) done() }) @@ -142,5 +142,4 @@ describe('ipfs subdomain', () => { 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() }) From 17f9292112d710509b2a9b3f59d152bd0872ccc5 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 23 Jul 2018 00:03:54 +0200 Subject: [PATCH 5/7] fix: remove old node builds from TravisCI --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) 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. From 8e053264402ddc418cc8ff0d739d66e09c0f9e59 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 23 Jul 2018 12:21:45 +0200 Subject: [PATCH 6/7] refactor: remove multibase check https://github.com/ipfs/is-ipfs/pull/20#discussion_r204333276 --- README.md | 10 +----- package.json | 1 - src/index.js | 1 - test/test-cid.spec.js | 38 ++++++++++++++++++++ test/test-multibase.spec.js | 69 ------------------------------------- 5 files changed, 39 insertions(+), 80 deletions(-) delete mode 100644 test/test-multibase.spec.js diff --git a/README.md b/README.md index 372be34..8e42ce9 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,6 @@ const isIPFS = require('is-ipfs') isIPFS.multihash('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.multihash('noop') // false -isIPFS.multibase('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') // 'base32' -isIPFS.multibase('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') // 'base58btc' -isIPFS.multibase('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false (no multibase prefix in CIDv0) -isIPFS.multibase('noop') // false - isIPFS.cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true (CIDv0) isIPFS.cid('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') // true (CIDv1) isIPFS.cid('noop') // false @@ -83,6 +78,7 @@ 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 @@ -111,10 +107,6 @@ Detection of IPFS Paths and identifiers in URLs is a two-stage process: Returns `true` if the provided string is a valid `multihash` or `false` otherwise. -### `isIPFS.multibase(cid)` - -Returns a string with multibase name if the provided CID has `multibase` prefix or `false` otherwise. - ### `isIPFS.cid(hash)` Returns `true` if the provided string is a valid `CID` or `false` otherwise. diff --git a/package.json b/package.json index 5c3cc26..7e3cf56 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "dependencies": { "bs58": "4.0.1", "cids": "0.5.3", - "multibase": "0.4.0", "multihashes": "0.4.13" }, "devDependencies": { diff --git a/src/index.js b/src/index.js index 88624d0..68a5427 100644 --- a/src/index.js +++ b/src/index.js @@ -108,7 +108,6 @@ function convertToString (input) { module.exports = { multihash: isMultihash, - multibase: isMultibase, cid: isCID, base32cid: (cid) => (isMultibase(cid) === 'base32' && isCID(cid)), ipfsSubdomain: (url) => isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch), diff --git a/test/test-cid.spec.js b/test/test-cid.spec.js index f9607f0..8243a48 100644 --- a/test/test-cid.spec.js +++ b/test/test-cid.spec.js @@ -60,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-multibase.spec.js b/test/test-multibase.spec.js deleted file mode 100644 index c5c5d7c..0000000 --- a/test/test-multibase.spec.js +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const expect = require('chai').expect -const isIPFS = require('../src/index') - -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() - }) -}) - -describe('ipfs multibase', () => { - it('isIPFS.multibase should return false for a valid CIDv0 (raw multihash in base58btc, nor multibase prefix)', (done) => { - const actual = isIPFS.multibase('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') - expect(actual).to.equal(false) - done() - }) - - it('isIPFS.multibase should match a valid CIDv1 in base58btc', (done) => { - const actual = isIPFS.multibase('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') - expect(actual).to.equal('base58btc') - done() - }) - - it('isIPFS.multibase should match CIDv1 in Base32', (done) => { - const actual = isIPFS.multibase('bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') - expect(actual).to.equal('base32') - done() - }) - - it('isIPFS.multibase should not match an invalid CID (with a typo)', (done) => { - const actual = isIPFS.multibase('afybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va') - expect(actual).to.equal(false) - done() - }) -}) From dcef7348af711880bfd3306f5b6775926957404b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 23 Jul 2018 13:22:25 +0200 Subject: [PATCH 7/7] refactor: addressing PR review --- README.md | 2 +- package.json | 1 + src/index.js | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e42ce9..379254c 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ isIPFS.ipnsSubdomain('http://foo-bar.ipns.dweb.link') // false (not a PeerID) # API -A suite of util methods provides efficient validation. +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 diff --git a/package.json b/package.json index 7e3cf56..5c3cc26 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "bs58": "4.0.1", "cids": "0.5.3", + "multibase": "0.4.0", "multihashes": "0.4.13" }, "devDependencies": { diff --git a/src/index.js b/src/index.js index 68a5427..acfef52 100644 --- a/src/index.js +++ b/src/index.js @@ -106,13 +106,16 @@ 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: (url) => isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch), - ipnsSubdomain: (url) => isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch), - subdomain: (url) => (isIpfs(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch) || isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnHashMatch)), + ipfsSubdomain: ipfsSubdomain, + ipnsSubdomain: ipnsSubdomain, + subdomain: (url) => (ipfsSubdomain(url) || ipnsSubdomain(url)), subdomainPattern: fqdnPattern, ipfsUrl: (url) => isIpfs(url, urlPattern), ipnsUrl: (url) => isIpns(url, urlPattern),