2

I'm trying to override the document.cookie since i need to control cookie creation, but seems that getOwnPropertyDescriptor casted on document.cookie doesn't retrieve its getter and setter ( tried on chrome and firefox ). Could someone explain me this behaviour?

https://jsfiddle.net/1363ktwp/7/

var obj={};

// creating a property using document.cookie descriptors
Object.defineProperty(
    obj, 
    "oldCookie",   
    Object.getOwnPropertyDescriptor(document, "cookie")
);
    
// setting cookies succesfully
document.cookie="test1=ok;path=/;expires=365;";
document.cookie="test2=ok;path=/;expires=365;";

alert(document.cookie);

Object.defineProperty(document, "cookie", {
    get: function () {
        return obj.oldCookie;
    },
    set: function (cookie) {
        /*
            ...preliminar operations
        */
        
        obj.oldCookie = cookie;
    }
});
    
// obj.oldCookie is just a string without getter/setter
// so assignments below doesn't works correctly
document.cookie="test3=ok;path=/;expires=365;";
document.cookie="test4=ok;path=/;expires=365;";

alert(document.cookie);
Joseph
  • 1,029
  • 13
  • 26

3 Answers3

9

The reason for

Object.getOwnPropertyDescriptor(document, 'cookie');

returning undefined is the way that getOwnPropertyDescriptor works: it does not traverse the prototype chain.

A global variable document contains object actually inheriting from Document.prototype:

Document.prototype.isPrototypeOf(document) // true

and does not own a property called "cookie", the Document.prototype does:

document.hasOwnProperty('cookie'); // false
Document.prototype.hasOwnProperty('cookie'); // true

A way to retrieve the descriptor of document.cookie is to retrieve the descriptor of Document.prototype.cookie itself:

Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');

Deprecated functions called __lookupGetter__ and __lookupSetter__ do actually traverse the prototype chain and therefore, you can retrieve these methods calling it on document, and not the Document.prototype:

const cookieDescriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie');
cookieDescriptor.get === document.__lookupGetter__('cookie') // true
Marcin Wanago
  • 624
  • 7
  • 11
  • +1 since there are viable use cases for this (a self-built cookie jar to make accessing and setting cookies easier), especially if you want to prevent other scripts from interfering via the public cookie API (you'd need to delete the getter/setter from Document.prototype after retrieving them). – Robidu Mar 15 '21 at 15:44
  • Detailed and Good Answer. I tried `document.__proto__` but in vain. Seems Document -> HTMLDocument so that I cannot use `__proto__` in `Object.getOwnPropertyDescriptor(document.__proto__, 'cookie');` – Chester Fung Apr 30 '23 at 09:06
5

You can use __lookupSetter__ and __lookupGetter__ methods, but be warn that they are deprecated and not supported everywhere. They work properly in Chrome, Firefox, IE11. Don't work in IE<10. Opera provides such methods, but they seam to always return undefined. Didn't check anything else.

Here is an example:

var cookieSetterOrig = document.__lookupSetter__("cookie");
var cookieGetterOrig = document.__lookupGetter__("cookie");
Object.defineProperty(document, "cookie", {
    get: function () {
        return cookieGetterOrig.apply(document);
    },
    set: function () {
        return cookieSetterOrig.apply(document, arguments);
    },
    configurable: true
});
Vlad Shevchenko
  • 738
  • 1
  • 8
  • 19
3

Could someone explain me this behaviour?

document.cookie is a property of a host object. Host objects are frequently not true JavaScript objects (called native objects) and are neither required nor guaranteed to have the features of JavaScript objects.

I'd be truly shocked, in fact, if many or even more than one or two browsers implemented document.cookie using ES5 property getters/setters. Perhaps for some newer APIs (or perhaps not), but for one that old, there's going to be a lot of cruft about. (I'd also have to think a long time about the security ramifications...)

If they did implement it via ES5 getters/setters, it wouldn't surprise me if they made it a non-configurable property (e.g., such that you couldn't change it).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thank you for your explaination! I'm trying to solve the problem generated by EU cookie law. It requires to control all kind of cookies generated by a site , but there's no way to disable/control them without modifying the specific code that creates it ( in a context where you've a platform fullfilled by 3rd Party plugins that shouldn't be modified it becomes very hard ). It is why i was searching for a "global" solution. – Joseph Jun 06 '15 at 16:59
  • 1
    @Joseph: Yeah. The latest guidance on that, as far as I know (and I Am Not A Lawyer [and even if I were, I'm not *your* lawyer]) is that having a cookie policy and a link to it from the landing page is probably sufficient, and that combined with a simple notification banner (which the user can dismiss -- a preference you might store in a cookie, amusingly, but is better stored in `localStorage`) is plenty good enough. More: https://econsultancy.com/blog/63118-17-useful-examples-of-eu-cookie-law-compliance/ – T.J. Crowder Jun 06 '15 at 17:14