b54ecc11fd88ce4f45ab95b0e9ffb163bfee2edd
5 * Built to support cross domain uploading, and api actions for a approved set of domains.
6 * mwProxy enables a system for fluid contributions across wikis domains for which your logged in.
8 * The framework support a request approval system for per-user domain approval
9 * and a central blacklisting of domains controlled by site or system administrators.
13 * Domain A (lets say en.wiki)
14 * invokes add-media-wizard and wants to upload to domain B ( commons.wiki )
16 * Domain A loads iframe to domain B ? with request param to to insert from Domain A
17 * Domain B checks list of approved domains for (Domain A) & checks the user is logged in ( and if the same account name )
18 * if user is not logged in
19 * a _link_ to Domain B to new window login page is given
20 * if user has not approved domain and (Domain A) is not pre-approved
21 * a new page link is generated with a approve domain request
22 * if user approves domain it goes into their User:{username}/apiProxyDomains.js config
23 * If Domain A is approved we then:
24 * loads a "push" and "pull" iframe back to Domain A
25 (Domain B can change the #hash values of these children thereby proxy the data)
26 * Domain A now gets the iframe "loaded" callback a does a initial echo to confirm cross domain proxy
27 * echo sends "echo" to push and (Domain A) js passes the echo onto the "pull"
28 * Domain A now sends api requests to the iframe "push" child and gets results from the iframe "pull"
29 * api actions happen with status updates and everything and we can reuse existing api interface code
31 * if the browser supports it we can pass msgs with the postMessage API
32 * http://ejohn.org/blog/cross-window-messaging/
34 * @@todo it would be nice if this supported multiple proxy targets (ie to a bright widgets future)
39 "mwe-setting-up-proxy" : "Setting up proxy",
40 "mwe-re-try" : "Retry Api request",
41 "mwe-re-trying": "Retrying api request",
42 "mwe-cancel" : "Cancel",
43 "mwe-proxy-not-ready": "Proxy is not configured",
44 "mwe-please-login" : "Please <a target=\"_new\" href=\"$1\">login</a> on ($2) and or enable mwEmbed and retry the request",
45 "mwe-remember-loging": "As a general security reminder. Only login to web sites when your address bar displays that site's address"
50 * Base API Proxy object
56 * The client setup function:
58 $.proxy
.client = function( pConf
, conf
){
61 if( pConf
.server_frame
)
62 $.proxy
.server_frame
= pConf
.server_frame
;
64 if( pConf
.client_frame_path
){
65 $.proxy
.client_frame_path
= pConf
.client_frame_path
;
67 //guess the client frame path:
68 $.proxy
.client_frame_path
= wgScriptPath
+'/js2/mwEmbed/libMwApi/NestedCallbackIframe.html';
71 if( parseUri( $.proxy
.server_frame
).host
== parseUri( document
.URL
).host
){
72 js_log("Error: why are you trying to proxy yourself? " );
77 //set the frameProxy Flag:
78 var frameProxyOk
= false;
79 /* setup a iframe request hash */
80 $.proxy
.doFrameProxy = function( reqObj
){
82 'cd': parseUri( document
.URL
).host
,
83 'cfp': $.proxy
.client_frame_path
,
86 js_log( "Do frame proxy request on src: \n" + $.proxy
.server_frame
+ "\n" +
87 JSON
.stringify( reqObj
) );
88 //we can't update src's so we have to remove and add all the time :(
89 //@@todo we should support frame msg system
90 $j('#frame_proxy').remove();
91 $j('body').append('<iframe style="display:none" id="frame_proxy" name="frame_proxy" ' +
92 'src="' + $.proxy
.server_frame
+
93 '#' + escape( JSON
.stringify( hashPack
) ) +
97 $j('#frame_proxy').get(0).onload = function(){
98 //add a 5 second timeout for setting up the nested child callback (after page load)
99 setTimeout(function(){
101 //we timmed out no api proxy (should make sure the user is "logged in")
102 js_log("Error:: api proxy timeout are we logged in? mwEmbed is on?");
103 $.proxy
.proxyNotReadyDialog();
109 $.proxy
.proxyNotReadyDialog = function(){
111 btn
[ gM('mwe-re-try') ] = function(){
112 $j
.addLoaderDialog( gM('mwe-re-trying') );
113 $.proxy
.doFrameProxy( lastApiReq
);
115 btn
[ gM('mwe-cancel') ] = function(){
116 $j
.closeLoaderDialog();
118 var pUri
= parseUri( $.proxy
.server_frame
);
119 //this is sort of a temporary hack if we change the MediaWiki:ApiProxy key
120 //we will have to deal with that here as well:
121 var login_url
= pUri
.protocol
+'://'+ pUri
.host
+
122 pUri
.path
.replace( 'MediaWiki:ApiProxy', 'Special:UserLogin');
123 $j
.addDialog( gM('mwe-proxy-not-ready'), gM('mwe-please-login', [ login_url
, pUri
.host
] ) +
124 '<p style="font-size:small">' + gM('mwe-remember-loging') + '</p>',
128 /* the do_api_request with callback: */
129 $.proxy
.doRequest = function( reqObj
, callback
){
130 js_log("doRequest:: " + JSON
.stringify( reqObj
) );
132 //setup the callback:
133 $.proxy
.callback
= callback
;
135 $.proxy
.doFrameProxy( reqObj
);
138 * The nested iframe action that passes its msg back up to the top instance
140 $.proxy
.nested = function( hashResult
){
141 //close the loader if present:
142 $j
.closeLoaderDialog();
143 js_log( '$.proxy.nested callback :: ' + unescape( hashResult
) );
145 //try to parse the hash result:
147 var rObj
= JSON
.parse( unescape( hashResult
) );
149 js_log("Error could not parse hashResult");
151 //special callback to frameProxyOk flag (not an api result, don't call callback)
152 if( rObj
.state
== 'ok')
155 //if all good pass it to the callback:
156 $.proxy
.callback( rObj
);
159 * The serverApiProxy handles the actual proxy
160 * and child frames pointing to the parent "blank" frames
162 * This is (Domain B) in the above described setup
164 $.proxy
.server = function( pConf
, callback
){
165 /* clear the body of any html */
166 $j('body').html( 'proxy setup' );
168 //read the anchor action from the requesting url
169 var jmsg
= unescape( parseUri( document
.URL
).anchor
);
171 var aObj
= JSON
.parse( jmsg
);
173 js_log("ProxyServer:: could not parse anchor");
176 js_log("Error: no client domain provided ");
180 js_log("Setup server on: " + parseUri( document
.URL
).host
+
181 ' client from: ' + aObj
.cd
+
182 ' to nested target: ' + aObj
.cfp
);
184 // make sure we are logged in
185 // (its a normal mediaWiki page so all site vars should be defined)
187 js_log('error Not logged in');
191 var domain
= aObj
.cd
;
192 var nested_frame_src
= 'http://' + aObj
.cd
+ aObj
.cfp
;
193 //check the master whitelist
194 for(var i
in pConf
.master_whitelist
){
195 if( domain
== pConf
.master_whitelist
[ i
] ){
197 return doNestedProxy( aObj
.req
);
200 //check master blacklist
201 for(var i
in pConf
.master_blacklist
){
202 if( domain
== pConf
.master_blacklist
){
203 js_log('domain: ' + domain
+ ' is blacklisted');
207 //@@todo grab the users whitelist for our current domain
208 /*var local_api = wgScriptPath + '/index' + wgScriptExtension + '?title=' +
209 'User:' + wgUserName + '/apiProxyDomainList.js' +
210 '&action=raw&smaxage=0&gen=js';
211 $j.get( local_api, function( data ){
215 //if still not found:
216 js_log("domain " + domain
+ " not approved");
218 //offer the user the ability to "approve" requested domain save to their user page
220 function doNestedProxy( reqObj
){
221 js_log("doNestedProxy to: " + nested_frame_src
);
222 //output iframe prior to running api request
223 //(so we can fail faster / cache the nested page / simotaniusly load things)
224 doNestedFrame ( 'nested_ok' , {'state':'ok'});
226 var outputhash
= escape( JSON
.stringify( reqObj
) );
227 //add some api stuff:
228 reqObj
['format'] = 'json';
229 //process the api request
230 $j
.post(wgScriptPath
+ '/api' + wgScriptExtension
,
233 //js_log("Proxy GOT Res: " + data );
234 //put it into the nested frame hash string:
235 doNestedFrame( 'nested_push', JSON
.parse( data
) );
239 //add the doNestedFrame iframe:
240 function doNestedFrame( nestname
, resultObj
){
241 $j('#nested_push').remove();
242 //setup the nested proxy that points back to top domain:
243 $j('body').append( '<iframe id="nested_push" name="nested_push" ' +
244 'src="'+ nested_frame_src
+
245 '#' + escape( JSON
.stringify( resultObj
) ) +