I'm making some updates to a Chrome extension that re-defines navigator.userAgent, and I came across this behavior when replacing DOMNodeInserted with MutationObserver ..
This question is generic and doesn't require testing from a Chrome extension.
The best way to explain this behavior is to navigate to: https://webbrowsertools.com/useragent/
Then ... using the console run the following javacript code, and check the response from iframe> navigator.userAgent:
DOMNodeInserted works fine, the iframe > navigator.userAgent is switched:
document.addEventListener('DOMNodeInserted', function(event)
{
if (event.target.tagName == 'IFRAME')
for (var i=0; i<window.frames.length; i++)
try { Object.defineProperty(window.frames[i].navigator, 'userAgent', {value:'TEST'}); } catch(e) {}
});
MutationObserver doesn't work, the iframe > navigator.userAgent is NOT switched:
var observer = new MutationObserver(function(mutations)
{
for (var mutation of mutations)
for (var item of mutation.addedNodes)
if (item.tagName == 'IFRAME')
for (var i=0; i<window.frames.length; i++)
try { Object.defineProperty(window.frames[i].navigator, 'userAgent', {value:'TEST'}); } catch(e) {}
});
observer.observe(document, { childList:true, subtree:true });
Excuse the crude iteration through window.frames and not the actual event.target
I believe it has to do with MutationObserver being too slow, but I don't know how to fix this ?!
UPDATE --------------------------------------------------------------
I have tried the suggestions without luck:
https://jsfiddle.net/12t5jx38/
See the script in action on the page:
First what happens without an injected script, then your suggestions, then the original using DOMNodeInserted ...
This is the result I'm trying to achieve, but without using DOMNodeInserted.
UPDATE 2 ------------------------------------------------------------
https://jsfiddle.net/st0ud9zq/
I believe there's no way to achieve the desired UA patch via MutationObserver.
Note: check the error within catch due to
CORS, you might not have access tocontentWindowof iframesIf your scripts register the observer after the iframe is there,
MutationObserverwon't detect anything. In that case go modify the available frames if you have access to theircontentWindow. For those that might be added at some point after your script,MutationObservershould work.I am not able to reproduce the behavior you had, SO snippet complains about CORS iframes so here is a JSFiddle
Here is the code
I used
setTimeoutto introduce a delay to initiate theMutationObserverincase the DOM node (in this case the iframe) might be inserted before the observer starts.you can also push a
Promiseto an outer array and resolve those pushed promises if you do not want to use setTimeout. But that's not the topic of this question.PS: It looks like the Mutation Observer is registered way after the DOM node is there, and on top you are using a text to dynamically set the content of the script and execute it there. In these cases divide the task in 2 parts, first scan the currently available iframes and do whatever you need to do on them and THEN register the Mutation Observer. Here is a fiddle:
https://jsfiddle.net/ibowankenobi/0bxyejga/