Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding an object prototype and disallowing any further overrides

Tags:

javascript

I'm trying to write a library that intercepts all XMLHttpRequest calls and do something before eventually sending out the request, by overriding its prototype, for example:

var original_open = XMLHttpRequest.prototype.open;    
XMLHttpRequest.prototype.open = function() {
    // my own override logic here before running the original function
    original_open.apply(this, arguments);
};

The problem is, I want to guarantee that when someone uses this library, it is impossible for any other code on the web page to re-override this effect.

Because otherwise, the website using this library can dynamically load another piece of JS code which simply overrides the XMLHttpRequest.prototype.open again, and the whole purpose of this library is to disallow that.

I thought about freezing the prototype using Object.freeze() right after the override, so that no other code can override my own override. The code would look something like this:

var original_open = XMLHttpRequest.prototype.open;    
XMLHttpRequest.prototype.open = function() {
    // my own override logic here before running the original function
    original_open.apply(this, arguments);
};
Object.freeze(XMLHttpRequest.prototype);

My expectation is that, if another piece of code on the same page tries to re-override my own override, it will fail because the prototype has been frozen.

My question:

  1. Is this the correct solution for this problem?
  2. Is this truly secure? (No loopholes)?
like image 724
Vlad Avatar asked Nov 14 '17 21:11

Vlad


1 Answers

Do not freeze the prototype. This will lead to developer frustration, unexplainable bugs, and no one using your library. You have no way of knowing what other libraries will modify that method, and how they will do it, which leads to you coding for an endless amount of edge cases. Stick to a best practice, and assume that developers are making wise, compatible library selections.

Due to the nature of client side code, you're going to have to assume that other professional libraries will follow best practices. If 5 libraries all modify the prototypical method using the convention you used, all 5 libraries will work together.

For example, these two overrides simply work together:

var old1 = Document.prototype.querySelector;
Document.prototype.querySelector = function(...args) {
  console.log('Override 1');
  return old1.call(this, ...args);
};

var old2 = Document.prototype.querySelector;
Document.prototype.querySelector = function(...args) {
  console.log('Override 2');
  return old2.call(this, ...args);
};

let p = document.querySelector('body');

console.log(p);
like image 138
KevBot Avatar answered Nov 20 '22 12:11

KevBot