I am working on a Chrome extension, and it’s currently published with Manifest v2,
I also have a Manifest v3 version, however there’s one small difference in functionality.
Consider the following content script, same for v2 and v3:
var AGScript = `
var setAgent = function(win)
{
try
{
Object.defineProperty(win.navigator, "userAgentData", {value:undefined});
Object.defineProperty(win.navigator, "platform", {value:undefined});
Object.defineProperty(win.navigator, "vendor", {value:undefined});
Object.defineProperty(win.navigator, "userAgent", {value:"xxx"});
Object.defineProperty(win.navigator, "appVersion", {value:"xxx"});
} catch(e) {}
};
document.addEventListener("DOMContentLoaded", function(event) { setAgent(window); });
document.addEventListener("DOMNodeInserted", function(event) { if (event.target.tagName == "IFRAME") setAgent(event.target.contentWindow); });
setAgent(window);
`;
var script = document.createElement("script");
script.type = "text/javascript";
script.textContent = AGScript;
document.documentElement.appendChild(script);
script.remove();
And the following v2 manifest section:
"content_scripts": [ {
"all_frames": true,
"js": [ "content-ag.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*", "file:///*" ],
"run_at": "document_start"
} ]
Also, a v3 manifest:
"content_scripts": [ {
"all_frames": true,
"js": [ "content-ag.js" ],
"matches": [ "<all_urls>" ],
"run_at": "document_start",
"world": "MAIN"
} ]
When testing on the following page: https://browserleaks.com/javascript
the v2 redefines userAgent for both window and iframe.contentWindow,
and yet v3 is only able to do it in window.
I have tried playing with different manifest options, but just can’t get it.
Yet, on the following page: https://webbrowsertools.com/useragent
both versions are able to change everything, including iframes.
This leads me to believe it’s a timing problem.
Update.
As suggested I have added "match_origin_as_fallback": true, as well as changed the content script to the following:
(() => {
console.log("here!");
var setAgent = function(win)
{
try
{
Object.defineProperty(win.navigator, "userAgentData", {value:undefined});
Object.defineProperty(win.navigator, "platform", {value:undefined});
Object.defineProperty(win.navigator, "vendor", {value:undefined});
Object.defineProperty(win.navigator, "userAgent", {value:"xxx"});
Object.defineProperty(win.navigator, "appVersion", {value:"xxx"});
} catch(e) {}
};
document.addEventListener("DOMContentLoaded", function(event) { setAgent(window); });
document.addEventListener("DOMNodeInserted", function(event) { if (event.target.tagName == "IFRAME") setAgent(event.target.contentWindow); });
setAgent(window);
})()
Unfortunately userAgent is not overridden when tested with https://webbrowsertools.com/useragent/
here! is printed in the console. Did I mess up somewhere?
(I was trying in manifest v2, not that it should make any difference)
2
Answers
What a bizarre way of adding script to one’s own document! 🙂
When you could’ve just…
…and saved yourself a ton of typing and even unnecessary delays!
Ah well… I guess some like to play the mysterious! 🙂
Onto the problem at hand…
Observation 1:
Instead of "DOMNodeInserted" use "DOMNodeInsertedIntoDocument".
The former is suitable for fragments while the latter is self-explanatory.
Observation 2:
You’re setting the agent up twice on the main window…
document.addEventListener("DOMContentLoaded", function(event) { setAgent(window); });
setAgent(window);
Why is that? Is that because DOMContentLoaded wasn’t working for you by any chance?
Observation 3:
Why were you not using <all_urls> in manifest II when it was possible since 2011? Or thereabouts…
Looks like a bug in Chrome.
A possible workaround is to intercept the getter for contentWindow: