|
1 | | -'use strict'; |
| 1 | +/** |
| 2 | + * @file |
| 3 | + * |
| 4 | + * Rewrites XMLHttpRequest to automatically send CSRF token with it. In theory |
| 5 | + * plays nice with other JavaScript libraries, needs testing though. |
| 6 | + */ |
2 | 7 |
|
3 | | -function _typeof(o){"@babel/helpers - typeof";return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o},_typeof(o)}// Sets things up for Mozilla/Opera/nice browsers |
| 8 | +// Here are the basic overloaded method definitions |
| 9 | +// The wrapper must be set BEFORE onreadystatechange is written to, since |
| 10 | +// a bug in ActiveXObject prevents us from properly testing for it. |
| 11 | +CsrfMagic = function (real) { |
| 12 | + // try to make it ourselves, if you didn't pass it |
| 13 | + if (!real) |
| 14 | + try { |
| 15 | + real = new XMLHttpRequest(); |
| 16 | + } catch (e) {} |
| 17 | + if (!real) |
| 18 | + try { |
| 19 | + real = new ActiveXObject('Msxml2.XMLHTTP'); |
| 20 | + } catch (e) {} |
| 21 | + if (!real) |
| 22 | + try { |
| 23 | + real = new ActiveXObject('Microsoft.XMLHTTP'); |
| 24 | + } catch (e) {} |
| 25 | + if (!real) |
| 26 | + try { |
| 27 | + real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); |
| 28 | + } catch (e) {} |
| 29 | + this.csrf = real; |
| 30 | + // properties |
| 31 | + var csrfMagic = this; |
| 32 | + real.onreadystatechange = function () { |
| 33 | + csrfMagic._updateProps(); |
| 34 | + return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null; |
| 35 | + }; |
| 36 | + csrfMagic._updateProps(); |
| 37 | +}; |
| 38 | + |
| 39 | +CsrfMagic.prototype = { |
| 40 | + open: function (method, url, async, username, password) { |
| 41 | + if (method == 'POST') this.csrf_isPost = true; |
| 42 | + this.csrf_url = url; |
| 43 | + // deal with Opera bug, thanks jQuery |
| 44 | + if (username) return this.csrf_open(method, url, async, username, password); |
| 45 | + else return this.csrf_open(method, url, async); |
| 46 | + }, |
| 47 | + csrf_open: function (method, url, async, username, password) { |
| 48 | + if (username) return this.csrf.open(method, url, async, username, password); |
| 49 | + else return this.csrf.open(method, url, async); |
| 50 | + }, |
| 51 | + |
| 52 | + send: function (data) { |
| 53 | + let url = null; |
| 54 | + try { |
| 55 | + url = new URL(this.csrf_url); |
| 56 | + } catch (e) { |
| 57 | + //for internal urls there could be no domain part |
| 58 | + //in that case it's not a valid url |
| 59 | + } |
| 60 | + //don't add token to external requests |
| 61 | + if (url !== null && typeof csrfMagicDomain !== 'undefined' && url.host !== csrfMagicDomain) { |
| 62 | + return this.csrf_send(data); |
| 63 | + } |
| 64 | + |
| 65 | + if (!this.csrf_isPost) return this.csrf_send(data); |
| 66 | + delete this.csrf_isPost; |
| 67 | + if (data instanceof FormData) { |
| 68 | + data.append(csrfMagicName, csrfMagicToken); |
| 69 | + return this.csrf_send(data); |
| 70 | + } else { |
| 71 | + return this.csrf_send(csrfMagicName + '=' + csrfMagicToken + '&' + data); |
| 72 | + } |
| 73 | + }, |
| 74 | + csrf_send: function (data) { |
| 75 | + return this.csrf.send(data); |
| 76 | + }, |
| 77 | + |
| 78 | + setRequestHeader: function (header, value) { |
| 79 | + // We have to auto-set this at the end, since we don't know how long the |
| 80 | + // nonce is when added to the data. |
| 81 | + if (this.csrf_isPost && header == 'Content-length') { |
| 82 | + this.csrf_purportedLength = value; |
| 83 | + return; |
| 84 | + } |
| 85 | + return this.csrf_setRequestHeader(header, value); |
| 86 | + }, |
| 87 | + csrf_setRequestHeader: function (header, value) { |
| 88 | + return this.csrf.setRequestHeader(header, value); |
| 89 | + }, |
| 90 | + |
| 91 | + abort: function () { |
| 92 | + return this.csrf.abort(); |
| 93 | + }, |
| 94 | + getAllResponseHeaders: function () { |
| 95 | + return this.csrf.getAllResponseHeaders(); |
| 96 | + }, |
| 97 | + getResponseHeader: function (header) { |
| 98 | + return this.csrf.getResponseHeader(header); |
| 99 | + } // , |
| 100 | +}; |
| 101 | + |
| 102 | +// proprietary |
| 103 | +CsrfMagic.prototype._updateProps = function () { |
| 104 | + this.readyState = this.csrf.readyState; |
| 105 | + if (this.readyState == 4) { |
| 106 | + this.responseText = this.csrf.responseText; |
| 107 | + this.responseXML = this.csrf.responseXML; |
| 108 | + this.status = this.csrf.status; |
| 109 | + this.statusText = this.csrf.statusText; |
| 110 | + } |
| 111 | +}; |
| 112 | +CsrfMagic.process = function (base) { |
| 113 | + if (typeof base == 'object') { |
| 114 | + base[csrfMagicName] = csrfMagicToken; |
| 115 | + return base; |
| 116 | + } |
| 117 | + var prepend = csrfMagicName + '=' + csrfMagicToken; |
| 118 | + if (base) return prepend + '&' + base; |
| 119 | + return prepend; |
| 120 | +}; |
| 121 | +// callback function for when everything on the page has loaded |
| 122 | +CsrfMagic.end = function () { |
| 123 | + // This rewrites forms AGAIN, so in case buffering didn't work this |
| 124 | + // certainly will. |
| 125 | + forms = document.getElementsByTagName('form'); |
| 126 | + for (var i = 0; i < forms.length; i++) { |
| 127 | + form = forms[i]; |
| 128 | + var method = form.getAttribute('method'); |
| 129 | + if (method && method.toUpperCase() !== 'POST') continue; |
| 130 | + if (form.elements[csrfMagicName]) continue; |
| 131 | + var input = document.createElement('input'); |
| 132 | + input.setAttribute('name', csrfMagicName); |
| 133 | + input.setAttribute('value', csrfMagicToken); |
| 134 | + input.setAttribute('type', 'hidden'); |
| 135 | + form.appendChild(input); |
| 136 | + } |
| 137 | +}; |
| 138 | + |
| 139 | +// Sets things up for Mozilla/Opera/nice browsers |
4 | 140 | // We very specifically match against Internet Explorer, since they haven't |
5 | 141 | // implemented prototypes correctly yet. |
6 | | -if(CsrfMagic=function CsrfMagic(real){// try to make it ourselves, if you didn't pass it |
7 | | -if(!real)try{real=new XMLHttpRequest;}catch(e){}if(!real)try{real=new ActiveXObject("Msxml2.XMLHTTP");}catch(e){}if(!real)try{real=new ActiveXObject("Microsoft.XMLHTTP");}catch(e){}if(!real)try{real=new ActiveXObject("Msxml2.XMLHTTP.4.0");}catch(e){}this.csrf=real;// properties |
8 | | -var csrfMagic=this;real.onreadystatechange=function(){return csrfMagic._updateProps(),csrfMagic.onreadystatechange?csrfMagic.onreadystatechange():null},csrfMagic._updateProps();},CsrfMagic.prototype={open:function open(method,url,async,username,password){// deal with Opera bug, thanks jQuery |
9 | | -return "POST"==method&&(this.csrf_isPost=!0),this.csrf_url=url,username?this.csrf_open(method,url,async,username,password):this.csrf_open(method,url,async)},csrf_open:function csrf_open(method,url,async,username,password){return username?this.csrf.open(method,url,async,username,password):this.csrf.open(method,url,async)},send:function send(data){var url=null;try{url=new URL(this.csrf_url);}catch(e){//for internal urls there could be no domain part |
10 | | -//in that case it's not a valid url |
11 | | -}//don't add token to external requests |
12 | | -return null!==url&&"undefined"!=typeof csrfMagicDomain&&url.host!==csrfMagicDomain?this.csrf_send(data):this.csrf_isPost?(delete this.csrf_isPost,data instanceof FormData?(data.append(csrfMagicName,csrfMagicToken),this.csrf_send(data)):this.csrf_send(csrfMagicName+"="+csrfMagicToken+"&"+data)):this.csrf_send(data)},csrf_send:function csrf_send(data){return this.csrf.send(data)},setRequestHeader:function setRequestHeader(header,value){// We have to auto-set this at the end, since we don't know how long the |
13 | | -// nonce is when added to the data. |
14 | | -return this.csrf_isPost&&"Content-length"==header?void(this.csrf_purportedLength=value):this.csrf_setRequestHeader(header,value)},csrf_setRequestHeader:function csrf_setRequestHeader(header,value){return this.csrf.setRequestHeader(header,value)},abort:function abort(){return this.csrf.abort()},getAllResponseHeaders:function getAllResponseHeaders(){return this.csrf.getAllResponseHeaders()},getResponseHeader:function getResponseHeader(header){return this.csrf.getResponseHeader(header)}// , |
15 | | -},CsrfMagic.prototype._updateProps=function(){this.readyState=this.csrf.readyState,4==this.readyState&&(this.responseText=this.csrf.responseText,this.responseXML=this.csrf.responseXML,this.status=this.csrf.status,this.statusText=this.csrf.statusText);},CsrfMagic.process=function(base){if("object"==_typeof(base))return base[csrfMagicName]=csrfMagicToken,base;var prepend=csrfMagicName+"="+csrfMagicToken;return base?prepend+"&"+base:prepend},CsrfMagic.end=function(){forms=document.getElementsByTagName("form");for(var i=0;i<forms.length;i++){form=forms[i];var method=form.getAttribute("method");if(!(method&&"POST"!==method.toUpperCase())&&!form.elements[csrfMagicName]){var input=document.createElement("input");input.setAttribute("name",csrfMagicName),input.setAttribute("value",csrfMagicToken),input.setAttribute("type","hidden"),form.appendChild(input);}}},window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&!0){var x=XMLHttpRequest.prototype,c=CsrfMagic.prototype;// Save the original functions |
16 | | -// Notice that CsrfMagic is itself an instantiatable object, but only |
17 | | -// open, send and setRequestHeader are necessary as decorators. |
18 | | -x.csrf_open=x.open,x.csrf_send=x.send,x.csrf_setRequestHeader=x.setRequestHeader,x.open=c.open,x.send=c.send,x.setRequestHeader=c.setRequestHeader;}else window.jQuery&&(jQuery.csrf_ajax=jQuery.ajax,jQuery.ajax=function(s){return s.type&&"POST"==s.type.toUpperCase()&&(s=jQuery.extend(!0,s,jQuery.extend(!0,{},jQuery.ajaxSettings,s)),s.data&&s.processData&&"string"!=typeof s.data&&(s.data=jQuery.param(s.data)),s.data=CsrfMagic.process(s.data)),jQuery.csrf_ajax(s)}),window.Prototype&&(Ajax.csrf_getTransport=Ajax.getTransport,Ajax.getTransport=function(){return new CsrfMagic(Ajax.csrf_getTransport())}),window.MooTools&&(Browser.csrf_Request=Browser.Request,Browser.Request=function(){return new CsrfMagic(Browser.csrf_Request())}),window.YAHOO&&(YAHOO.util.Connect.csrf_createXhrObject=YAHOO.util.Connect.createXhrObject,YAHOO.util.Connect.createXhrObject=function(transaction){return obj=YAHOO.util.Connect.csrf_createXhrObject(transaction),obj.conn=new CsrfMagic(obj.conn),obj}),window.Ext&&(Ext.lib.Ajax.csrf_createXhrObject=Ext.lib.Ajax.createXhrObject,Ext.lib.Ajax.createXhrObject=function(transaction){return obj=Ext.lib.Ajax.csrf_createXhrObject(transaction),obj.conn=new CsrfMagic(obj.conn),obj}),window.dojo&&(dojo.csrf__xhrObj=dojo._xhrObj,dojo._xhrObj=function(){return new CsrfMagic(dojo.csrf__xhrObj())}); |
19 | | -//# sourceMappingURL=Csrf.min.js.map |
| 142 | +if (window.XMLHttpRequest && window.XMLHttpRequest.prototype && '\v' != 'v') { |
| 143 | + var x = XMLHttpRequest.prototype; |
| 144 | + var c = CsrfMagic.prototype; |
| 145 | + |
| 146 | + // Save the original functions |
| 147 | + x.csrf_open = x.open; |
| 148 | + x.csrf_send = x.send; |
| 149 | + x.csrf_setRequestHeader = x.setRequestHeader; |
| 150 | + |
| 151 | + // Notice that CsrfMagic is itself an instantiatable object, but only |
| 152 | + // open, send and setRequestHeader are necessary as decorators. |
| 153 | + x.open = c.open; |
| 154 | + x.send = c.send; |
| 155 | + x.setRequestHeader = c.setRequestHeader; |
| 156 | +} else { |
| 157 | + // The only way we can do this is by modifying a library you have been |
| 158 | + // using. We support YUI, script.aculo.us, prototype, MooTools, |
| 159 | + // jQuery, Ext and Dojo. |
| 160 | + if (window.jQuery) { |
| 161 | + // jQuery didn't implement a new XMLHttpRequest function, so we have |
| 162 | + // to do this the hard way. |
| 163 | + jQuery.csrf_ajax = jQuery.ajax; |
| 164 | + jQuery.ajax = function (s) { |
| 165 | + if (s.type && s.type.toUpperCase() == 'POST') { |
| 166 | + s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s)); |
| 167 | + if (s.data && s.processData && typeof s.data != 'string') { |
| 168 | + s.data = jQuery.param(s.data); |
| 169 | + } |
| 170 | + s.data = CsrfMagic.process(s.data); |
| 171 | + } |
| 172 | + return jQuery.csrf_ajax(s); |
| 173 | + }; |
| 174 | + } |
| 175 | + if (window.Prototype) { |
| 176 | + // This works for script.aculo.us too |
| 177 | + Ajax.csrf_getTransport = Ajax.getTransport; |
| 178 | + Ajax.getTransport = function () { |
| 179 | + return new CsrfMagic(Ajax.csrf_getTransport()); |
| 180 | + }; |
| 181 | + } |
| 182 | + if (window.MooTools) { |
| 183 | + Browser.csrf_Request = Browser.Request; |
| 184 | + Browser.Request = function () { |
| 185 | + return new CsrfMagic(Browser.csrf_Request()); |
| 186 | + }; |
| 187 | + } |
| 188 | + if (window.YAHOO) { |
| 189 | + // old YUI API |
| 190 | + YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject; |
| 191 | + YAHOO.util.Connect.createXhrObject = function (transaction) { |
| 192 | + obj = YAHOO.util.Connect.csrf_createXhrObject(transaction); |
| 193 | + obj.conn = new CsrfMagic(obj.conn); |
| 194 | + return obj; |
| 195 | + }; |
| 196 | + } |
| 197 | + if (window.Ext) { |
| 198 | + // Ext can use other js libraries as loaders, so it has to come last |
| 199 | + // Ext's implementation is pretty identical to Yahoo's, but we duplicate |
| 200 | + // it for comprehensiveness's sake. |
| 201 | + Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject; |
| 202 | + Ext.lib.Ajax.createXhrObject = function (transaction) { |
| 203 | + obj = Ext.lib.Ajax.csrf_createXhrObject(transaction); |
| 204 | + obj.conn = new CsrfMagic(obj.conn); |
| 205 | + return obj; |
| 206 | + }; |
| 207 | + } |
| 208 | + if (window.dojo) { |
| 209 | + // NOTE: this doesn't work with latest dojo |
| 210 | + dojo.csrf__xhrObj = dojo._xhrObj; |
| 211 | + dojo._xhrObj = function () { |
| 212 | + return new CsrfMagic(dojo.csrf__xhrObj()); |
| 213 | + }; |
| 214 | + } |
| 215 | +} |
0 commit comments