Customize: Harden url matching to account for varying ports and ensuring matching base pathname for allowed urls

Fixes #38409.

Built from https://develop.svn.wordpress.org/trunk@38890


git-svn-id: http://core.svn.wordpress.org/trunk@38833 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Weston Ruter 2016-10-24 20:07:31 +00:00
parent 1129311849
commit 885d1dd89d
7 changed files with 39 additions and 40 deletions

View File

@ -4040,7 +4040,7 @@
// ssl certs. // ssl certs.
previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) { previewer.add( 'previewUrl', params.previewUrl ).setter( function( to ) {
var result, urlParser, newPreviewUrl, schemeMatchingPreviewUrl, queryParams; var result = null, urlParser, queryParams, parsedAllowedUrl, parsedCandidateUrls = [];
urlParser = document.createElement( 'a' ); urlParser = document.createElement( 'a' );
urlParser.href = to; urlParser.href = to;
@ -4062,31 +4062,30 @@
} }
} }
newPreviewUrl = urlParser.href; parsedCandidateUrls.push( urlParser );
// Prepend list with URL that matches the scheme/protocol of the iframe.
if ( previewer.scheme.get() + ':' !== urlParser.protocol ) {
urlParser = document.createElement( 'a' );
urlParser.href = parsedCandidateUrls[0].href;
urlParser.protocol = previewer.scheme.get() + ':'; urlParser.protocol = previewer.scheme.get() + ':';
schemeMatchingPreviewUrl = urlParser.href; parsedCandidateUrls.unshift( urlParser );
}
// Attempt to match the URL to the control frame's scheme // Attempt to match the URL to the control frame's scheme
// and check if it's allowed. If not, try the original URL. // and check if it's allowed. If not, try the original URL.
$.each( [ schemeMatchingPreviewUrl, newPreviewUrl ], function( i, url ) { parsedAllowedUrl = document.createElement( 'a' );
$.each( previewer.allowedUrls, function( i, allowed ) { _.find( parsedCandidateUrls, function( parsedCandidateUrl ) {
var path; return ! _.isUndefined( _.find( previewer.allowedUrls, function( allowedUrl ) {
parsedAllowedUrl.href = allowedUrl;
allowed = allowed.replace( /\/+$/, '' ); if ( urlParser.protocol === parsedAllowedUrl.protocol && urlParser.host === parsedAllowedUrl.host && 0 === parsedAllowedUrl.pathname.indexOf( urlParser.pathname ) ) {
path = url.replace( allowed, '' ); result = parsedCandidateUrl.href;
return true;
if ( 0 === url.indexOf( allowed ) && /^([/#?]|$)/.test( path ) ) {
result = url;
return false;
}
});
if ( result ) {
return false;
} }
} ) );
} ); } );
// If we found a matching result, return it. If not, bail. return result;
return result ? result : null;
}); });
previewer.bind( 'ready', previewer.ready ); previewer.bind( 'ready', previewer.ready );

File diff suppressed because one or more lines are too long

View File

@ -654,7 +654,8 @@ window.wp = window.wp || {};
this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) { this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
var urlParser = document.createElement( 'a' ); var urlParser = document.createElement( 'a' );
urlParser.href = to; urlParser.href = to;
return urlParser.protocol + '//' + urlParser.hostname; // Port stripping needed by IE since it adds to host but not to event.origin.
return urlParser.protocol + '//' + urlParser.host.replace( /:80$/, '' );
}); });
// first add with no value // first add with no value

File diff suppressed because one or more lines are too long

View File

@ -275,13 +275,13 @@
* @param {HTMLAnchorElement|HTMLAreaElement} element Link element. * @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
* @param {string} element.search Query string. * @param {string} element.search Query string.
* @param {string} element.pathname Path. * @param {string} element.pathname Path.
* @param {string} element.hostname Hostname. * @param {string} element.host Host.
* @param {object} [options] * @param {object} [options]
* @param {object} [options.allowAdminAjax=false] Allow admin-ajax.php requests. * @param {object} [options.allowAdminAjax=false] Allow admin-ajax.php requests.
* @returns {boolean} Is appropriate for changeset link. * @returns {boolean} Is appropriate for changeset link.
*/ */
api.isLinkPreviewable = function isLinkPreviewable( element, options ) { api.isLinkPreviewable = function isLinkPreviewable( element, options ) {
var hasMatchingHost, urlParser, args; var matchesAllowedUrl, parsedAllowedUrl, args;
args = _.extend( {}, { allowAdminAjax: false }, options || {} ); args = _.extend( {}, { allowAdminAjax: false }, options || {} );
@ -294,15 +294,12 @@
return false; return false;
} }
urlParser = document.createElement( 'a' ); parsedAllowedUrl = document.createElement( 'a' );
hasMatchingHost = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) { matchesAllowedUrl = ! _.isUndefined( _.find( api.settings.url.allowed, function( allowedUrl ) {
urlParser.href = allowedUrl; parsedAllowedUrl.href = allowedUrl;
if ( urlParser.hostname === element.hostname && urlParser.protocol === element.protocol ) { return parsedAllowedUrl.protocol === element.protocol && parsedAllowedUrl.host === element.host && 0 === element.pathname.indexOf( parsedAllowedUrl.pathname );
return true;
}
return false;
} ) ); } ) );
if ( ! hasMatchingHost ) { if ( ! matchesAllowedUrl ) {
return false; return false;
} }
@ -331,7 +328,9 @@
* @access protected * @access protected
* *
* @param {HTMLAnchorElement|HTMLAreaElement} element Link element. * @param {HTMLAnchorElement|HTMLAreaElement} element Link element.
* @param {object} element.search Query string. * @param {string} element.search Query string.
* @param {string} element.host Host.
* @param {string} element.protocol Protocol.
* @returns {void} * @returns {void}
*/ */
api.prepareLinkPreview = function prepareLinkPreview( element ) { api.prepareLinkPreview = function prepareLinkPreview( element ) {
@ -348,7 +347,7 @@
} }
// Make sure links in preview use HTTPS if parent frame uses HTTPS. // Make sure links in preview use HTTPS if parent frame uses HTTPS.
if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.hostname ) ) { if ( 'https' === api.preview.scheme.get() && 'http:' === element.protocol && -1 !== api.settings.url.allowedHosts.indexOf( element.host ) ) {
element.protocol = 'https:'; element.protocol = 'https:';
} }
@ -496,7 +495,7 @@
urlParser.href = form.action; urlParser.href = form.action;
// Make sure forms in preview use HTTPS if parent frame uses HTTPS. // Make sure forms in preview use HTTPS if parent frame uses HTTPS.
if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.hostname ) ) { if ( 'https' === api.preview.scheme.get() && 'http:' === urlParser.protocol && -1 !== api.settings.url.allowedHosts.indexOf( urlParser.host ) ) {
urlParser.protocol = 'https:'; urlParser.protocol = 'https:';
form.action = urlParser.href; form.action = urlParser.href;
} }

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.7-alpha-38889'; $wp_version = '4.7-alpha-38890';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.