uBlock-LLC / uBlock

uBlock: a fast, lightweight, and lean blocker for Chrome, Firefox, and Safari.
https://ublock.org/
GNU General Public License v3.0
8.18k stars 436 forks source link

Blocking scripts should display noscript tags #574

Closed anmarmansur closed 2 years ago

anmarmansur commented 9 years ago

This might be specific to Firefox, as I don't use Chrome, but as it stands blocking scripts with uBlock will leave most websites unusable, while, for comparison, blocking scripts using the NoScript extension will not do so, because NoScript (I believe) tells the browser to parse and display the page's

If this is intentional, and if there is a benefit to continue to hide the page's , perhaps a user selectable behavior could be added.

lewisje commented 9 years ago

If you're talking about dynamic filtering, blocking all scripts that run on a certain hostname, then I think this extension might need to use the contentSettings API like uMatrix does; then if it uses that API to disable scripts on that hostname, Chrome will parse noscript elements as usual.

anmarmansur commented 9 years ago

Yes, I am talking about dynamic filtering, but on Firefox not Chrome. I looked at a couple of Firefox extensions, NoScript and TabMixPlus, and the way they tell Firefox to parse a page's <noscript> tags is as simple as setting the linkedBrowser.docShell.allowJavascript property of the tab object to false. That, however, is a tab-wide setting that will block all scripts on a page regardless of origin.

It appears that, on Firefox at least, there's no straightforward way to achieve this while maintaining the origin-specific granularity of blocking scripts, as the only way to get Firefox to parse <noscript> tags is to block all scripts on a tab. Please, feel free to close this issue.

gorhill commented 9 years ago

@lewisje

need to use the contentSettings API like uMatrix does

No, uMatrix does not do that.

The solution is simple: to transform <noscript> into <div> when inline script tags are blocked, just like uMatrix does.

chrisaljoudi commented 9 years ago

@gorhill some thoughts on why this might not be optimal:

My own, humble suggestion would be to offer some visual indicator in the µBlock toolbar icon when one or more first-party scripts are blocked (an "asterisk" after the count, perhaps?). That gives the advantage of easier debugging/troubleshooting without the potential problems listed above.

What do you think?

chrisaljoudi commented 9 years ago

@gorhill just another quick note (follow-up to comment above): if you do decide to show <noscript> stuff on pages µBlock blocks a script, I think it'd be good to consider using a style injection instead of traversing the DOM.

In other words:

noscript {
    display: block;
}

Inserting that should be much cheaper than looking for/replacing <noscript> tags, offloading most of the work to the browser (which presumably knows how to efficiently select elements and modify how/whether they get rendered).

anmarmansur commented 9 years ago

I thought of that too, but Firefox appears to have the following rule hardcoded in about:PreferenceStyleSheet, and it takes precedence over anything you inject:

noscript {
    display: none !important;
}
chrisaljoudi commented 9 years ago

it takes precedence over anything you inject

Is that a conclusion, or something special that Firefox does? You can have !important and that'll override it if it's just playing by CSS rules. If it's fully CSS-compliant and Firefox isn't hacking in some weird thing, being slightly more specific with the selector should be sufficient:

* > noscript {
    display: block !important;
}
anmarmansur commented 9 years ago

Well, it either takes precedence through some trickery, or the CSS rules are being ignored altogether, and the noscript tags are forced hidden in the DOM. Either way, the result is the same, unless you disable scripting on a tab, noscript tags are hidden. I might dig through the source code this weekend if I get a chance, out of curiosity and not hope of achieving anything mind you.

lewisje commented 9 years ago

@gorhill I thought uMatrix might use contentSettings for more than just setting, as a baseline, a couple whitelists (whitelisting all scripts on URLs starting with http:// and https://); I guess it wouldn't have worked to use contentSettings to granularly enforce cookie and plugin and image and script permissions, or else you would have done that.

@anmarmansur Did you try injecting that style block with !important and still found that it was being overridden?

anmarmansur commented 9 years ago

Yes, I did try injecting that style block with !important among many other things. I also had a chance to take a quick look at the source code and found something interesting to support my assumption that noscript CSS rules were being ignored: Gecko's HTML parser has a special class of tags, which it doesn't parse, but outputs their contents untouched as CDATA. Among those are script, style, and noscript tags!

I immediately confirmed this in the browser by creating this simple HTML document:

...
<body>
    <div>div 1</div>
    <noscript>
        <div>div 2</div>
        <div>div 3</div>
    </noscript>
</body>
...

And this is what the resulting DOM looks like:

...
BODY
    #text
    DIV
        #text
    #text
    NOSCRIPT
        #text
    #text

Notice how the latter two div tags are absent from the DOM. In fact, that #text node under the NOSCRIPT node contains the inner html unparsed complete with indentations and new lines:

"\n        <div>div 2</div>\n        <div>div 3</div>\n    "    
gorhill commented 9 years ago

Yes the DOM won't parse noscript if javascript is not disabled. There could be meta tag in there for automatic redirection when javascript is disabled etc. It's why it is implemented the way it is in uMatrix.

quinncomendant commented 9 years ago

+1 I would like to see the <noscript> when all JS on the site is blocked. But if at least one JS is enabled, then <noscript> should be hidden.

lewisje commented 9 years ago

Unfortunately that can't be done: Apparently there is no way to have the browser think that scripting is disabled altogether just because every single script is blocked, and <noscript> elements are parsed and displayed only if scripting is disabled.

bzbarsky commented 6 years ago

That, however, is a tab-wide setting that will block all scripts on a page regardless of origin.

More precisely, setting allowJavascript on a docshell will by default inherit that same setting into its descendant docshells (iframes). One can directly set allowJavascript on those other docshells if desired if their script-enabled state should not match the parent.

bzbarsky commented 6 years ago

and it takes precedence over anything you inject

Oh, and for this part: the preferences sheet is a user-level sheet. !important rules in it have hight precedence than any author-sheet rules. Having an extension add a user-level or ua-level sheet with a !important rule would allow overriding it.

gorhill commented 6 years ago

@bzbarsky The repo here is dead since years. I was made aware of your comment from https://bugzilla.mozilla.org/show_bug.cgi?id=1392090#c5. The issue for (not abandonware) uBlock Origin is here: https://github.com/gorhill/uBlock/issues/308. I would like to understand what you are referring to with:

setting allowJavascript on a docshell

What WebExtensions API are you referring to?

bzbarsky commented 6 years ago

I'll follow up in https://github.com/gorhill/uBlock/issues/308

bzbarsky commented 6 years ago

What WebExtensions API are you referring to?

There might well not be a webextensions API for this. That part of my comment was in response to the earlier discussion in this issue, which was not in a webextensions context.