1 |
53a37558
|
Ermal
|
/**
|
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 |
|
|
*/
|
7 |
|
|
|
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) try { real = new XMLHttpRequest; } catch (e) {;}
|
14 |
|
|
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) {;}
|
15 |
|
|
if (!real) try { real = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {;}
|
16 |
|
|
if (!real) try { real = new ActiveXObject('Msxml2.XMLHTTP.4.0'); } catch (e) {;}
|
17 |
|
|
this.csrf = real;
|
18 |
|
|
// properties
|
19 |
|
|
var csrfMagic = this;
|
20 |
|
|
real.onreadystatechange = function() {
|
21 |
|
|
csrfMagic._updateProps();
|
22 |
|
|
return csrfMagic.onreadystatechange ? csrfMagic.onreadystatechange() : null;
|
23 |
|
|
};
|
24 |
|
|
csrfMagic._updateProps();
|
25 |
|
|
}
|
26 |
|
|
|
27 |
|
|
CsrfMagic.prototype = {
|
28 |
|
|
|
29 |
|
|
open: function(method, url, async, username, password) {
|
30 |
|
|
if (method == 'POST') this.csrf_isPost = true;
|
31 |
|
|
// deal with Opera bug, thanks jQuery
|
32 |
|
|
if (username) return this.csrf_open(method, url, async, username, password);
|
33 |
|
|
else return this.csrf_open(method, url, async);
|
34 |
|
|
},
|
35 |
|
|
csrf_open: function(method, url, async, username, password) {
|
36 |
|
|
if (username) return this.csrf.open(method, url, async, username, password);
|
37 |
|
|
else return this.csrf.open(method, url, async);
|
38 |
|
|
},
|
39 |
|
|
|
40 |
|
|
send: function(data) {
|
41 |
|
|
if (!this.csrf_isPost) return this.csrf_send(data);
|
42 |
|
|
prepend = csrfMagicName + '=' + csrfMagicToken + '&';
|
43 |
dc668baa
|
Renato Botelho
|
// XXX: Removed to eliminate 'Refused to set unsafe header "Content-length" ' errors in modern browsers
|
44 |
|
|
// if (this.csrf_purportedLength === undefined) {
|
45 |
|
|
// this.csrf_setRequestHeader("Content-length", this.csrf_purportedLength + prepend.length);
|
46 |
|
|
// delete this.csrf_purportedLength;
|
47 |
|
|
// }
|
48 |
53a37558
|
Ermal
|
delete this.csrf_isPost;
|
49 |
|
|
return this.csrf_send(prepend + data);
|
50 |
|
|
},
|
51 |
|
|
csrf_send: function(data) {
|
52 |
|
|
return this.csrf.send(data);
|
53 |
|
|
},
|
54 |
|
|
|
55 |
|
|
setRequestHeader: function(header, value) {
|
56 |
|
|
// We have to auto-set this at the end, since we don't know how long the
|
57 |
|
|
// nonce is when added to the data.
|
58 |
|
|
if (this.csrf_isPost && header == "Content-length") {
|
59 |
|
|
this.csrf_purportedLength = value;
|
60 |
|
|
return;
|
61 |
|
|
}
|
62 |
|
|
return this.csrf_setRequestHeader(header, value);
|
63 |
|
|
},
|
64 |
|
|
csrf_setRequestHeader: function(header, value) {
|
65 |
|
|
return this.csrf.setRequestHeader(header, value);
|
66 |
|
|
},
|
67 |
|
|
|
68 |
|
|
abort: function() {
|
69 |
|
|
return this.csrf.abort();
|
70 |
|
|
},
|
71 |
|
|
getAllResponseHeaders: function() {
|
72 |
|
|
return this.csrf.getAllResponseHeaders();
|
73 |
|
|
},
|
74 |
|
|
getResponseHeader: function(header) {
|
75 |
|
|
return this.csrf.getResponseHeader(header);
|
76 |
|
|
} // ,
|
77 |
|
|
}
|
78 |
|
|
|
79 |
|
|
// proprietary
|
80 |
|
|
CsrfMagic.prototype._updateProps = function() {
|
81 |
|
|
this.readyState = this.csrf.readyState;
|
82 |
|
|
if (this.readyState == 4) {
|
83 |
|
|
this.responseText = this.csrf.responseText;
|
84 |
|
|
this.responseXML = this.csrf.responseXML;
|
85 |
|
|
this.status = this.csrf.status;
|
86 |
|
|
this.statusText = this.csrf.statusText;
|
87 |
|
|
}
|
88 |
|
|
}
|
89 |
|
|
CsrfMagic.process = function(base) {
|
90 |
dc668baa
|
Renato Botelho
|
if(typeof base == 'object') {
|
91 |
|
|
base[csrfMagicName] = csrfMagicToken;
|
92 |
|
|
return base;
|
93 |
|
|
}
|
94 |
53a37558
|
Ermal
|
var prepend = csrfMagicName + '=' + csrfMagicToken;
|
95 |
|
|
if (base) return prepend + '&' + base;
|
96 |
|
|
return prepend;
|
97 |
|
|
}
|
98 |
|
|
// callback function for when everything on the page has loaded
|
99 |
|
|
CsrfMagic.end = function() {
|
100 |
|
|
// This rewrites forms AGAIN, so in case buffering didn't work this
|
101 |
|
|
// certainly will.
|
102 |
|
|
forms = document.getElementsByTagName('form');
|
103 |
|
|
for (var i = 0; i < forms.length; i++) {
|
104 |
|
|
form = forms[i];
|
105 |
|
|
if (form.method.toUpperCase() !== 'POST') continue;
|
106 |
|
|
if (form.elements[csrfMagicName]) continue;
|
107 |
|
|
var input = document.createElement('input');
|
108 |
|
|
input.setAttribute('name', csrfMagicName);
|
109 |
|
|
input.setAttribute('value', csrfMagicToken);
|
110 |
|
|
input.setAttribute('type', 'hidden');
|
111 |
|
|
form.appendChild(input);
|
112 |
|
|
}
|
113 |
|
|
}
|
114 |
|
|
|
115 |
|
|
// Sets things up for Mozilla/Opera/nice browsers
|
116 |
fcf53c1e
|
jim-p
|
// We very specifically match against Internet Explorer, since they haven't
|
117 |
|
|
// implemented prototypes correctly yet.
|
118 |
8462bfdc
|
Erik Fonnesbeck
|
if (window.XMLHttpRequest && window.XMLHttpRequest.prototype && '\v' != 'v') {
|
119 |
53a37558
|
Ermal
|
var x = XMLHttpRequest.prototype;
|
120 |
|
|
var c = CsrfMagic.prototype;
|
121 |
|
|
|
122 |
|
|
// Save the original functions
|
123 |
|
|
x.csrf_open = x.open;
|
124 |
|
|
x.csrf_send = x.send;
|
125 |
|
|
x.csrf_setRequestHeader = x.setRequestHeader;
|
126 |
|
|
|
127 |
|
|
// Notice that CsrfMagic is itself an instantiatable object, but only
|
128 |
|
|
// open, send and setRequestHeader are necessary as decorators.
|
129 |
|
|
x.open = c.open;
|
130 |
|
|
x.send = c.send;
|
131 |
|
|
x.setRequestHeader = c.setRequestHeader;
|
132 |
|
|
} else {
|
133 |
|
|
// The only way we can do this is by modifying a library you have been
|
134 |
|
|
// using. We support YUI, script.aculo.us, prototype, MooTools,
|
135 |
|
|
// jQuery, Ext and Dojo.
|
136 |
|
|
if (window.jQuery) {
|
137 |
|
|
// jQuery didn't implement a new XMLHttpRequest function, so we have
|
138 |
|
|
// to do this the hard way.
|
139 |
|
|
jQuery.csrf_ajax = jQuery.ajax;
|
140 |
|
|
jQuery.ajax = function( s ) {
|
141 |
|
|
if (s.type && s.type.toUpperCase() == 'POST') {
|
142 |
|
|
s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
|
143 |
|
|
if ( s.data && s.processData && typeof s.data != "string" ) {
|
144 |
|
|
s.data = jQuery.param(s.data);
|
145 |
|
|
}
|
146 |
|
|
s.data = CsrfMagic.process(s.data);
|
147 |
|
|
}
|
148 |
|
|
return jQuery.csrf_ajax( s );
|
149 |
|
|
}
|
150 |
29732bc3
|
Renato Botelho
|
}
|
151 |
|
|
if (window.Prototype) {
|
152 |
53a37558
|
Ermal
|
// This works for script.aculo.us too
|
153 |
|
|
Ajax.csrf_getTransport = Ajax.getTransport;
|
154 |
|
|
Ajax.getTransport = function() {
|
155 |
|
|
return new CsrfMagic(Ajax.csrf_getTransport());
|
156 |
|
|
}
|
157 |
29732bc3
|
Renato Botelho
|
}
|
158 |
|
|
if (window.MooTools) {
|
159 |
53a37558
|
Ermal
|
Browser.csrf_Request = Browser.Request;
|
160 |
|
|
Browser.Request = function () {
|
161 |
|
|
return new CsrfMagic(Browser.csrf_Request());
|
162 |
|
|
}
|
163 |
29732bc3
|
Renato Botelho
|
}
|
164 |
|
|
if (window.YAHOO) {
|
165 |
|
|
// old YUI API
|
166 |
53a37558
|
Ermal
|
YAHOO.util.Connect.csrf_createXhrObject = YAHOO.util.Connect.createXhrObject;
|
167 |
|
|
YAHOO.util.Connect.createXhrObject = function (transaction) {
|
168 |
|
|
obj = YAHOO.util.Connect.csrf_createXhrObject(transaction);
|
169 |
|
|
obj.conn = new CsrfMagic(obj.conn);
|
170 |
|
|
return obj;
|
171 |
|
|
}
|
172 |
29732bc3
|
Renato Botelho
|
}
|
173 |
|
|
if (window.Ext) {
|
174 |
53a37558
|
Ermal
|
// Ext can use other js libraries as loaders, so it has to come last
|
175 |
|
|
// Ext's implementation is pretty identical to Yahoo's, but we duplicate
|
176 |
|
|
// it for comprehensiveness's sake.
|
177 |
|
|
Ext.lib.Ajax.csrf_createXhrObject = Ext.lib.Ajax.createXhrObject;
|
178 |
|
|
Ext.lib.Ajax.createXhrObject = function (transaction) {
|
179 |
|
|
obj = Ext.lib.Ajax.csrf_createXhrObject(transaction);
|
180 |
|
|
obj.conn = new CsrfMagic(obj.conn);
|
181 |
|
|
return obj;
|
182 |
|
|
}
|
183 |
29732bc3
|
Renato Botelho
|
}
|
184 |
|
|
if (window.dojo) {
|
185 |
|
|
// NOTE: this doesn't work with latest dojo
|
186 |
53a37558
|
Ermal
|
dojo.csrf__xhrObj = dojo._xhrObj;
|
187 |
|
|
dojo._xhrObj = function () {
|
188 |
|
|
return new CsrfMagic(dojo.csrf__xhrObj());
|
189 |
|
|
}
|
190 |
|
|
}
|
191 |
|
|
}
|