mw.ForeignApi: don’t set origin for same-origin requests

If the foreign API has the same host as the current page (e. g. if it’s
actually the same wiki, or multiple wikis are installed under different
paths on the same host), then the browser will not send an Origin
header, and if we still set an origin parameter, then the API will
complain that the two don’t match. Detect this and unset the origin
parameter in that case.

Bug: T208601
Change-Id: Ia006f3dc3283ce3f81d4d72cbe9676a00797c4d0
This commit is contained in:
Lucas Werkmeister 2019-09-09 16:55:35 +02:00
parent 1e2cce13ea
commit f07b69cf13
3 changed files with 43 additions and 7 deletions

View file

@ -895,6 +895,7 @@ return [
'dependencies' => [
'mediawiki.api',
'oojs',
'mediawiki.Uri',
],
'targets' => [ 'desktop', 'mobile' ],
],

View file

@ -59,7 +59,6 @@
}
},
parameters: {
// Add 'origin' query parameter to all requests.
origin: this.getOrigin()
}
},
@ -77,17 +76,26 @@
* any).
*
* @protected
* @return {string}
* @return {string|undefined}
*/
CoreForeignApi.prototype.getOrigin = function () {
var origin;
var origin, apiUri, apiOrigin;
if ( this.anonymous ) {
return '*';
}
origin = location.protocol + '//' + location.hostname;
if ( location.port ) {
origin += ':' + location.port;
}
apiUri = new mw.Uri( this.apiUrl );
apiOrigin = apiUri.protocol + '://' + apiUri.getAuthority();
if ( origin === apiOrigin ) {
// requests are not cross-origin, omit parameter
return undefined;
}
return origin;
};
@ -101,10 +109,12 @@
if ( ajaxOptions.type === 'POST' ) {
url = ( ajaxOptions && ajaxOptions.url ) || this.defaults.ajax.url;
origin = ( parameters && parameters.origin ) || this.defaults.parameters.origin;
url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
// Depending on server configuration, MediaWiki may forbid periods in URLs, due to an IE 6
// XSS bug. So let's escape them here. See WebRequest::checkUrlExtension() and T30235.
'origin=' + encodeURIComponent( origin ).replace( /\./g, '%2E' );
if ( origin !== undefined ) {
url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
// Depending on server configuration, MediaWiki may forbid periods in URLs, due to an IE 6
// XSS bug. So let's escape them here. See WebRequest::checkUrlExtension() and T30235.
'origin=' + encodeURIComponent( origin ).replace( /\./g, '%2E' );
}
newAjaxOptions = $.extend( {}, ajaxOptions, { url: url } );
} else {
newAjaxOptions = ajaxOptions;

View file

@ -29,4 +29,29 @@
return api.post( {} );
} );
QUnit.test( 'origin is not included in same-origin GET requests', function ( assert ) {
var apiUrl = location.protocol + '//' + location.host + '/w/api.php',
api = new mw.ForeignApi( apiUrl );
this.server.respond( function ( request ) {
assert.strictEqual( request.url.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in GET requests' );
request.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
} );
return api.get( {} );
} );
QUnit.test( 'origin is not included in same-origin POST requests', function ( assert ) {
var apiUrl = location.protocol + '//' + location.host + '/w/api.php',
api = new mw.ForeignApi( apiUrl );
this.server.respond( function ( request ) {
assert.strictEqual( request.requestBody.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in POST request body' );
assert.strictEqual( request.url.match( /origin=.*?(?:&|$)/ ), null, 'origin is not included in POST request URL, either' );
request.respond( 200, { 'Content-Type': 'application/json' }, '[]' );
} );
return api.post( {} );
} );
}() );