cubicweb security #36257: les urls /add/EntityName sont accessibles en anonyme
/* * :organization: Logilab * :copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. * :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr */CubicWeb.require('python.js');CubicWeb.require('htmlhelpers.js');varJSON_BASE_URL=baseuri()+'json?';function_loadAjaxHtmlHead(node,head,tag,srcattr){varloaded=[];varjqtagfilter=tag+'['+srcattr+']';jQuery('head '+jqtagfilter).each(function(i){loaded.push(this.getAttribute(srcattr));});node.find(tag).each(function(i){if(this.getAttribute(srcattr)){if(!loaded.contains(this.getAttribute(srcattr))){jQuery(this).appendTo(head);}}else{jQuery(this).appendTo(head);}});node.find(jqtagfilter).remove();}/* * inspect dom response, search for a <div class="ajaxHtmlHead"> node and * put its content into the real document's head. * This enables dynamic css and js loading and is used by replacePageChunk */functionloadAjaxHtmlHead(node){varhead=jQuery('head');node=jQuery(node).find('div.ajaxHtmlHead');_loadAjaxHtmlHead(node,head,'script','src');_loadAjaxHtmlHead(node,head,'link','href');node.find('*').appendTo(head);}functionpreprocessAjaxLoad(node,newdomnode){loadAjaxHtmlHead(newdomnode);}functionpostAjaxLoad(node){// find sortable tables if there are someif(typeof(Sortable)!='undefined'){Sortable.sortTables(node);}// find textareas and wrap them if there are someif(typeof(FCKeditor)!='undefined'){buildWysiwygEditors();}if(typeofinitFacetBoxEvents!='undefined'){initFacetBoxEvents(node);}if(typeofbuildWidgets!='undefined'){buildWidgets(node);}if(typeofroundedCorners!='undefined'){roundedCorners(node);}if(typeofsetFormsTarget!='undefined'){setFormsTarget(node);}loadDynamicFragments(node);// XXX simulates document.ready, but the former// only runs once, this one potentially many times// we probably need to unbind the fired events// When this is done, jquery.treeview.js (for instance)// can be unpatched.jQuery(CubicWeb).trigger('ajax-loaded');}/* cubicweb loadxhtml plugin to make jquery handle xhtml response * * fetches `url` and replaces this's content with the result * * @param mode how the replacement should be done (default is 'replace') * Possible values are : * - 'replace' to replace the node's content with the generated HTML * - 'swap' to replace the node itself with the generated HTML * - 'append' to append the generated HTML to the node's content */jQuery.fn.loadxhtml=function(url,data,reqtype,mode){varajax=null;if(reqtype=='post'){ajax=jQuery.post;}else{ajax=jQuery.get;}if(this.size()>1){log('loadxhtml was called with more than one element');}varnode=this.get(0);// only consider the first elementmode=mode||'replace';varcallback=null;if(data&&data.callback){callback=data.callback;deletedata.callback;}ajax(url,data,function(response){vardomnode=getDomFromResponse(response);preprocessAjaxLoad(node,domnode);if(mode=='swap'){varorigId=node.id;node=swapDOM(node,domnode);if(!node.id){node.id=origId;}}elseif(mode=='replace'){jQuery(node).empty().append(domnode);}elseif(mode=='append'){jQuery(node).append(domnode);}postAjaxLoad(node);while(jQuery.isFunction(callback)){callback=callback.apply(this,[domnode]);}});};/* finds each dynamic fragment in the page and executes the * the associated RQL to build them (Async call) */functionloadDynamicFragments(node){if(node){varfragments=jQuery(node).find('div.dynamicFragment');}else{varfragments=jQuery('div.dynamicFragment');}if(fragments.length==0){return;}if(typeofLOADING_MSG=='undefined'){LOADING_MSG='loading';// this is only a safety belt, it should not happen}for(vari=0;i<fragments.length;i++){varfragment=fragments[i];fragment.innerHTML='<h3>'+LOADING_MSG+' ... <img src="data/loading.gif" /></h3>';// if cubicweb:loadurl is set, just pick the url et send it to loadxhtmlvarurl=getNodeAttribute(fragment,'cubicweb:loadurl');if(url){jQuery(fragment).loadxhtml(url);continue;}// else: rebuild full url by fetching cubicweb:rql, cubicweb:vid, etc.varrql=getNodeAttribute(fragment,'cubicweb:rql');varitems=getNodeAttribute(fragment,'cubicweb:vid').split('&');varvid=items[0];varextraparams={};// case where vid='myvid¶m1=val1¶m2=val2': this is a deprecated abuse-caseif(items.length>1){console.log("[3.5] you're using extraargs in cubicweb:vid attribute, this is deprecated, consider using loadurl instead");for(varj=1;j<items.length;j++){varkeyvalue=items[j].split('=');extraparams[keyvalue[0]]=keyvalue[1];}}varactrql=getNodeAttribute(fragment,'cubicweb:actualrql');if(actrql){extraparams['actualrql']=actrql;}varfbvid=getNodeAttribute(fragment,'cubicweb:fallbackvid');if(fbvid){extraparams['fallbackvid']=fbvid;}replacePageChunk(fragment.id,rql,vid,extraparams);}}jQuery(document).ready(function(){loadDynamicFragments();});//============= base AJAX functions to make remote calls =====================//functionremoteCallFailed(err,req){if(req.status==500){updateMessage(err);}else{updateMessage(_("an error occured while processing your request"));}}/* * This function will call **synchronously** a remote method on the cubicweb server * @param fname: the function name to call (as exposed by the JSONController) * * additional arguments will be directly passed to the specified function * * It looks at http headers to guess the response type. */functionremoteExec(fname/* ... */){setProgressCursor();varprops={'fname':fname,'pageid':pageid,'arg':map(jQuery.toJSON,sliceList(arguments,1))};varresult=jQuery.ajax({url:JSON_BASE_URL,data:props,async:false}).responseText;if(result){result=evalJSON(result);}resetCursor();returnresult;}/* * This function will call **asynchronously** a remote method on the json * controller of the cubicweb http server * * @param fname: the function name to call (as exposed by the JSONController) * * additional arguments will be directly passed to the specified function * * It looks at http headers to guess the response type. */functionasyncRemoteExec(fname/* ... */){setProgressCursor();varprops={'fname':fname,'pageid':pageid,'arg':map(jQuery.toJSON,sliceList(arguments,1))};vardeferred=loadRemote(JSON_BASE_URL,props,'POST');deferred=deferred.addErrback(remoteCallFailed);deferred=deferred.addErrback(resetCursor);deferred=deferred.addCallback(resetCursor);returndeferred;}/* emulation of gettext's _ shortcut */function_(message){returnremoteExec('i18n',[message])[0];}functionuserCallback(cbname){asyncRemoteExec('user_callback',cbname);}functionunloadPageData(){// NOTE: do not make async calls on unload if you want to avoid// strange bugsremoteExec('unload_page_data');}functionopenHash(){if(document.location.hash){varnid=document.location.hash.replace('#','');varnode=jQuery('#'+nid);if(node){removeElementClass(node,"hidden");}};}jQuery(document).ready(openHash);functionreloadComponent(compid,rql,registry,nodeid,extraargs){registry=registry||'components';rql=rql||'';nodeid=nodeid||(compid+'Component');extraargs=extraargs||{};varnode=getNode(nodeid);vard=asyncRemoteExec('component',compid,rql,registry,extraargs);d.addCallback(function(result,req){vardomnode=getDomFromResponse(result);if(node){// make sure the component is visibleremoveElementClass(node,"hidden");swapDOM(node,domnode);postAjaxLoad(domnode);}});d.addCallback(resetCursor);d.addErrback(function(xxx){updateMessage(_("an error occured"));log(xxx);});returnd;}/* XXX: HTML architecture of cubicweb boxes is a bit strange */functionreloadBox(boxid,rql){returnreloadComponent(boxid,rql,'boxes',boxid);}functionuserCallbackThenUpdateUI(cbname,compid,rql,msg,registry,nodeid){vard=asyncRemoteExec('user_callback',cbname);d.addCallback(function(){reloadComponent(compid,rql,registry,nodeid);if(msg){updateMessage(msg);}});d.addCallback(resetCursor);d.addErrback(function(xxx){updateMessage(_("an error occured"));log(xxx);returnresetCursor();});}functionuserCallbackThenReloadPage(cbname,msg){vard=asyncRemoteExec('user_callback',cbname);d.addCallback(function(){window.location.reload();if(msg){updateMessage(msg);}});d.addCallback(resetCursor);d.addErrback(function(xxx){updateMessage(_("an error occured"));log(xxx);returnresetCursor();});}/* * unregisters the python function registered on the server's side * while the page was generated. */functionunregisterUserCallback(cbname){vard=asyncRemoteExec('unregister_user_callback',cbname);d.addCallback(function(){resetCursor();});d.addErrback(function(xxx){updateMessage(_("an error occured"));log(xxx);returnresetCursor();});}/* executes an async query to the server and replaces a node's * content with the query result * * @param nodeId the placeholder node's id * @param rql the RQL query * @param vid the vid to apply to the RQL selection (default if not specified) * @param extraparmas table of additional query parameters */functionreplacePageChunk(nodeId,rql,vid,extraparams,/* ... */swap,callback){varparams=null;if(callback){params={callback:callback};}varnode=jQuery('#'+nodeId)[0];varprops={};if(node){props['rql']=rql;props['fname']='view';props['pageid']=pageid;if(vid){props['vid']=vid;}if(extraparams){jQuery.extend(props,extraparams);}// FIXME we need to do asURL(props) manually instead of// passing `props` directly to loadxml because replacePageChunk// is sometimes called (abusively) with some extra parameters in `vid`varmode=swap?'swap':'replace';varurl=JSON_BASE_URL+asURL(props);jQuery(node).loadxhtml(url,params,'get',mode);}else{log('Node',nodeId,'not found');}}/* XXX deprecates? * fetches `url` and replaces `nodeid`'s content with the result * @param replacemode how the replacement should be done (default is 'replace') * Possible values are : * - 'replace' to replace the node's content with the generated HTML * - 'swap' to replace the node itself with the generated HTML * - 'append' to append the generated HTML to the node's content */functionloadxhtml(nodeid,url,/* ... */replacemode){jQuery('#'+nodeid).loadxhtml(url,null,'post',replacemode);}/* XXX: this function should go in edition.js but as for now, htmlReplace * references it. * * replace all textareas with fckeditors. */functionbuildWysiwygEditors(parent){jQuery('textarea').each(function(){if(this.getAttribute('cubicweb:type')=='wysiwyg'){// mark editor as instanciated, we may be called a number of times// (see postAjaxLoad)this.setAttribute('cubicweb:type','fckeditor');if(typeofFCKeditor!="undefined"){varfck=newFCKeditor(this.id);fck.Config['CustomConfigurationsPath']=fckconfigpath;fck.Config['DefaultLanguage']=fcklang;fck.BasePath="fckeditor/";fck.ReplaceTextarea();}else{log('fckeditor could not be found.');}}});}jQuery(document).ready(buildWysiwygEditors);/* * takes a list of DOM nodes and removes all empty text nodes */functionstripEmptyTextNodes(nodelist){varstripped=[];for(vari=0;i<nodelist.length;i++){varnode=nodelist[i];if(isTextNode(node)&&!node.textContent.strip()){continue;}else{stripped.push(node);}}returnstripped;}/* convenience function that returns a DOM node based on req's result. * XXX clarify the need to clone * */functiongetDomFromResponse(response){if(typeof(response)=='string'){vardoc=html2dom(response);}else{vardoc=response.documentElement;}varchildren=doc.childNodes;if(!children.length){// no child (error cases) => return the whole documentreturnjQuery(doc).clone().context;}children=stripEmptyTextNodes(children);if(children.length==1){// only one child => return itreturnjQuery(children[0]).clone().context;}// several children => wrap them in a single node and return the wrapreturnDIV(null,map(function(node){returnjQuery(node).clone().context;},children));}functionpostJSON(url,data,callback){returnjQuery.post(url,data,callback,'json');}functiongetJSON(url,data,callback){returnjQuery.get(url,data,callback,'json');}CubicWeb.provide('ajax.js');