diff --git a/README.md b/README.md index 88c3ea6..fae9366 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,19 @@ isIPFS.path('/ipfs/js-ipfs/blob/master/README.md') // false isIPFS.urlOrPath('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.urlOrPath('https://ipfs.io/ipns/github.com') // true isIPFS.urlOrPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true +isIPFS.urlOrPath('ipfs://QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.urlOrPath('/ipns/github.com') // true +isIPFS.urlOrPath('ipns://github.com') // true isIPFS.urlOrPath('https://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true isIPFS.urlOrPath('https://google.com') // false isIPFS.ipfsUrl('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.ipfsUrl('https://ipfs.io/ipfs/invalid-hash') // false +isIPFS.ipfsUrl('ipfs://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.ipnsUrl('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false isIPFS.ipnsUrl('https://ipfs.io/ipns/github.com') // true +isIPFS.ipnsUrl('ipns://ipfs.io/ipns/github.com') // true isIPFS.ipfsPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true isIPFS.ipfsPath('/ipfs/invalid-hash') // false diff --git a/src/index.ts b/src/index.ts index 0d7b9be..2ba6120 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,15 +40,19 @@ * isIPFS.urlOrPath('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true * isIPFS.urlOrPath('https://ipfs.io/ipns/github.com') // true * isIPFS.urlOrPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true + * isIPFS.urlOrPath('ipfs://QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true * isIPFS.urlOrPath('/ipns/github.com') // true + * isIPFS.urlOrPath('ipns://github.com') // true * isIPFS.urlOrPath('https://bafybeie5gq4jxvzmsym6hjlwxej4rwdoxt7wadqvmmwbqi7r27fclha2va.ipfs.dweb.link') // true * isIPFS.urlOrPath('https://google.com') // false * * isIPFS.ipfsUrl('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true * isIPFS.ipfsUrl('https://ipfs.io/ipfs/invalid-hash') // false + * isIPFS.ipfsUrl('ipfs://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true * * isIPFS.ipnsUrl('https://ipfs.io/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // false * isIPFS.ipnsUrl('https://ipfs.io/ipns/github.com') // true + * isIPFS.ipnsUrl('ipns://ipfs.io/ipns/github.com') // true * * isIPFS.ipfsPath('/ipfs/QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true * isIPFS.ipfsPath('/ipfs/invalid-hash') // false @@ -116,6 +120,9 @@ 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])$/ +// URI IANA-scheme +const uriSchemePattern = /^(ip[fn]s):\/\/([^/?#]+)/ + function isMultihash (hash: Uint8Array | string): boolean { const formatted = convertToString(hash) @@ -320,13 +327,13 @@ export const subdomain = (url: string | Uint8Array): boolean => ipfsSubdomain(ur * Returns `true` if the provided string is a valid IPFS url or `false` * otherwise. */ -export const ipfsUrl = (url: string | Uint8Array): boolean => isIpfs(url, pathGatewayPattern) || ipfsSubdomain(url) +export const ipfsUrl = (url: string | Uint8Array): boolean => isIpfs(url, pathGatewayPattern) || ipfsSubdomain(url) || isIpfs(url, uriSchemePattern) /** * Returns `true` if the provided string is a valid IPNS url or `false` * otherwise. */ -export const ipnsUrl = (url: string | Uint8Array): boolean => isIpns(url, pathGatewayPattern) || ipnsSubdomain(url) +export const ipnsUrl = (url: string | Uint8Array): boolean => isIpns(url, pathGatewayPattern) || ipnsSubdomain(url) || isIpns(url, uriSchemePattern) /** * Returns `true` if the provided string is a valid IPFS or IPNS url or `false` diff --git a/test/test-path.spec.ts b/test/test-path.spec.ts index 6725ae1..e4c0c8e 100644 --- a/test/test-path.spec.ts +++ b/test/test-path.spec.ts @@ -107,6 +107,12 @@ describe('ipfs path', () => { done() }) + it('isIPFS.urlOrPath should match an IANA-schema compliant ipfs url', (done) => { + const actual = isIPFS.urlOrPath('ipfs://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') + expect(actual).to.equal(true) + done() + }) + it('isIPFS.urlOrPath should match ipns url', (done) => { const actual = isIPFS.urlOrPath('http://ipfs.io/ipns/foo.bar.com') expect(actual).to.equal(true) @@ -153,7 +159,12 @@ describe('ipfs path', () => { }) it('isIPFS.cidPath should not match an IPFS path', () => { - const actual = isIPFS.cidPath('/ipfs/QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') - expect(actual).to.equal(false) + expect(isIPFS.cidPath('/ipfs/QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm')).to.be.false() + }) +}) + +describe('ipns path', () => { + it('isIPFS.urlOrPath should match an IANA-schema compliant ipns url', () => { + expect(isIPFS.urlOrPath('ipns://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm')).to.be.true() }) }) diff --git a/test/test-url.spec.ts b/test/test-url.spec.ts index bd5bfb3..3523e3c 100644 --- a/test/test-url.spec.ts +++ b/test/test-url.spec.ts @@ -11,6 +11,12 @@ describe('ipfs url', () => { done() }) + it('isIPFS.ipfsUrl should match an IANA-schema compliant ipfs uri', (done) => { + const actual = isIPFS.ipfsUrl('ipfs://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') + expect(actual).to.equal(true) + done() + }) + it('isIPFS.ipfsUrl should match a complex ipfs url', (done) => { const actual = isIPFS.ipfsUrl('http://ipfs.alexandria.media/ipfs/QmeWz9YZEeNFXQhHg4PnR5ZiNr5isttgi5n1tc1eD5EfGU/content/index.html?arg=val#hash') expect(actual).to.equal(true) @@ -71,12 +77,24 @@ describe('ipfs url', () => { done() }) + it('isIPFS.ipnsUrl should not match an IANA-schema compliant ipfs uri', (done) => { + const actual = isIPFS.ipnsUrl('ipfs://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') + expect(actual).to.equal(false) + done() + }) + it('isIPFS.url should match an ipfs url', (done) => { const actual = isIPFS.url('http://ipfs.io/ipfs/QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') expect(actual).to.equal(true) done() }) + it('isIPFS.url should match an IANA-schema compliant ipfs uri', (done) => { + const actual = isIPFS.url('ipfs://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm') + expect(actual).to.equal(true) + done() + }) + it('isIPFS.url should match an ipns url', (done) => { const actual = isIPFS.url('http://ipfs.io/ipns/github.com/') expect(actual).to.equal(true) @@ -101,3 +119,17 @@ describe('ipfs url', () => { done() }) }) + +describe('ipns url', () => { + it('isIPFS.ipnsUrl should match an IANA-schema compliant ipns uri', () => { + expect(isIPFS.ipnsUrl('ipns://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm')).to.be.true() + }) + + it('isIPFS.ipnsUrl should not match an IANA-schema compliant ipfs uri', () => { + expect(isIPFS.ipnsUrl('ipfs://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm')).to.be.false() + }) + + it('isIPFS.url should match an IANA-schema compliant ipns uri', () => { + expect(isIPFS.url('ipns://QmYHNYAaYK5hm3ZhZFx5W9H6xydKDGimjdgJMrMSdnctEm')).to.be.true() + }) +})