6

I have a Chrome extension (source provided below) that is getting caught with a race condition. I need some injected JavaScript to run before all other JavaScript on a web page.

The source code of a simple example of what I'm trying to do is here: https://github.com/nddipiazza/oogi

It is attempting to add a namespace to all cookie names that will actually be persisted as cookies, but at the same time remove those namespaces from the cookies that are in use.

So let's say normally without the extension you would have 2 cookies that are saved after accessing a site:

JSESSIONID
lastVisit

This extension would save them as:

oogi$JSESSIONID
oogi$lastVisit

There are basically two major parts to the extension.

The problem here is that in order for this to work, I need the javascript cookie header intercepts in inject.js to absolutely always be loaded before any other javascript. But it doesn't.

Example: Cookies in inline javascript such as:

<body>
<H2>Cookies from Inline JavaScript</H2>
<script>
    console.log("Inline javascript is executed.");
    document.write(listCookies());
</script>
</body>

Will already load prior to the inject cookie interceptor being loaded. You can tell from the console log will read in this order:

Inline javascript is executed.
cookie get/set injector completed

Is there a way to fix this inject race condition? I want to allow a chrome extension to force a javascript to be run prior to doing any javascript on a page.

ZiGaelle
  • 744
  • 1
  • 9
  • 21
Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152
  • It's not clear how you set the cookies currently but I think the solution is rather simple: use chrome.webRequest.onHeadersReceived. – wOxxOm Jun 21 '18 at 04:39
  • let me take some time and add some snippets to demonstrate what i'm doing now from the extension JS. i will be back with this shortly. – Nicholas DiPiazza Jun 21 '18 at 15:36
  • @wOxxOm i provided a ton of detail to the question. hopefully that helps us get to the bottom of this. also adding a bounty – Nicholas DiPiazza Jun 23 '18 at 05:50
  • Sounds like https://crbug.com/634381. Try running your scripts using methods 2-3 from [here](https://stackoverflow.com/a/9517879) – wOxxOm Jun 23 '18 at 05:56
  • Yep. worked like a charm. can you go ahead and make that comment an answer? it might help others and i can award you bounty that way – Nicholas DiPiazza Jun 23 '18 at 06:07
  • 2
    I'm too lazy. Go ahead and add an answer with the actual code. – wOxxOm Jun 23 '18 at 06:16
  • Done. also created a related question you probably will know how to answer https://stackoverflow.com/questions/51003814/how-to-intercept-local-storage-in-a-chrome-extension – Nicholas DiPiazza Jun 23 '18 at 18:08

1 Answers1

6

Thanks to the comments on this ticket, the solution in my case was Method 2 from this answer: https://stackoverflow.com/a/9517879

Special thanks to https://stackoverflow.com/users/3959875/woxxom

Here is a link to the finished solution:

https://github.com/nddipiazza/oogi/commit/64e1ef8dc3abfb32fec2db5fb67891a29cfe12ea

The important part of the code that makes the difference is here

var actualCode = `var cookieGetter = document.__lookupGetter__("cookie").bind(document);
var cookieSetter = document.__lookupSetter__("cookie").bind(document);
var getPrefix = function() {
    return "oogi$"
};
var processCookieStr = function(cookiesStr) {
    var prefix = getPrefix();
    var cookieStrList = cookiesStr.split('; ');
    var newStrList = [];
    cookieStrList.forEach(function(cookieStr){
        if (cookieStr.indexOf(prefix)==0) {
            newStrList.push(cookieStr.substring(prefix.length, cookieStr.length));
        }
    });
    return newStrList.join("; ");
};
var processSetCookieStr = function(str) {
    console.log("Processing set cookie string " + str);
    return getPrefix()+str;
};
Object.defineProperty(document, 'cookie', {
    get: function() {
        var storedCookieStr = cookieGetter();
        console.log("Intercepted a cookie get " + storedCookieStr + " , and returning processed cookie string " + processCookieStr(storedCookieStr));
        return processCookieStr(storedCookieStr);
    },
    set: function(cookieString) {
        var newValue = processSetCookieStr(cookieString);
        console.log("Intercepted a cookie set " + newValue)
        return cookieSetter(newValue);
    }
});
console.log("cookie get/set injector completed");
`;

var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
Nicholas DiPiazza
  • 10,029
  • 11
  • 83
  • 152