Skip to content

Commit

Permalink
Fix url validation errors (#11835)
Browse files Browse the repository at this point in the history
* Fix issue where href validation would incorrectly consider any URL with a fragment to be invalid

* Resolve issue where getFragment only matched to the last # encountered instead of the first

* Add extra checks for http urls to ensure the right number of forward slashes are used

* Update isValidProtocol to only consider the protocol as characters up to and including the colon

* Update changelogs
  • Loading branch information
talldan authored and noisysocks committed Nov 16, 2018
1 parent f3b4794 commit 2a0b617
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 8 deletions.
6 changes: 6 additions & 0 deletions packages/format-library/CHANGELOG.md
@@ -1,3 +1,9 @@
## 1.2.3 (Unreleased)

### Bug fixes
- Link URL validation now works correctly when a URL includes a fragment. Previously any URL containing a fragment failed validation.
- Link URL validation catches an incorrect number of forward slashes following a url using the http protocol.

## 1.2.2 (2018-11-15)

## 1.2.1 (2018-11-12)
Expand Down
3 changes: 3 additions & 0 deletions packages/format-library/src/link/test/utils.js
Expand Up @@ -26,6 +26,8 @@ describe( 'isValidHref', () => {
expect( isValidHref( 'https://test.com' ) ).toBe( true );
expect( isValidHref( 'http://test-with-hyphen.com' ) ).toBe( true );
expect( isValidHref( 'http://test.com/' ) ).toBe( true );
expect( isValidHref( 'http://test.com#fragment' ) ).toBe( true );
expect( isValidHref( 'http://test.com/path#fragment' ) ).toBe( true );
expect( isValidHref( 'http://test.com/with/path/separators' ) ).toBe( true );
expect( isValidHref( 'http://test.com/with?query=string&params' ) ).toBe( true );
} );
Expand All @@ -36,6 +38,7 @@ describe( 'isValidHref', () => {
expect( isValidHref( 'mailto: test@somewhere.com' ) ).toBe( false );
expect( isValidHref( 'ht#tp://this/is/invalid' ) ).toBe( false );
expect( isValidHref( 'ht#tp://th&is/is/invalid' ) ).toBe( false );
expect( isValidHref( 'http:/test.com' ) ).toBe( false );
expect( isValidHref( 'http://?test.com' ) ).toBe( false );
expect( isValidHref( 'http://#test.com' ) ).toBe( false );
expect( isValidHref( 'http://test.com?double?params' ) ).toBe( false );
Expand Down
10 changes: 8 additions & 2 deletions packages/format-library/src/link/utils.js
Expand Up @@ -37,13 +37,19 @@ export function isValidHref( href ) {
return false;
}

// Does the href start with something that looks like a url protocol?
// Does the href start with something that looks like a URL protocol?
if ( /^\S+:/.test( trimmedHref ) ) {
const protocol = getProtocol( trimmedHref );
if ( ! isValidProtocol( protocol ) ) {
return false;
}

// Add some extra checks for http(s) URIs, since these are the most common use-case.
// This ensures URIs with an http protocol have exactly two forward slashes following the protocol.
if ( startsWith( protocol, 'http' ) && ! /^https?:\/\/[^\/\s]/i.test( trimmedHref ) ) {
return false;
}

const authority = getAuthority( trimmedHref );
if ( ! isValidAuthority( authority ) ) {
return false;
Expand All @@ -60,7 +66,7 @@ export function isValidHref( href ) {
}

const fragment = getFragment( trimmedHref );
if ( fragment && ! isValidFragment( trimmedHref ) ) {
if ( fragment && ! isValidFragment( fragment ) ) {
return false;
}
}
Expand Down
6 changes: 6 additions & 0 deletions packages/url/CHANGELOG.md
@@ -1,3 +1,9 @@
## 2.3.1 (Unreleased)

### Bug fixes
- The `isValidProtocol` function now correctly considers the protocol of the URL as only incoporating characters up to and including the colon (':').
- `getFragment` is now greedier and matches fragments from the first occurence of the '#' symbol instead of the last.

## 2.3.0 (2018-11-12)

### New Features
Expand Down
6 changes: 3 additions & 3 deletions packages/url/src/index.js
Expand Up @@ -37,13 +37,13 @@ export function getProtocol( url ) {
*
* @param {string} protocol The url protocol.
*
* @return {boolean} True if the argument is a valid protocol (e.g. http://, tel:).
* @return {boolean} True if the argument is a valid protocol (e.g. http:, tel:).
*/
export function isValidProtocol( protocol ) {
if ( ! protocol ) {
return false;
}
return /^[a-z\-.\+]+[0-9]*:(?:\/\/)?\/?$/i.test( protocol );
return /^[a-z\-.\+]+[0-9]*:$/i.test( protocol );
}

/**
Expand Down Expand Up @@ -138,7 +138,7 @@ export function isValidQueryString( queryString ) {
* @return {?string} The fragment part of the URL.
*/
export function getFragment( url ) {
const matches = /^\S+(#[^\s\?]*)/.exec( url );
const matches = /^\S+?(#[^\s\?]*)/.exec( url );
if ( matches ) {
return matches[ 1 ];
}
Expand Down
4 changes: 1 addition & 3 deletions packages/url/src/test/index.test.js
Expand Up @@ -78,9 +78,7 @@ describe( 'isValidProtocol', () => {
expect( isValidProtocol( 'tel:' ) ).toBe( true );
expect( isValidProtocol( 'http:' ) ).toBe( true );
expect( isValidProtocol( 'https:' ) ).toBe( true );
expect( isValidProtocol( 'http://' ) ).toBe( true );
expect( isValidProtocol( 'https://' ) ).toBe( true );
expect( isValidProtocol( 'file:///' ) ).toBe( true );
expect( isValidProtocol( 'file:' ) ).toBe( true );
expect( isValidProtocol( 'test.protocol:' ) ).toBe( true );
expect( isValidProtocol( 'test-protocol:' ) ).toBe( true );
expect( isValidProtocol( 'test+protocol:' ) ).toBe( true );
Expand Down

0 comments on commit 2a0b617

Please sign in to comment.