I need to log setting of document.cookie. I can not redefine cookie property just with document.cookie = {...}
So I need to get setter for document.cookie. But Object.getOwnPropertyDescriptor(document, "cookie")
returns undefined
.
UPD. While I was writing the question I found a working solution, but it uses deprecated __lookupGetter__
and __lookupSetter__
methods. Is there any solution which doesn't use obsolete API?
The standardized way of accessing getters and setters is with Object.getOwnPropertyDescriptor
, but as the name suggests, it only looks on the objects own properties (it does not look up the prototype chain). document
is an instance of HTMLDocument
, which inherits from Document
. In modern browsers the cookie
property is defined on Document.prototype
, whereas in older versions of Firefox it is defined on HTMLDocument.prototype
.
var cookieDesc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie') ||
Object.getOwnPropertyDescriptor(HTMLDocument.prototype, 'cookie');
if (cookieDesc && cookieDesc.configurable) {
Object.defineProperty(document, 'cookie', {
get: function () {
return cookieDesc.get.call(document);
},
set: function (val) {
console.log(val);
cookieDesc.set.call(document, val);
}
});
}
Ironically, in the most privacy-concerned browser Safari, the descriptor has set configurable
to false and does not contain the getter nor setter, and neither does __lookupGetter__
or __lookupSetter__
. So I haven't found a way to override document.cookie
in Safari yet (8.0.8 on OS X and iOS 9.0.2). WebKit nightly acts the same way as Safari, so it doesn't seem to get fixed anytime soon.
Update October 2019: Tested the above code in Safari 12.1.2 on MacOS Mojave, and cookieDesk
is now configurable! This means my proof of concept document.cookie
protection from 2015 might actually work now :)
While I was writing the question I found next code solves my problem:
var cookie_setter_orig = document.__lookupSetter__("cookie").bind(document);
var cookie_getter_orig = document.__lookupGetter__("cookie").bind(document);
Object.defineProperty(document, "cookie", {
get: function () {
return cookie_getter_orig();
},
set: function (val) {
console.log(val);
cookie_setter_orig(val);
}
});
But I don't like using deprecated methods, so I hope there is a better solution.