/** * The OWASP CSRFGuard Project, BSD License * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of OWASP nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function() { /** * Code to ensure our event always gets triggered when the DOM is updated. * @param obj * @param type * @param fn * @source http://www.dustindiaz.com/rock-solid-addevent/ */ function addEvent( obj, type, fn ) { if (obj.addEventListener) { obj.addEventListener( type, fn, false ); EventCache.add(obj, type, fn); } else if (obj.attachEvent) { obj["e"+type+fn] = fn; obj[type+fn] = function() { obj["e"+type+fn]( window.event ); } obj.attachEvent( "on"+type, obj[type+fn] ); EventCache.add(obj, type, fn); } else { obj["on"+type] = obj["e"+type+fn]; } } var EventCache = function(){ var listEvents = []; return { listEvents : listEvents, add : function(node, sEventName, fHandler){ listEvents.push(arguments); }, flush : function(){ var i, item; for(i = listEvents.length - 1; i >= 0; i = i - 1){ item = listEvents[i]; if(item[0].removeEventListener){ item[0].removeEventListener(item[1], item[2], item[3]); }; if(item[1].substring(0, 2) != "on"){ item[1] = "on" + item[1]; }; if(item[0].detachEvent){ item[0].detachEvent(item[1], item[2]); }; item[0][item[1]] = null; }; } }; }(); /** string utility functions **/ String.prototype.startsWith = function(prefix) { return this.indexOf(prefix) === 0; }; String.prototype.endsWith = function(suffix) { return this.match(suffix+"$") == suffix; }; /** hook using standards based prototype **/ function hijackStandard() { XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { this.url = url; this._open.apply(this, arguments); }; XMLHttpRequest.prototype._send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function(data) { if(this.onsend != null) { this.onsend.apply(this, arguments); } this._send.apply(this, arguments); }; } /** ie does not properly support prototype - wrap completely **/ function hijackExplorer() { var _XMLHttpRequest = window.XMLHttpRequest; function alloc_XMLHttpRequest() { this.base = _XMLHttpRequest ? new _XMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); } function init_XMLHttpRequest() { return new alloc_XMLHttpRequest; } init_XMLHttpRequest.prototype = alloc_XMLHttpRequest.prototype; /** constants **/ init_XMLHttpRequest.UNSENT = 0; init_XMLHttpRequest.OPENED = 1; init_XMLHttpRequest.HEADERS_RECEIVED = 2; init_XMLHttpRequest.LOADING = 3; init_XMLHttpRequest.DONE = 4; /** properties **/ init_XMLHttpRequest.prototype.status = 0; init_XMLHttpRequest.prototype.statusText = ""; init_XMLHttpRequest.prototype.readyState = init_XMLHttpRequest.UNSENT; init_XMLHttpRequest.prototype.responseText = ""; init_XMLHttpRequest.prototype.responseXML = null; init_XMLHttpRequest.prototype.onsend = null; init_XMLHttpRequest.url = null; init_XMLHttpRequest.onreadystatechange = null; /** methods **/ init_XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { var self = this; this.url = url; this.base.onreadystatechange = function() { try { self.status = self.base.status; } catch (e) { } try { self.statusText = self.base.statusText; } catch (e) { } try { self.readyState = self.base.readyState; } catch (e) { } try { self.responseText = self.base.responseText; } catch(e) { } try { self.responseXML = self.base.responseXML; } catch(e) { } if(self.onreadystatechange != null) { self.onreadystatechange.apply(this, arguments); } } this.base.open(method, url, async, user, pass); }; init_XMLHttpRequest.prototype.send = function(data) { if(this.onsend != null) { this.onsend.apply(this, arguments); } this.base.send(data); }; init_XMLHttpRequest.prototype.abort = function() { this.base.abort(); }; init_XMLHttpRequest.prototype.getAllResponseHeaders = function() { return this.base.getAllResponseHeaders(); }; init_XMLHttpRequest.prototype.getResponseHeader = function(name) { return this.base.getResponseHeader(name); }; init_XMLHttpRequest.prototype.setRequestHeader = function(name, value) { return this.base.setRequestHeader(name, value); }; /** hook **/ window.XMLHttpRequest = init_XMLHttpRequest; } /** check if valid domain based on domainStrict **/ function isValidDomain(current, target) { var result = false; /** check exact or subdomain match **/ if(current == target) { result = true; } else if(false == false) { if(target.charAt(0) == '.') { result = current.endsWith(target); } else { result = current.endsWith('.' + target); } } return result; } /** determine if uri/url points to valid domain **/ function isValidUrl(src) { var result = false; /** parse out domain to make sure it points to our own **/ if(src.substring(0, 7) == "http://" || src.substring(0, 8) == "https://") { var token = "://"; var index = src.indexOf(token); var part = src.substring(index + token.length); var domain = ""; /** parse up to end, first slash, or anchor **/ for(var i=0; i 0) { part = url.substring(index + token.length); } else if(url.charAt(0) != '/') { part = "/" + url; } else { part = url; } /** parse up to end or query string **/ var uriContext = (index == -1); for(var i=0; i