-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: helper-ui input-validator update (#202)
* feat: helper-ui input-validator update the input validator now accepts the same urls as verified-fetch and provides more helpful information * fix: support native ipfs/ipns urls * fix: ux of input-validator help text * fix: regex support for more urls * fix: ux improvements to input-validator help text * fix: helper-ui input label * fix: preact import has no default * feat: helper-ui input allows CID only
- Loading branch information
Showing
7 changed files
with
246 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export interface IpfsUriParts { | ||
protocol: 'ipfs' | 'ipns' | ||
cidOrPeerIdOrDnslink: string | ||
path?: string | ||
parentDomain?: string | ||
} | ||
|
||
/** | ||
* `http[s]://${cid}.ipfs.example.com[/${path}]` | ||
* `http[s]://${dnsLinkDomain}.ipns.example.com[/${path}]` | ||
* `http[s]://${peerId}.ipns.example.com[/${path}]` | ||
* | ||
* @see https://regex101.com/r/EcY028/4 | ||
*/ | ||
export const subdomainRegex = /^(?:https?:\/\/|\/\/)?(?<cidOrPeerIdOrDnslink>[^/]+)\.(?<protocol>ip[fn]s)\.(?<parentDomain>[^/?#]*)(?<path>.*)$/ | ||
|
||
/** | ||
* `http[s]://example.com/ipfs/${cid}[/${path}]` | ||
* `/ipfs/${cid}[/${path}]` | ||
* `/ipns/${dnsLinkDomain}[/${path}]` | ||
* `/ipns/${peerId}[/${path}]` | ||
* | ||
* @see https://regex101.com/r/zdDp0i/1 | ||
*/ | ||
export const pathRegex = /^.*\/(?<protocol>ip[fn]s)\/(?<cidOrPeerIdOrDnslink>[^/?#]*)(?<path>.*)$/ | ||
|
||
/** | ||
* `ip[fn]s://${cidOrPeerIdOrDnslink}${path}` | ||
*/ | ||
export const nativeProtocolRegex = /^(?<protocol>ip[fn]s):\/\/(?<cidOrPeerIdOrDnslink>[^/?#]*)(?<path>.*)$/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Tests | ||
|
||
These tests are ran using `aegir test`. | ||
Tests with the name `*.spec.ts` are ran using `npm run test:iso`. | ||
|
||
Since we don't use aegir for building our dist folder, we need all tests in this directory to be javascript files. This is a temporary solution until we can use aegir for building our dist folder. | ||
There is one file without a `.spec.ts` suffix that verifies our dist folder ran with `npm run test:node`, and no further test files without `.spec.ts` suffix should be added. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* eslint-env mocha */ | ||
import { expect } from 'aegir/chai' | ||
import { nativeProtocolRegex, pathRegex, subdomainRegex } from '../src/lib/regex.js' | ||
|
||
const validPathUrls = [ | ||
// IPFS paths without domain | ||
['/ipfs/bafyFoo', 'ipfs', 'bafyFoo', ''], | ||
['/ipfs/bafyFoo/', 'ipfs', 'bafyFoo', '/'], | ||
['/ipfs/bafyFoo/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
|
||
// IPFS paths with domain | ||
['http://example.com/ipfs/bafyFoo', 'ipfs', 'bafyFoo', ''], | ||
['http://example.com/ipfs/bafyFoo/', 'ipfs', 'bafyFoo', '/'], | ||
['http://example.com/ipfs/bafyFoo/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
['http://example.com/ipfs/bafyFoo/path/to/file/', 'ipfs', 'bafyFoo', '/path/to/file/'], | ||
|
||
// IPNS paths without domain | ||
['/ipns/specs.ipfs.tech', 'ipns', 'specs.ipfs.tech', ''], | ||
['/ipns/specs.ipfs.tech/', 'ipns', 'specs.ipfs.tech', '/'], | ||
['/ipns/specs.ipfs.tech/path/to/file', 'ipns', 'specs.ipfs.tech', '/path/to/file'], | ||
|
||
// IPNS paths with domain | ||
['http://example.com/ipns/specs.ipfs.tech', 'ipns', 'specs.ipfs.tech', ''], | ||
['http://example.com/ipns/specs.ipfs.tech/', 'ipns', 'specs.ipfs.tech', '/'], | ||
['http://example.com/ipns/specs.ipfs.tech/path/to/file', 'ipns', 'specs.ipfs.tech', '/path/to/file'], | ||
['http://example.com/ipns/specs.ipfs.tech/path/to/file/', 'ipns', 'specs.ipfs.tech', '/path/to/file/'], | ||
|
||
// schemeless | ||
['//example.com/ipns/specs.ipfs.tech', 'ipns', 'specs.ipfs.tech', ''], | ||
['//example.com/ipns/specs.ipfs.tech/', 'ipns', 'specs.ipfs.tech', '/'], | ||
['//example.com/ipns/specs.ipfs.tech/path/to/file', 'ipns', 'specs.ipfs.tech', '/path/to/file'], | ||
['//example.com/ipns/specs.ipfs.tech/path/to/file/', 'ipns', 'specs.ipfs.tech', '/path/to/file/'], | ||
|
||
// with different path starts (hash, query, etc) | ||
['/ipfs/bafyFoo#hash', 'ipfs', 'bafyFoo', '#hash'], | ||
['/ipfs/bafyFoo?query', 'ipfs', 'bafyFoo', '?query'], | ||
['/ipfs/bafyFoo?query#hash', 'ipfs', 'bafyFoo', '?query#hash'], | ||
['/ipfs/bafyFoo#hash?query', 'ipfs', 'bafyFoo', '#hash?query'] | ||
] | ||
|
||
const validSubdomainUrls = [ | ||
// IPFS subdomains | ||
['http://bafyFoo.ipfs.example.com', 'ipfs', 'bafyFoo', ''], | ||
['http://bafyFoo.ipfs.example.com/', 'ipfs', 'bafyFoo', '/'], | ||
['http://bafyFoo.ipfs.example.com/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
|
||
// IPNS subdomains | ||
['http://bafyFoo.ipns.example.com', 'ipns', 'bafyFoo', ''], | ||
['http://bafyFoo.ipns.example.com/', 'ipns', 'bafyFoo', '/'], | ||
['http://bafyFoo.ipns.example.com/path/to/file', 'ipns', 'bafyFoo', '/path/to/file'], | ||
|
||
// IPNS subdomains with dnslink | ||
['http://specs-ipfs-tech.ipns.example.com', 'ipns', 'specs-ipfs-tech', ''], | ||
['http://specs-ipfs-tech.ipns.example.com/', 'ipns', 'specs-ipfs-tech', '/'], | ||
['http://specs-ipfs-tech.ipns.example.com/path/to/file', 'ipns', 'specs-ipfs-tech', '/path/to/file'], | ||
|
||
// schemeless | ||
['//bafyFoo.ipfs.example.com', 'ipfs', 'bafyFoo', ''], | ||
['//bafyFoo.ipfs.example.com/', 'ipfs', 'bafyFoo', '/'], | ||
['//bafyFoo.ipfs.example.com/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
|
||
['//bafyFoo.ipns.example.com', 'ipns', 'bafyFoo', ''], | ||
['//bafyFoo.ipns.example.com/', 'ipns', 'bafyFoo', '/'], | ||
['//bafyFoo.ipns.example.com/path/to/file', 'ipns', 'bafyFoo', '/path/to/file'], | ||
|
||
['//specs-ipfs-tech.ipns.example.com', 'ipns', 'specs-ipfs-tech', ''], | ||
['//specs-ipfs-tech.ipns.example.com/', 'ipns', 'specs-ipfs-tech', '/'], | ||
['//specs-ipfs-tech.ipns.example.com/path/to/file', 'ipns', 'specs-ipfs-tech', '/path/to/file'], | ||
|
||
// hostname only | ||
['bafyFoo.ipfs.example.com', 'ipfs', 'bafyFoo', ''], | ||
['bafyFoo.ipfs.example.com/', 'ipfs', 'bafyFoo', '/'], | ||
['bafyFoo.ipfs.example.com/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
|
||
['bafyFoo.ipns.example.com', 'ipns', 'bafyFoo', ''], | ||
['bafyFoo.ipns.example.com/', 'ipns', 'bafyFoo', '/'], | ||
['bafyFoo.ipns.example.com/path/to/file', 'ipns', 'bafyFoo', '/path/to/file'], | ||
|
||
['specs-ipfs-tech.ipns.example.com', 'ipns', 'specs-ipfs-tech', ''], | ||
['specs-ipfs-tech.ipns.example.com/', 'ipns', 'specs-ipfs-tech', '/'], | ||
['specs-ipfs-tech.ipns.example.com/path/to/file', 'ipns', 'specs-ipfs-tech', '/path/to/file'], | ||
|
||
// with different path starts (hash, query, etc) | ||
['bafyFoo.ipfs.example.com#hash', 'ipfs', 'bafyFoo', '#hash'], | ||
['bafyFoo.ipfs.example.com?query', 'ipfs', 'bafyFoo', '?query'], | ||
['bafyFoo.ipfs.example.com?query#hash', 'ipfs', 'bafyFoo', '?query#hash'], | ||
['bafyFoo.ipfs.example.com#hash?query', 'ipfs', 'bafyFoo', '#hash?query'] | ||
] | ||
|
||
const validNativeProtocolUrls = [ | ||
['ipfs://bafyFoo', 'ipfs', 'bafyFoo', ''], | ||
['ipfs://bafyFoo/', 'ipfs', 'bafyFoo', '/'], | ||
['ipfs://bafyFoo/path/to/file', 'ipfs', 'bafyFoo', '/path/to/file'], | ||
|
||
['ipns://specs.ipfs.tech', 'ipns', 'specs.ipfs.tech', ''], | ||
['ipns://specs.ipfs.tech/', 'ipns', 'specs.ipfs.tech', '/'], | ||
['ipns://specs.ipfs.tech/path/to/file', 'ipns', 'specs.ipfs.tech', '/path/to/file'] | ||
] | ||
|
||
const invalidUrls = [ | ||
'http://localhost/notipfs/bafyFoo/path/to/file' | ||
] | ||
|
||
describe('regex', () => { | ||
describe('paths', () => { | ||
validPathUrls.forEach(([url, protocol, cidOrPeerIdOrDnslink, path]) => { | ||
it(`should correctly match "${url}"`, () => { | ||
const match = url.match(pathRegex) | ||
|
||
expect(match).not.to.be.null() | ||
expect(match?.groups).to.be.ok() | ||
expect(match?.groups?.protocol).to.equal(protocol) | ||
expect(match?.groups?.cidOrPeerIdOrDnslink).to.equal(cidOrPeerIdOrDnslink) | ||
expect(match?.groups?.path).to.equal(path) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('subdomains', () => { | ||
validSubdomainUrls.forEach(([url, protocol, cidOrPeerIdOrDnslink, path]) => { | ||
it(`should correctly match "${url}"`, () => { | ||
const match = url.match(subdomainRegex) | ||
|
||
expect(match).not.to.be.null() | ||
expect(match?.groups).to.be.ok() | ||
expect(match?.groups?.protocol).to.equal(protocol) | ||
expect(match?.groups?.cidOrPeerIdOrDnslink).to.equal(cidOrPeerIdOrDnslink) | ||
expect(match?.groups?.path).to.equal(path) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('native protocols', () => { | ||
validNativeProtocolUrls.forEach(([url, protocol, cidOrPeerIdOrDnslink, path]) => { | ||
it(`should correctly match "${url}"`, () => { | ||
const match = url.match(nativeProtocolRegex) | ||
|
||
expect(match).not.to.be.null() | ||
expect(match?.groups).to.be.ok() | ||
expect(match?.groups?.protocol).to.equal(protocol) | ||
expect(match?.groups?.cidOrPeerIdOrDnslink).to.equal(cidOrPeerIdOrDnslink) | ||
expect(match?.groups?.path).to.equal(path) | ||
}) | ||
}) | ||
}) | ||
|
||
describe('invalid urls', () => { | ||
invalidUrls.forEach(url => { | ||
it(`should return null for "${url}"`, () => { | ||
const match = url.match(pathRegex) | ||
|
||
expect(match).to.be.null() | ||
}) | ||
}) | ||
}) | ||
}) |