Skip to content

Commit 6034adf

Browse files
Csrf.min.js
1 parent dd2fdae commit 6034adf

File tree

2 files changed

+212
-17
lines changed

2 files changed

+212
-17
lines changed

src/Csrf.min.js

Lines changed: 212 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,215 @@
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+
*/
27

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
4140
// We very specifically match against Internet Explorer, since they haven't
5141
// 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

Comments
 (0)