-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsample.js
323 lines (296 loc) · 9.44 KB
/
sample.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/**
* =================================================================
* Javascript code for OWASP CSRF Protector
* Task it does: Fetch csrftoken from cookie, and attach it to every
* POST request
* Allowed GET url
* -- XHR
* -- Static Forms
* -- URLS (GET only)
* -- dynamic forms
* =================================================================
*/
var CSRFP = {
CSRFP_TOKEN: 'csrfp_token',
/**
* Array of patterns of url, for which csrftoken need to be added
* In case of GET request also, provided from server
*
* @var string array
*/
checkForUrls: [],
/**
* Function to check if a certain url is allowed to perform the request
* With or without csrf token
*
* @param: string, url
*
* @return: boolean, true if csrftoken is not needed
* false if csrftoken is needed
*/
_isValidGetRequest: function(url) {
for (var i = 0; i < CSRFP.checkForUrls.length; i++) {
var match = CSRFP.checkForUrls[i].exec(url);
if (match !== null && match.length > 0) {
return false;
}
}
return true;
},
/**
* function to get Auth key from cookie And return it to requesting function
*
* @param: void
* @todo: make this more functional @priority: medium
* @return: string, csrftoken retrieved from cookie
*/
_getAuthKey: function() {
var re = new RegExp(CSRFP.CSRFP_TOKEN +"=([^;]+)(;|$)");
var RegExpArray = re.exec(document.cookie);
if (RegExpArray === null) {
return false;
}
return RegExpArray[1];
},
/**
* Function to get domain of any url
*
* @param: string, url
*
* @return: string, domain of url
*/
_getDomain: function(url) {
if (url.indexOf("http://") !== 0
&& url.indexOf("https://") !== 0)
return document.domain;
return /http(s)?:\/\/([^\/]+)/.exec(url)[2];
},
/**
* Function to create and return a hidden input element
* For stroing the CSRFP_TOKEN
*
* @param void
*
* @return input element
*/
_getInputElt: function() {
var hiddenObj = document.createElement("input");
hiddenObj.name = CSRFP.CSRFP_TOKEN;
hiddenObj.type = 'hidden'; // #todo: might need this to be not hidden, check!
// ^ @priority: custom
hiddenObj.value = CSRFP._getAuthKey();
return hiddenObj;
},
/**
* Returns absolute path for relative path
*
* @param base, base url
* @param relative, relative url
*
* @return absolute path (string)
*/
_getAbsolutePath: function(base, relative) {
var stack = base.split("/");
var parts = relative.split("/");
// remove current file name (or empty string)
// (omit if "base" is the current folder without trailing slash)
stack.pop();
for (var i = 0; i < parts.length; i++) {
if (parts[i] == ".")
continue;
if (parts[i] == "..")
stack.pop();
else
stack.push(parts[i]);
}
return stack.join("/");
},
/**
* Remove jcsrfp-token run fun and then put them back
*
* @param function
* @param reference form obj
*
* @retrun function
*/
_csrfpWrap: function(fun, obj) {
return function(event) {
// Remove CSRf token if exists
if (typeof obj[CSRFP.CSRFP_TOKEN] !== 'undefined') {
var target = obj[CSRFP.CSRFP_TOKEN];
target.parentNode.removeChild(target);
}
/**
* #todo: what if todo doesn't exist, make a case for that
* @deadline: 21/01/2014 @tags: abhinavdahiya, minhazav
* @assign: mebjas
@label: csrf, google, gsoc
* @remindon: 19/01/2014
* @priority: high
*/
// Trigger the functions
var result = fun.apply(this, [event]);
// Now append the csrfp_token back
obj.appendChild(CSRFP._getInputElt());
return result;
};
},
/**
* Initialises the CSRFProtector js script
*
* @param void
*
* @return void
*/
_init: function() {
//convert these rules received from php lib to regex objects
for (var i = 0; i < CSRFP.checkForUrls.length; i++) {
CSRFP.checkForUrls[i] = CSRFP.checkForUrls[i].replace(/\*/g, '(.*)')
.replace(/\//g, "\\/");
CSRFP.checkForUrls[i] = new RegExp(CSRFP.checkForUrls[i]);
}
}
};
//==========================================================
// Adding tokens, wrappers on window onload
//==========================================================
function csrfprotector_init() {
// Call the init funcion
CSRFP._init();
//==================================================================
// Adding csrftoken to request resulting from <form> submissions
// Add for each POST, while for mentioned GET request
//==================================================================
for(var i = 0; i < document.forms.length; i++) {
document.forms[i].addEventListener("submit", function(event) {
if (typeof event.target[CSRFP.CSRFP_TOKEN] === 'undefined') {
event.target.appendChild(CSRFP._getInputElt());
} else {
//modify token to latest value
event.target[CSRFP.CSRFP_TOKEN].value = CSRFP._getAuthKey();
}
});
}
/**
* Add wrapper for HTMLFormElements addEventListener so that any further
* addEventListens won't have trouble with CSRF token
*/
HTMLFormElement.prototype.addEventListener_ = HTMLFormElement.prototype.addEventListener;
HTMLFormElement.prototype.addEventListener = function(eventType, fun, bubble) {
if (eventType === 'submit') {
var wrapped = CSRFP._csrfpWrap(fun, this);
this.addEventListener_(eventType, wrapped, bubble);
} else {
this.addEventListener_(eventType, fun, bubble);
}
}
/**
* Add wrapper for IE's attachEvent
*/
if (typeof HTMLFormElement.prototype.attachEvent !== 'undefined') {
HTMLFormElement.prototype.attachEvent_ = HTMLFormElement.prototype.attachEvent;
HTMLFormElement.prototype.attachEvent = function(eventType, fun) {
if (eventType === 'submit') {
var wrapped = CSRFP._csrfpWrap(fun, this);
this.attachEvent_(eventType, wrapped);
} else {
this.attachEvent_(eventType, fun);
}
}
}
//==================================================================
// Wrapper for XMLHttpRequest & ActiveXObject (for IE 6 & below)
// Set X-No-CSRF to true before sending if request method is
//==================================================================
/**
* Wrapper to XHR open method
* Add a property method to XMLHttpRequst class
* @param: all parameters to XHR open method
* @return: object returned by default, XHR open method
*/
function new_open(method, url, async, username, password) {
this.method = method;
var isAbsolute = (url.indexOf("./") === -1) ? true : false;
if (!isAbsolute) {
var base = location.protocol +'//' +location.host
+ location.pathname;
url = CSRFP._getAbsolutePath(base, url);
}
if (method.toLowerCase() === 'get'
&& !CSRFP._isValidGetRequest(url)) {
//modify the url
if (url.indexOf('?') === -1) {
url += "?" +CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey();
} else {
url += "&" +CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey();
}
}
return this.old_open(method, url, async, username, password);
}
/**
* Wrapper to XHR send method
* Add query paramter to XHR object
*
* @param: all parameters to XHR send method
*
* @return: object returned by default, XHR send method
*/
function new_send(data) {
if (this.method.toLowerCase() === 'post') {
if (data !== "") {
data += "&";
} else {
data = "";
}
data += CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey();
}
return this.old_send(data);
}
if (window.XMLHttpRequest) {
// Wrapping
XMLHttpRequest.prototype.old_send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.old_open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = new_open;
XMLHttpRequest.prototype.send = new_send;
}
if (typeof ActiveXObject !== 'undefined') {
ActiveXObject.prototype.old_send = ActiveXObject.prototype.send;
ActiveXObject.prototype.old_open = ActiveXObject.prototype.open;
ActiveXObject.prototype.open = new_open;
ActiveXObject.prototype.send = new_send;
}
//==================================================================
// Rewrite existing urls ( Attach CSRF token )
// Rules:
// Rewrite those urls which matches the regex sent by Server
// Ingore cross origin urls & internal links (one with hashtags)
// Append the token to those url already containig GET query parameter(s)
// Add the token to those which does not contain GET query parameter(s)
//==================================================================
for (var i = 0; i < document.links.length; i++) {
document.links[i].addEventListener("mousedown", function(event) {
var urlDisect = event.target.href.split('#');
var url = urlDisect[0];
var hash = urlDisect[1];
if(CSRFP._getDomain(url).indexOf(document.domain) === -1
|| CSRFP._isValidGetRequest(url)) {
//cross origin or not to be protected by rules -- ignore
return;
}
if (url.indexOf('?') !== -1) {
if(url.indexOf(CSRFP.CSRFP_TOKEN) === -1) {
url += "&" +CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey();
} else {
url = url.replace(new RegExp(CSRFP.CSRFP_TOKEN +"=.*?(&|$)", 'g'),
CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey() + "$1");
}
} else {
url += "?" +CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey();
}
event.target.href = url;
if (typeof hash !== 'undefined') {
event.target.href += '#' +hash;
}
});
}
}