diff --git a/README.md b/README.md index 1be46fa..1ce31fe 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,12 @@ isIPFS.ipnsSubdomain('http://bafybeiabc2xofh6tdi6vutusorpumwcikw3hf3st4ecjugo6j5 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) + +isIPFS.multiaddr('/ip4/127.0.0.1/udp/1234') // true +isIPFS.multiaddr('/ip4/127.0.0.1/udp/1234/http') // true +isIPFS.multiaddr('/ip6/::1/udp/1234') // true +isIPFS.multiaddr('ip6/::1/udp/1234') // false +isIPFS.multiaddr('/yoloinvalid/::1/udp/1234') // false ``` # API @@ -115,7 +121,7 @@ Returns `true` if the provided string is a valid `multihash` or `false` otherwis ### `isIPFS.cid(hash)` -Returns `true` if the provided string is a valid `CID` or `false` otherwise. +Returns `true` if the provided string or [`CID`](/~https://github.com/ipld/js-cid) is a valid [CID](https://docs.ipfs.io/guides/concepts/cid/) or `false` otherwise. ### `isIPFS.base32cid(hash)` @@ -172,6 +178,11 @@ Returns `true` if the provided string includes a valid IPFS subdomain or `false` Returns `true` if the provided string includes a valid IPNS subdomain or `false` otherwise. +## Multiaddrs + +### `isIPFS.multiaddr(addr)` + +Returns `true` if the provided `string`, [`Multiaddr`](/~https://github.com/multiformats/js-multiaddr) or `Buffer` includes a valid [multiaddr](https://multiformats.io/multiaddr/) or `false` otherwise. # License diff --git a/package.json b/package.json index f9b08bd..3f0e957 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "bs58": "4.0.1", "cids": "~0.5.6", + "multiaddr": "6.0.4", "multibase": "~0.6.0", "multihashes": "~0.4.13" }, diff --git a/src/index.js b/src/index.js index 58e9f67..08de930 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ const base58 = require('bs58') const multihash = require('multihashes') const multibase = require('multibase') +const Multiaddr = require('multiaddr') const CID = require('cids') const urlPattern = /^https?:\/\/[^/]+\/(ip(f|n)s)\/((\w+).*)/ @@ -42,6 +43,20 @@ function isCID (hash) { } } +function isMultiaddr (input) { + if (!input) return false + if (isString(input) || input instanceof Buffer) { + try { + new Multiaddr(input) // eslint-disable-line no-new + return true + } catch (e) { + return false + } + } + if (Multiaddr.isMultiaddr(input)) return true + return false +} + function isIpfs (input, pattern, protocolMatch = defaultProtocolMatch, hashMatch = defaultHashMath) { const formatted = convertToString(input) if (!formatted) { @@ -116,6 +131,7 @@ const ipnsSubdomain = (url) => isIpns(url, fqdnPattern, fqdnProtocolMatch, fqdnH module.exports = { multihash: isMultihash, + multiaddr: isMultiaddr, cid: isCID, base32cid: (cid) => (isMultibase(cid) === 'base32' && isCID(cid)), ipfsSubdomain: ipfsSubdomain, diff --git a/test/test-cid.spec.js b/test/test-cid.spec.js index 8243a48..065e4d7 100644 --- a/test/test-cid.spec.js +++ b/test/test-cid.spec.js @@ -4,8 +4,16 @@ const base58 = require('bs58') const expect = require('chai').expect const isIPFS = require('../src/index') +const CID = require('cids') describe('ipfs cid', () => { + it('isIPFS.cid should match a valid CID instance', (done) => { + const cid = new CID('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') + const actual = isIPFS.cid(cid) + expect(actual).to.equal(true) + done() + }) + it('isIPFS.cid should match a valid CIDv0 (multihash)', (done) => { const actual = isIPFS.cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') expect(actual).to.equal(true) diff --git a/test/test-multiaddr.spec.js b/test/test-multiaddr.spec.js new file mode 100644 index 0000000..a388b25 --- /dev/null +++ b/test/test-multiaddr.spec.js @@ -0,0 +1,64 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const Multiaddr = require('multiaddr') +const isIPFS = require('../src/index') + +describe('ipfs multiaddr', () => { + it('isIPFS.multiaddr should match a string with valid ip4 multiaddr', (done) => { + const actual = isIPFS.multiaddr('/ip4/127.0.0.1/udp/1234/http') + expect(actual).to.equal(true) + done() + }) + + it('isIPFS.multiaddr should match a string with valid ip6 multiaddr', (done) => { + const actual = isIPFS.multiaddr('/ip6/::1/udp/1234/http') + expect(actual).to.equal(true) + done() + }) + + it('isIPFS.multiaddr should match a valid Multiaddr instance', (done) => { + const ma = new Multiaddr('/ip6/::1/udp/1234/http') + const actual = isIPFS.multiaddr(ma) + expect(actual).to.equal(true) + done() + }) + + it('isIPFS.multiaddr should match a Buffer with multiaddr', (done) => { + const ma = new Multiaddr('/ip6/::1/udp/1234/http') + const actual = isIPFS.multiaddr(Buffer.from(ma.buffer)) + expect(actual).to.equal(true) + done() + }) + + it('isIPFS.multiaddr should not match random Buffer', (done) => { + const actual = isIPFS.multiaddr(Buffer.from('randombuffer')) + expect(actual).to.equal(false) + done() + }) + + it('isIPFS.multiaddr should not match an invalid multiaddr (no initial slash)', (done) => { + const actual = isIPFS.multiaddr('ip4/127.0.0.1/udp/1234/http') + expect(actual).to.equal(false) + done() + }) + + it('isIPFS.multiaddr should not match an invalid multiaddr (unknown namespace)', (done) => { + const actual = isIPFS.multiaddr('/yoloinvalid/127.0.0.1/udp/1234/http') + expect(actual).to.equal(false) + done() + }) + + it('isIPFS.multiaddr should not match an invalid multiaddr', (done) => { + const actual = isIPFS.multiaddr('noop') + expect(actual).to.equal(false) + done() + }) + + it('isIPFS.multiaddr should not match an invalid multiaddr data type', (done) => { + const actual = isIPFS.multiaddr(4) + expect(actual).to.equal(false) + done() + }) +})