1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
( function () {
/**
* Create an object like mw.Api, but automatically handling everything required to communicate
* with another MediaWiki wiki via cross-origin requests (CORS).
*
* The foreign wiki must be configured to accept requests from the current wiki. See
* <https://www.mediawiki.org/wiki/Manual:$wgCrossSiteAJAXdomains> for details.
*
* var api = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
* api.get( {
* action: 'query',
* meta: 'userinfo'
* } ).done( function ( data ) {
* console.log( data );
* } );
*
* To ensure that the user at the foreign wiki is logged in, pass the `assert: 'user'` parameter
* to #get/#post (since MW 1.23): if they are not, the API request will fail. (Note that this
* doesn't guarantee that it's the same user.)
*
* Authentication-related MediaWiki extensions may extend this class to ensure that the user
* authenticated on the current wiki will be automatically authenticated on the foreign one. These
* extension modules should be registered using the ResourceLoaderForeignApiModules hook. See
* CentralAuth for a practical example. The general pattern to extend and override the name is:
*
* function MyForeignApi() {};
* OO.inheritClass( MyForeignApi, mw.ForeignApi );
* mw.ForeignApi = MyForeignApi;
*
* @class mw.ForeignApi
* @extends mw.Api
* @since 1.26
*
* @constructor
* @param {string|mw.Uri} url URL pointing to another wiki's `api.php` endpoint.
* @param {Object} [options] See mw.Api.
* @param {Object} [options.anonymous=false] Perform all requests anonymously. Use this option if
* the target wiki may otherwise not accept cross-origin requests, or if you don't need to
* perform write actions or read restricted information and want to avoid the overhead.
*
* @author Bartosz Dziewoński
* @author Jon Robson
*/
function CoreForeignApi( url, options ) {
if ( !url || $.isPlainObject( url ) ) {
throw new Error( 'mw.ForeignApi() requires a `url` parameter' );
}
this.apiUrl = String( url );
this.anonymous = options && options.anonymous;
options = $.extend( /* deep=*/ true,
{
ajax: {
url: this.apiUrl,
xhrFields: {
withCredentials: !this.anonymous
}
},
parameters: {
// Add 'origin' query parameter to all requests.
origin: this.getOrigin()
}
},
options
);
// Call parent constructor
CoreForeignApi.parent.call( this, options );
}
OO.inheritClass( CoreForeignApi, mw.Api );
/**
* Return the origin to use for API requests, in the required format (protocol, host and port, if
* any).
*
* @protected
* @return {string}
*/
CoreForeignApi.prototype.getOrigin = function () {
var origin;
if ( this.anonymous ) {
return '*';
}
origin = location.protocol + '//' + location.hostname;
if ( location.port ) {
origin += ':' + location.port;
}
return origin;
};
/**
* @inheritdoc
*/
CoreForeignApi.prototype.ajax = function ( parameters, ajaxOptions ) {
var url, origin, newAjaxOptions;
// 'origin' query parameter must be part of the request URI, and not just POST request body
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' );
newAjaxOptions = $.extend( {}, ajaxOptions, { url: url } );
} else {
newAjaxOptions = ajaxOptions;
}
return CoreForeignApi.parent.prototype.ajax.call( this, parameters, newAjaxOptions );
};
// Expose
mw.ForeignApi = CoreForeignApi;
}() );
|