(function() { // don't leak XSSTripwire into global ns

  /*
  Assumptions:
    - we need to run first, before any other attacker script
    - we can't prevent tripwire from being detected (e.g. by side effects)
  Todo:
    - a lot more in lockdown
    - protect XHR
  */
  var XSSTripwire = new Object();

  XSSTripwire.report = function() {
    // Notify server
    var notify = XSSTripwire.newXHR();

    // Create a results string to send back
    var results;
    try {
      results = "HTML=" + encodeURIComponent(document.body.outerHTML);
    } catch (e) {} // we don't always have document.body

    notify.open("POST", XSSTripwire.ReportURL, true);
    notify.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    notify.send(results);
  }

  XSSTripwire.lockdown = function(obj, name) {
    if (Object.defineProperty) {
      Object.defineProperty(obj, name, {
        configurable: false
      })
    }
  }

  XSSTripwire.newXHR = function() {
    var xmlreq = false;
    if (window.XMLHttpRequest) {
      xmlreq = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      // Try ActiveX
      try {
        xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e1) {
        // first method failed
        try {
          xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e2) {
          // both methods failed
        }
      }
    }
    return xmlreq;
  };

  XSSTripwire.proxy = function(obj, name, report_function_name, exec_original) {
    var proxy = obj[name];
    obj[name] = function() {
      // URL of the page to notify, in the event of a detected XSS event:
      XSSTripwire.ReportURL = "xss-tripwire-report?function=" + encodeURIComponent(report_function_name);

      XSSTripwire.report();

      if (exec_original) {
        return proxy.apply(this, arguments);
      }
    };
    XSSTripwire.lockdown(obj, name);
  };

  XSSTripwire.proxy(window, 'alert', 'window.alert', true);
  XSSTripwire.proxy(window, 'confirm', 'window.confirm', true);
  XSSTripwire.proxy(window, 'prompt', 'window.prompt', true);
  XSSTripwire.proxy(window, 'unescape', 'unescape', true);
  XSSTripwire.proxy(document, 'write', 'document.write', true);
  XSSTripwire.proxy(String, 'fromCharCode', 'String.fromCharCode', true);

})();