Discussions » Development

mutationObserver on iframe doesn't seem to work in Firefox (ok in Chrome)

§
Posted: 2020-12-01
Edited: 2020-12-06

Greetings

I'd like to ask your help please with a problem with a script of mine, ProtonMail - remove forced signature
(it's continuation of this report in my repo)

I have the above script. It removes the forced Sent with ProtonMail Secure Email signature from the 'New message' textboxes .
It's meant to work for both https://mail.protonmail.com and https://beta.protonmail.com/ .
It works ok in both sites with Tampermonkey/Violentmonkey in Chrome
but unfortunately not in Firefox regarding the latter, 'beta' subdomain, i.e. https://beta.protonmail.com/

How the script works:
The problem with the signature in the beta subdomain is that the signature element gets created after the editor iframe is fully created.
So my script uses the arrive.js library to wait for the .squireIframe element to be created,
and then it creates a mutationobserver inside the iframe to wait for the signature element to be created, then remove it.

So, why does my script doesn't work ok in https://beta.protonmail.com/ with Firefox in TM/VM?
It seems like it cannot access the iframe: arrive.js fires ok when the iframe element gets created, but the mutationobserver doesn't fire at all.

Below is a shortened version of the script:


// ==UserScript==
// @name        ProtonMail - remove forced signature
// @include     https://beta.protonmail.com/*
// @grant       none
// @require     https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js
// ==/UserScript==

var elementToWatch = elementToWatch = '.squireIframe';

document.arrive(elementToWatch, function () {

    let iframe = iframe = this.contentDocument;

    const config = {
        childList: true,
        subtree: true
    };

    const callback = function callback(mutationList, observer) {
        mutationList.forEach( (mutation) => {
            mutation.addedNodes.forEach( (node) => {
                if (node.className === 'protonmail_signature_block') {
                    node.remove();
                    observer.disconnect();
                }});
        });
    };

    const observer = new MutationObserver(callback);
    observer.observe(iframe, config);

});

§
Posted: 2020-12-01
Edited: 2020-12-02

I'm getting Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”)
in both mail.protonmail.com and beta.protonmail.com with Firefox
but the script works ok in the former, mail.protonmail.com, where no mutationObserver for inside the iframe is needed.
I guess it's a known Firefox limitation? Is there no solution?

I've already tried (always in Firefox) without success:

  • in the script: // @include *
  • in both Tampermonkey/Violentmonkey: changed // @grant none to // @grant add_Style in order to restore the proper sandbox.
  • in Tampermonkey: changed in: Security | Modify existing content security policy (CSP) headers| 'Remove entirely'
  • in Violentmonkey: added in the script: // @inject-into page
  • in Firefox itself: disabled security.csp.enable in about:config .
§
Posted: 2020-12-02
Edited: 2020-12-02

It's seems that you are making things too complicated, why you don't just use settimeout or setinterval to check for the existence of the signature text? then either "reload" the iframe or erase the whole iframe text contents.

I'm not sure how your script works because I didn't read all the codes, but you should also make sure that the user isn't opening a draft, otherwise your script might end up erasing the draft content

It's probably easier if you use this to correctly erase only the signature text
// @require https://cdnjs.cloudflare.com/ajax/libs/findAndReplaceDOMText/0.4.6/findAndReplaceDOMText.min.js

if (document.body.innerText.search("signature text here") > -1) {
findAndReplaceDOMText(document.body, {find: 'signature text here',replace: ""});
}


*Try using/running the script without the grant none tag

§
Posted: 2020-12-02
Edited: 2020-12-02

First of all, thank you for replying.


why you don't just use settimeout or setinterval to check for the existence of the signature text

I don't want to settimeout or setinterval, because I want to make the script remove the signature exactly the moment it gets inserted.

you should also make sure that the user isn't opening a draft, otherwise your script might end up erasing the draft content

In Chrome as I said, the script works fine and doesn't remove any existing draft content.

 

At any case, I tried changing the code into:

// ==UserScript==
// @name        ProtonMail - remove forced signature
// @include     https://beta.protonmail.com/*
// @grant       GM_addStyle
// @require     https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/findAndReplaceDOMText/0.4.6/findAndReplaceDOMText.min.js
// ==/UserScript==

var elementToWatch = elementToWatch = '.squireIframe';

document.arrive(elementToWatch, function () {

    let iframe = this.contentDocument.body;  // 'this' refers to the newly created element

    const signatureText = 'Sent with ProtonMail Secure Email.';

    if (iframe.innerText.search(signatureText) > -1) {
        findAndReplaceDOMText(iframe, {
            find: signatureText,
            replace: ''
        });
    }

})

but it doesn't work.

§
Posted: 2020-12-02
Edited: 2020-12-02

You are welcome, if you use a timeout you can make the script remove the signature exactly the moment it gets inserted...

The problem of your code is this find: signatureText,
signature text is the text itself, not something else. https://www.xspdf.com/help/50537862.html

§
Posted: 2020-12-02

if you use a timeout you can make the script remove the signature exactly the moment it gets inserted...

With that method, there will always be some additional msec difference between being inserted and being removed,
I don't think it's possible to guess/find the exact msec value after which that it gets inserted.

The problem of your code is this find: signatureText,
signature text is the text itself, not something else.

But, it simply gets the value of the const, signatureText :
find: signatureText, is the exact same as putting find: 'Sent with ProtonMail Secure Email.',.

I even tried changing its value to '\n\n\n\nSent with ProtonMail Secure Email.\n', to include the newlines, but it doesn't make any difference.

§
Posted: 2020-12-02

Your script also doesn't work with tampermonkey on the opera browser on the url https://mail.protonmail.com/inbox

I will try to make it work the way I'm saying now

§
Posted: 2020-12-02
Edited: 2020-12-02

Actually that text is contained here document.querySelector("#uid1 > section > div > div.composer-editor.angular-squire.fill.squire-container.squireEditor-loaded > div > textarea")

So neither your script neither mine does work
(function() {
'use strict';
function alertFunc(){
findAndReplaceDOMText(document.querySelector(".squireIframe").contentDocument, {find: 'Sent with ProtonMail Secure Email.',replace: ""});
document.querySelector(".squireIframe").contentDocument.querySelector("body > div.protonmail_signature_block > div.protonmail_signature_block-proton").innerText = ''
}
setTimeout(function(){ document.querySelector("#pm_sidebar > button").onclick = function() {
setTimeout(alertFunc, 6000);
};
}, 6000);
})();


Because document.querySelector(".squireIframe") doesn't have any text, it does have the text signature on it, but even if you do this document.querySelector(".squireIframe").contentDocument.querySelector("body > div.protonmail_signature_block > div.protonmail_signature_block-proton").innerText = ''
The text will still be there, because the text is actually on document.querySelector("#uid1 > section > div > div.composer-editor.angular-squire.fill.squire-container.squireEditor-loaded > div > textarea")

But apparently document.querySelector("#uid1 > section > div > div.composer-editor.angular-squire.fill.squire-container.squireEditor-loaded > div > textarea") does not have any text content.This is because ProtonMail Secure the website to prevent scripts from changing or getting the content, so it's going to be much harder to make a script to auto remove their signature

Let me know if you fix your script somehow

§
Posted: 2020-12-02
Edited: 2020-12-02

Could you please enclose your code blocks/lines with <code> (HTML) or backticks ` (Markdown, 1 for single-line, 3 for multi-line) ?
Thank you!

§
Posted: 2020-12-02
Edited: 2020-12-02

I'm not sure how you could remove the br on the signature.

You can also try another solution that maybe won't really look as nice as your first solution, or the solution that I was talking about.
You can try making a script that would click on that text box and press ctrl+a then you could erase (maybe ctrl+x?) the signature with the br s on it maybe.

It doesn't seem that will be easy to figure out where they really store their signature text, or how you could erase the signature.
I would recommend you to first try some codes to retrive/get the signature and the written email, then try erasing or modifying some parts, when you can do that on the browser console you will be able to make the codes and the logic to make a tampermonkey script

It seems that the real signature text is hidden on some of their functions.
Maybe you still can try this document.querySelector(".squireIframe") doesn't have any text, it does have the text signature on it, but even if you do this document.querySelector(".squireIframe").contentDocument.querySelector("body > div.protonmail_signature_block > div.protonmail_signature_block-proton").innerText = '', because maybe this actually does remove the signature text, but I didn't reload the iframe, so I didn't se any changes? I'm not sure.

You could also try simulating their "sent email box", you can make a "sent email box" that works and that is 100% identical to their default "sent email box", but you would change the html of your box to not show the signature

You are welcome
Let me know when you fix your script

§
Posted: 2020-12-03

I think it is just firefox does not allow to do what you want. Look here: same issue with Safari browser

§
Posted: 2020-12-03
Edited: 2020-12-03

I'm using opera, but neither his script, neither mine worked

§
Posted: 2020-12-03
Edited: 2020-12-03

I think it is just firefox does not allow to do what you want. Look here: same issue with Safari browser

Thanks for your reply. I'm leaning towards this explanation too.

Post reply

Sign in to post a reply.