Skip to content

Commit

Permalink
Add matched cosmetic filters in troubleshooting information
Browse files Browse the repository at this point in the history
  • Loading branch information
gorhill committed Apr 4, 2023
1 parent 09265ef commit 6efd8eb
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 13 deletions.
37 changes: 25 additions & 12 deletions src/js/messaging.js
Expand Up @@ -609,6 +609,31 @@ const onMessage = function(request, sender, callback) {
});
return;

case 'launchReporter': {
const pageStore = µb.pageStoreFromTabId(request.tabId);
if ( pageStore === null ) { break; }
if ( vAPI.net.hasUnprocessedRequest(request.tabId) ) {
request.popupPanel.hasUnprocessedRequest = true;
}
const supportURL = new URL(vAPI.getURL('support.html'));
supportURL.searchParams.set('pageURL', request.pageURL);
supportURL.searchParams.set('popupPanel', JSON.stringify(request.popupPanel));
vAPI.tabs.executeScript(request.tabId, {
allFrames: true,
file: '/js/scriptlets/cosmetic-report.js',
matchAboutBlank: true,
}).then(results => {
const filters = results.reduce((a, v) => {
if ( Array.isArray(v) ) { a.push(...v); }
return a;
}, []);
if ( filters.length !== 0 ) {
supportURL.searchParams.set('cosmetic', JSON.stringify(filters));
}
µb.openNewTab({ url: supportURL.href, select: true, index: -1 });
});
return;
}
default:
break;
}
Expand All @@ -623,18 +648,6 @@ const onMessage = function(request, sender, callback) {
response = lastModified !== request.contentLastModified;
break;
}
case 'launchReporter': {
const pageStore = µb.pageStoreFromTabId(request.tabId);
if ( pageStore === null ) { break; }
if ( vAPI.net.hasUnprocessedRequest(request.tabId) ) {
request.popupPanel.hasUnprocessedRequest = true;
}
const supportURL = new URL(vAPI.getURL('support.html'));
supportURL.searchParams.set('pageURL', request.pageURL);
supportURL.searchParams.set('popupPanel', JSON.stringify(request.popupPanel));
µb.openNewTab({ url: supportURL.href, select: true, index: -1 });
break;
}
case 'revertFirewallRules':
// TODO: use Set() to message around sets of hostnames
sessionFirewall.copyRules(
Expand Down
2 changes: 1 addition & 1 deletion src/js/scriptlets/cosmetic-logger.js
Expand Up @@ -269,7 +269,7 @@ const handlers = {
if (
details.action !== undefined &&
details.tasks === undefined &&
details.action[0] === ':style'
details.action[0] === 'style'
) {
exceptionDict.set(details.selector, details.raw);
continue;
Expand Down
137 changes: 137 additions & 0 deletions src/js/scriptlets/cosmetic-report.js
@@ -0,0 +1,137 @@
/*******************************************************************************
uBlock Origin - a browser extension to block requests.
Copyright (C) 2015-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/

'use strict';

/******************************************************************************/

(( ) => {
// >>>>>>>> start of private namespace

/******************************************************************************/

if ( typeof vAPI !== 'object' ) { return; }
if ( typeof vAPI.domFilterer !== 'object' ) { return; }

/******************************************************************************/

const rePseudoElements = /:(?::?after|:?before|:[a-z-]+)$/;

const hasSelector = selector => {
try {
return document.querySelector(selector) !== null;
}
catch(ex) {
}
return false;
};

const safeQuerySelector = selector => {
const safeSelector = rePseudoElements.test(selector)
? selector.replace(rePseudoElements, '')
: selector;
try {
return document.querySelector(safeSelector);
}
catch(ex) {
}
return null;
};

const safeGroupSelectors = selectors => {
const arr = Array.isArray(selectors)
? selectors
: Array.from(selectors);
return arr.map(s => {
return rePseudoElements.test(s)
? s.replace(rePseudoElements, '')
: s;
}).join(',\n');
};

const allSelectors = vAPI.domFilterer.getAllSelectors();
const matchedSelectors = [];

if ( Array.isArray(allSelectors.declarative) ) {
const declarativeSet = new Set();
for ( const block of allSelectors.declarative ) {
for ( const selector of block.split(',\n') ) {
declarativeSet.add(selector);
}
}
if ( hasSelector(safeGroupSelectors(declarativeSet)) ) {
for ( const selector of declarativeSet ) {
if ( safeQuerySelector(selector) === null ) { continue; }
matchedSelectors.push(`##${selector}`);
}
}
}

if (
Array.isArray(allSelectors.procedural) &&
allSelectors.procedural.length !== 0
) {
for ( const pselector of allSelectors.procedural ) {
if ( pselector.hit === false && pselector.exec().length === 0 ) { continue; }
matchedSelectors.push(`##${pselector.raw}`);
}
}

if ( Array.isArray(allSelectors.exceptions) ) {
const exceptionDict = new Map();
for ( const selector of allSelectors.exceptions ) {
if ( selector.charCodeAt(0) !== 0x7B /* '{' */ ) {
exceptionDict.set(selector, selector);
continue;
}
const details = JSON.parse(selector);
if (
details.action !== undefined &&
details.tasks === undefined &&
details.action[0] === 'style'
) {
exceptionDict.set(details.selector, details.raw);
continue;
}
const pselector = vAPI.domFilterer.createProceduralFilter(details);
if ( pselector.test() === false ) { continue; }
matchedSelectors.push(`#@#${pselector.raw}`);
}
if (
exceptionDict.size !== 0 &&
hasSelector(safeGroupSelectors(exceptionDict.keys()))
) {
for ( const [ selector, raw ] of exceptionDict ) {
if ( safeQuerySelector(selector) === null ) { continue; }
matchedSelectors.push(`#@#${raw}`);
}
}
}

if ( matchedSelectors.length === 0 ) { return; }

return matchedSelectors;

/******************************************************************************/

// <<<<<<<< end of private namespace
})();

8 changes: 8 additions & 0 deletions src/js/support.js
Expand Up @@ -151,6 +151,9 @@ function showData() {
}
if ( reportedPage !== null ) {
shownData.popupPanel = reportedPage.popupPanel;
if ( reportedPage.cosmeticFilters ) {
shownData.cosmeticFilters = reportedPage.cosmeticFilters;
}
}
const text = JSON.stringify(shownData, null, 2)
.split('\n')
Expand Down Expand Up @@ -197,9 +200,14 @@ const reportedPage = (( ) => {
select.append(option);
}
dom.cl.add(dom.body, 'filterIssue');
let cosmeticFilters;
if ( url.searchParams.has('cosmetic') ) {
cosmeticFilters = JSON.parse(url.searchParams.get('cosmetic'));
}
return {
hostname: parsedURL.hostname.replace(/^(m|mobile|www)\./, ''),
popupPanel: JSON.parse(url.searchParams.get('popupPanel')),
cosmeticFilters,
};
} catch(ex) {
}
Expand Down

7 comments on commit 6efd8eb

@gwarser
Copy link
Contributor

@gwarser gwarser commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reporting dialog does not open on this page: https://florydziak.pl/uncategorized/10-kwietnia-juz-oficjalnie-ale/ when Fanboy's Annoyance list is enabled. Firefox Nightly, or my dirty profile only beta too, works fine in Chrome. No errors afaict. This commit seems related.

@gwarser
Copy link
Contributor

@gwarser gwarser commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dozens of tabs with report dialog opened as soon as I closed the tab with this page. No cosmetic filtering info in any of them.

@gorhill
Copy link
Owner Author

@gorhill gorhill commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I reproduce such issue on my side too, there is an issue in Firefox where the promise returned by tabs.executeScript never resolve. In my case JS was disabled on the site and enabling it fixed the issue, though this should not interfere with content scripts. Need to investigate more.

@gorhill
Copy link
Owner Author

@gorhill gorhill commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems related to using matchAboutBlank.


Using runAt: 'document_start' seems to solve the issue, I will publish a new dev build and will see.

@gorhill
Copy link
Owner Author

@gorhill gorhill commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could reproduce the issue at https://florydziak.pl/uncategorized/10-kwietnia-juz-oficjalnie-ale/, now I can't.

On my side I was having the issue at https://www.businessinsider.com/charlie-javice-frank-criminal-charges-financial-fraud-jpmorgan-chase-2023-1 with JS disabled, now it works.

So issue fixed?

@gwarser
Copy link
Contributor

@gwarser gwarser commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it works now. Worth to note that "matched" means "right now" - logger reports more filters.


Disqus adblock detector

define("core/utils/isAdBlockEnabled", [], function() {
    "use strict";
    function a() {
        var a = d.createElement("div");
        return a.setAttribute("class", "pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links ad-text adSense adBlock adContent adBanner"),

These starting with .ad are logged on my side.

@gorhill
Copy link
Owner Author

@gorhill gorhill commented on 6efd8eb Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it won't detect bait elements etc., but still useful for cases like https://www.reddit.com/r/uBlockOrigin/comments/12b3eik/, there was a lot of back and forth and it can get very difficult when we have to ask non technical users to find which cosmetic filter interfere negatively. It's why I implemented this, to save time for those cases.

Please sign in to comment.