mirror of https://github.com/gorhill/uBlock.git
Disable creation of cosmetic filters in picker when unenforceable
Related issue: - https://github.com/gorhill/uBlock/issues/3212 The element picker will now properly work on sites where cosmetic filtering is disabled, but will not allow the creation of cosmetic filters when specific cosmetic filters are not meant to be enforced in the current page. When specific cosmetic filters are not meant to be enforced, the element picker will still allow the creation of network filters, that is unless the current page is trusted, in which case using the element picker is pointless.
This commit is contained in:
parent
f1a453d349
commit
e983f9a76e
|
@ -1275,12 +1275,21 @@ vAPI.DOMFilterer = class {
|
|||
|
||||
vAPI.domCollapser.start();
|
||||
|
||||
if ( response.noCosmeticFiltering ) {
|
||||
const {
|
||||
noSpecificCosmeticFiltering,
|
||||
noGenericCosmeticFiltering,
|
||||
scriptlets,
|
||||
} = response;
|
||||
|
||||
vAPI.noSpecificCosmeticFiltering = noSpecificCosmeticFiltering;
|
||||
vAPI.noGenericCosmeticFiltering = noGenericCosmeticFiltering;
|
||||
|
||||
if ( noSpecificCosmeticFiltering && noGenericCosmeticFiltering ) {
|
||||
vAPI.domFilterer = null;
|
||||
vAPI.domSurveyor = null;
|
||||
} else {
|
||||
const domFilterer = vAPI.domFilterer = new vAPI.DOMFilterer();
|
||||
if ( response.noGenericCosmeticFiltering || cfeDetails.noDOMSurveying ) {
|
||||
if ( noGenericCosmeticFiltering || cfeDetails.noDOMSurveying ) {
|
||||
vAPI.domSurveyor = null;
|
||||
}
|
||||
domFilterer.exceptions = cfeDetails.exceptionFilters;
|
||||
|
@ -1293,9 +1302,9 @@ vAPI.DOMFilterer = class {
|
|||
|
||||
// Library of resources is located at:
|
||||
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
||||
if ( response.scriptlets ) {
|
||||
vAPI.injectScriptlet(document, response.scriptlets);
|
||||
vAPI.injectedScripts = response.scriptlets;
|
||||
if ( scriptlets ) {
|
||||
vAPI.injectScriptlet(document, scriptlets);
|
||||
vAPI.injectedScripts = scriptlets;
|
||||
}
|
||||
|
||||
if ( vAPI.domSurveyor instanceof Object ) {
|
||||
|
|
|
@ -114,6 +114,9 @@ const onEntryClicked = function(details, tab) {
|
|||
if ( details.menuItemId === 'uBlock0-blockElementInFrame' ) {
|
||||
return onBlockElementInFrame(details, tab);
|
||||
}
|
||||
if ( details.menuItemId === 'uBlock0-blockResource' ) {
|
||||
return onBlockElement(details, tab);
|
||||
}
|
||||
if ( details.menuItemId === 'uBlock0-subscribeToList' ) {
|
||||
return onSubscribeToList(details);
|
||||
}
|
||||
|
@ -128,23 +131,28 @@ const menuEntries = {
|
|||
blockElement: {
|
||||
id: 'uBlock0-blockElement',
|
||||
title: vAPI.i18n('pickerContextMenuEntry'),
|
||||
contexts: ['all'],
|
||||
contexts: [ 'all' ],
|
||||
},
|
||||
blockElementInFrame: {
|
||||
id: 'uBlock0-blockElementInFrame',
|
||||
title: vAPI.i18n('contextMenuBlockElementInFrame'),
|
||||
contexts: ['frame'],
|
||||
contexts: [ 'frame' ],
|
||||
},
|
||||
blockResource: {
|
||||
id: 'uBlock0-blockResource',
|
||||
title: vAPI.i18n('pickerContextMenuEntry'),
|
||||
contexts: [ 'audio', 'frame', 'image', 'video' ],
|
||||
},
|
||||
subscribeToList: {
|
||||
id: 'uBlock0-subscribeToList',
|
||||
title: vAPI.i18n('contextMenuSubscribeToList'),
|
||||
contexts: ['link'],
|
||||
contexts: [ 'link' ],
|
||||
targetUrlPatterns: [ 'abp:*' ],
|
||||
},
|
||||
temporarilyAllowLargeMediaElements: {
|
||||
id: 'uBlock0-temporarilyAllowLargeMediaElements',
|
||||
title: vAPI.i18n('contextMenuTemporarilyAllowLargeMediaElements'),
|
||||
contexts: ['all'],
|
||||
contexts: [ 'all' ],
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -155,25 +163,35 @@ let currentBits = 0;
|
|||
const update = function(tabId = undefined) {
|
||||
let newBits = 0;
|
||||
if ( µBlock.userSettings.contextMenuEnabled && tabId !== undefined ) {
|
||||
let pageStore = µBlock.pageStoreFromTabId(tabId);
|
||||
const pageStore = µBlock.pageStoreFromTabId(tabId);
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
newBits |= 0x01;
|
||||
if ( pageStore.shouldApplySpecificCosmeticFilters(0) ) {
|
||||
newBits |= 0b0001;
|
||||
} else {
|
||||
newBits |= 0b0010;
|
||||
}
|
||||
if ( pageStore.largeMediaCount !== 0 ) {
|
||||
newBits |= 0x02;
|
||||
newBits |= 0b0100;
|
||||
}
|
||||
}
|
||||
newBits |= 0b1000;
|
||||
}
|
||||
if ( newBits === currentBits ) { return; }
|
||||
currentBits = newBits;
|
||||
let usedEntries = [];
|
||||
if ( newBits & 0x01 ) {
|
||||
const usedEntries = [];
|
||||
if ( newBits & 0b0001 ) {
|
||||
usedEntries.push(menuEntries.blockElement);
|
||||
usedEntries.push(menuEntries.blockElementInFrame);
|
||||
usedEntries.push(menuEntries.subscribeToList);
|
||||
}
|
||||
if ( newBits & 0x02 ) {
|
||||
if ( newBits & 0b0010 ) {
|
||||
usedEntries.push(menuEntries.blockResource);
|
||||
}
|
||||
if ( newBits & 0b0100 ) {
|
||||
usedEntries.push(menuEntries.temporarilyAllowLargeMediaElements);
|
||||
}
|
||||
if ( newBits & 0b1000 ) {
|
||||
usedEntries.push(menuEntries.subscribeToList);
|
||||
}
|
||||
vAPI.contextMenu.setEntries(usedEntries, onEntryClicked);
|
||||
};
|
||||
|
||||
|
|
|
@ -966,7 +966,10 @@ FilterContainer.prototype.retrieveSpecificSelectors = function(
|
|||
};
|
||||
const injectedCSS = [];
|
||||
|
||||
if ( options.noCosmeticFiltering !== true ) {
|
||||
if (
|
||||
options.noSpecificCosmeticFiltering !== true ||
|
||||
options.noGenericCosmeticFiltering !== true
|
||||
) {
|
||||
const injectedHideFilters = [];
|
||||
const specificSet = this.$specificSet;
|
||||
const proceduralSet = this.$proceduralSet;
|
||||
|
@ -1161,7 +1164,7 @@ FilterContainer.prototype.benchmark = async function() {
|
|||
entity: '',
|
||||
};
|
||||
const options = {
|
||||
noCosmeticFiltering: false,
|
||||
noSpecificCosmeticFiltering: false,
|
||||
noGenericCosmeticFiltering: false,
|
||||
};
|
||||
let count = 0;
|
||||
|
|
|
@ -696,7 +696,7 @@ const viewPort = (( ) => {
|
|||
if ( filteringType === 'static' ) {
|
||||
divcl.add('canLookup');
|
||||
} else if ( details.realm === 'extended' ) {
|
||||
divcl.add('canLookup');
|
||||
divcl.toggle('canLookup', /^#@?#/.test(filter.raw));
|
||||
divcl.toggle('isException', filter.raw.startsWith('#@#'));
|
||||
}
|
||||
if ( filter.modifier === true ) {
|
||||
|
|
|
@ -555,73 +555,23 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
}
|
||||
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
const noCosmeticFiltering = pageStore.noCosmeticFiltering === true;
|
||||
const noSpecificCosmeticFiltering =
|
||||
pageStore.shouldApplySpecificCosmeticFilters(frameId) === false;
|
||||
const noGenericCosmeticFiltering =
|
||||
pageStore.shouldApplyGenericCosmeticFilters(frameId) === false;
|
||||
|
||||
const response = {
|
||||
collapseBlocked: µb.userSettings.collapseBlocked,
|
||||
noCosmeticFiltering,
|
||||
noGenericCosmeticFiltering: noCosmeticFiltering,
|
||||
noSpecificCosmeticFiltering: noCosmeticFiltering,
|
||||
noGenericCosmeticFiltering,
|
||||
noSpecificCosmeticFiltering,
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uAssets/issues/5704
|
||||
// `generichide` must be evaluated in the frame context.
|
||||
if ( noCosmeticFiltering === false ) {
|
||||
const genericHide =
|
||||
µb.staticNetFilteringEngine.matchStringReverse(
|
||||
'generichide',
|
||||
request.url
|
||||
);
|
||||
response.noGenericCosmeticFiltering = genericHide === 2;
|
||||
if ( loggerEnabled && genericHide !== 0 ) {
|
||||
µBlock.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(request.url)
|
||||
.setRealm('network')
|
||||
.setType('generichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
}
|
||||
|
||||
request.tabId = tabId;
|
||||
request.frameId = frameId;
|
||||
request.hostname = µb.URI.hostnameFromURI(request.url);
|
||||
request.domain = µb.URI.domainFromHostname(request.hostname);
|
||||
request.entity = µb.URI.entityFromDomain(request.domain);
|
||||
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/
|
||||
// Add support for `specifichide`.
|
||||
if ( noCosmeticFiltering === false ) {
|
||||
const specificHide =
|
||||
µb.staticNetFilteringEngine.matchStringReverse(
|
||||
'specifichide',
|
||||
request.url
|
||||
);
|
||||
response.noSpecificCosmeticFiltering = specificHide === 2;
|
||||
if ( loggerEnabled && specificHide !== 0 ) {
|
||||
µBlock.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(request.url)
|
||||
.setRealm('network')
|
||||
.setType('specifichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
}
|
||||
|
||||
// Cosmetic filtering can be effectively disabled when both specific and
|
||||
// generic cosmetic filtering are disabled.
|
||||
if (
|
||||
noCosmeticFiltering === false &&
|
||||
response.noGenericCosmeticFiltering &&
|
||||
response.noSpecificCosmeticFiltering
|
||||
) {
|
||||
response.noCosmeticFiltering = true;
|
||||
}
|
||||
|
||||
response.specificCosmeticFilters =
|
||||
µb.cosmeticFilteringEngine.retrieveSpecificSelectors(request, response);
|
||||
|
||||
|
@ -656,7 +606,11 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
// Inject as early as possible to make the cosmetic logger code less
|
||||
// sensitive to the removal of DOM nodes which may match injected
|
||||
// cosmetic filters.
|
||||
if ( loggerEnabled && response.noCosmeticFiltering !== true ) {
|
||||
if ( loggerEnabled ) {
|
||||
if (
|
||||
noSpecificCosmeticFiltering === false ||
|
||||
noGenericCosmeticFiltering === false
|
||||
) {
|
||||
vAPI.tabs.executeScript(tabId, {
|
||||
allFrames: false,
|
||||
file: '/js/scriptlets/cosmetic-logger.js',
|
||||
|
@ -665,6 +619,7 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
runAt: 'document_start',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
|
|
@ -192,6 +192,10 @@ const FrameStore = class {
|
|||
this.domain =
|
||||
vAPI.domainFromHostname(this.hostname) || this.hostname;
|
||||
}
|
||||
// Evaluated on-demand
|
||||
// - 0b01: specific cosmetic filtering
|
||||
// - 0b10: generic cosmetic filtering
|
||||
this._cosmeticFilteringBits = undefined;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -203,6 +207,60 @@ const FrameStore = class {
|
|||
return null;
|
||||
}
|
||||
|
||||
getCosmeticFilteringBits(tabId) {
|
||||
if ( this._cosmeticFilteringBits !== undefined ) {
|
||||
return this._cosmeticFilteringBits;
|
||||
}
|
||||
this._cosmeticFilteringBits = 0b11;
|
||||
{
|
||||
const result = µb.staticNetFilteringEngine.matchStringReverse(
|
||||
'specifichide',
|
||||
this.rawURL
|
||||
);
|
||||
if ( result !== 0 && µb.logger.enabled ) {
|
||||
µBlock.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('network')
|
||||
.setType('specifichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
if ( result === 2 ) {
|
||||
this._cosmeticFilteringBits &= ~0b01;
|
||||
}
|
||||
}
|
||||
{
|
||||
const result = µb.staticNetFilteringEngine.matchStringReverse(
|
||||
'generichide',
|
||||
this.rawURL
|
||||
);
|
||||
if ( result !== 0 && µb.logger.enabled ) {
|
||||
µBlock.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('network')
|
||||
.setType('generichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
if ( result === 2 ) {
|
||||
this._cosmeticFilteringBits &= ~0b10;
|
||||
}
|
||||
}
|
||||
return this._cosmeticFilteringBits;
|
||||
}
|
||||
|
||||
shouldApplySpecificCosmeticFilters(tabId) {
|
||||
return (this.getCosmeticFilteringBits(tabId) & 0b01) !== 0;
|
||||
}
|
||||
|
||||
shouldApplyGenericCosmeticFilters(tabId) {
|
||||
return (this.getCosmeticFilteringBits(tabId) & 0b10) !== 0;
|
||||
}
|
||||
|
||||
static factory(frameURL, parentId = -1) {
|
||||
const entry = FrameStore.junkyard.pop();
|
||||
if ( entry === undefined ) {
|
||||
|
@ -296,7 +354,7 @@ const PageStore = class {
|
|||
// The context is used to determine whether we report behavior change
|
||||
// to the logger.
|
||||
|
||||
init(tabId, context) {
|
||||
init(tabId) {
|
||||
const tabContext = µb.tabContextManager.mustLookup(tabId);
|
||||
this.tabId = tabId;
|
||||
|
||||
|
@ -327,28 +385,8 @@ const PageStore = class {
|
|||
this.frames = new Map();
|
||||
this.setFrameURL({ url: tabContext.rawURL });
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/314
|
||||
const masterSwitch = tabContext.getNetFilteringSwitch();
|
||||
|
||||
this.noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
|
||||
'no-cosmetic-filtering',
|
||||
tabContext.rootHostname
|
||||
) === true;
|
||||
if (
|
||||
masterSwitch &&
|
||||
this.noCosmeticFiltering &&
|
||||
µb.logger.enabled &&
|
||||
context === 'tabCommitted'
|
||||
) {
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(tabContext.rawURL)
|
||||
.setRealm('cosmetic')
|
||||
.setType('dom')
|
||||
.setFilter(µb.sessionSwitches.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
// Evaluated on-demand
|
||||
this._noCosmeticFiltering = undefined;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -493,15 +531,53 @@ const PageStore = class {
|
|||
.getNetFilteringSwitch();
|
||||
}
|
||||
|
||||
getSpecificCosmeticFilteringSwitch() {
|
||||
return this.noCosmeticFiltering !== true;
|
||||
}
|
||||
|
||||
toggleNetFilteringSwitch(url, scope, state) {
|
||||
µb.toggleNetFilteringSwitch(url, scope, state);
|
||||
this.netFilteringCache.empty();
|
||||
}
|
||||
|
||||
shouldApplyCosmeticFilters(frameId = 0) {
|
||||
if ( this._noCosmeticFiltering === undefined ) {
|
||||
this._noCosmeticFiltering = this.getNetFilteringSwitch() === false;
|
||||
if ( this._noCosmeticFiltering === false ) {
|
||||
this._noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
|
||||
'no-cosmetic-filtering',
|
||||
this.tabHostname
|
||||
) === true;
|
||||
if ( this._noCosmeticFiltering && µb.logger.enabled ) {
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(this.tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('cosmetic')
|
||||
.setType('dom')
|
||||
.setFilter(µb.sessionSwitches.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( this._noCosmeticFiltering ) { return false; }
|
||||
if ( frameId === -1 ) { return true; }
|
||||
// Cosmetic filtering can be effectively disabled when both specific
|
||||
// and generic cosmetic filters are disabled.
|
||||
return this.shouldApplySpecificCosmeticFilters(frameId) ||
|
||||
this.shouldApplyGenericCosmeticFilters(frameId);
|
||||
}
|
||||
|
||||
shouldApplySpecificCosmeticFilters(frameId) {
|
||||
if ( this.shouldApplyCosmeticFilters(-1) === false ) { return false; }
|
||||
const frameStore = this.getFrameStore(frameId);
|
||||
if ( frameStore === null ) { return false; }
|
||||
return frameStore.shouldApplySpecificCosmeticFilters(this.tabId);
|
||||
}
|
||||
|
||||
shouldApplyGenericCosmeticFilters(frameId) {
|
||||
if ( this.shouldApplyCosmeticFilters(-1) === false ) { return false; }
|
||||
const frameStore = this.getFrameStore(frameId);
|
||||
if ( frameStore === null ) { return false; }
|
||||
return frameStore.shouldApplyGenericCosmeticFilters(this.tabId);
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2105
|
||||
// Be sure to always include the current page's hostname -- it might not
|
||||
// be present when the page itself is pulled from the browser's
|
||||
|
|
|
@ -378,6 +378,7 @@ const filterTypes = {
|
|||
const cosmeticFilterFromElement = function(elem) {
|
||||
if ( elem === null ) { return 0; }
|
||||
if ( elem.nodeType !== 1 ) { return 0; }
|
||||
if ( noCosmeticFiltering ) { return 0; }
|
||||
|
||||
if ( candidateElements.indexOf(elem) === -1 ) {
|
||||
candidateElements.push(elem);
|
||||
|
@ -709,6 +710,7 @@ const filterToDOMInterface = (( ) => {
|
|||
// https://github.com/gorhill/uBlock/issues/2515
|
||||
// Remove trailing pseudo-element when querying.
|
||||
const fromCompiledCosmeticFilter = function(raw) {
|
||||
if ( noCosmeticFiltering ) { return; }
|
||||
if ( typeof raw !== 'string' ) { return; }
|
||||
let elems, style;
|
||||
try {
|
||||
|
@ -798,7 +800,7 @@ const filterToDOMInterface = (( ) => {
|
|||
if ( permanent === false || reCosmeticAnchor.test(lastFilter) === false ) {
|
||||
return apply();
|
||||
}
|
||||
if ( vAPI.domFilterer instanceof Object === false ) { return; }
|
||||
if ( noCosmeticFiltering ) { return; }
|
||||
const cssSelectors = new Set();
|
||||
const proceduralSelectors = new Set();
|
||||
for ( const { raw } of lastResultset ) {
|
||||
|
@ -886,7 +888,15 @@ const elementFromPoint = (( ) => {
|
|||
const magicAttr = `${vAPI.sessionId}-clickblind`;
|
||||
pickerRoot.setAttribute(magicAttr, '');
|
||||
let elem = document.elementFromPoint(x, y);
|
||||
if ( elem === document.body || elem === document.documentElement ) {
|
||||
if (
|
||||
elem === null || /* to skip following tests */
|
||||
elem === document.body ||
|
||||
elem === document.documentElement || (
|
||||
pickerBootArgs.zap !== true &&
|
||||
noCosmeticFiltering &&
|
||||
resourceURLsFromElement(elem).length === 0
|
||||
)
|
||||
) {
|
||||
elem = null;
|
||||
}
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/380
|
||||
|
@ -1013,6 +1023,7 @@ const startPicker = function() {
|
|||
// Try using mouse position
|
||||
if (
|
||||
pickerBootArgs.mouse &&
|
||||
vAPI.mouseClick instanceof Object &&
|
||||
typeof vAPI.mouseClick.x === 'number' &&
|
||||
vAPI.mouseClick.x > 0
|
||||
) {
|
||||
|
@ -1046,9 +1057,15 @@ const startPicker = function() {
|
|||
if ( (src !== url) && (src !== '' || url !== 'about:blank') ) {
|
||||
continue;
|
||||
}
|
||||
elem.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
filtersFrom(elem);
|
||||
return showDialog({ broad: true });
|
||||
if (
|
||||
netFilterCandidates.length !== 0 ||
|
||||
cosmeticFilterCandidates.length !== 0
|
||||
) {
|
||||
elem.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
showDialog({ broad: true });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// A target was specified, but it wasn't found: abort.
|
||||
|
@ -1193,12 +1210,9 @@ const onConnectionMessage = function(msg) {
|
|||
}
|
||||
|
||||
// The DOM filterer will not be present when cosmetic filtering is disabled.
|
||||
if (
|
||||
pickerBootArgs.zap !== true &&
|
||||
vAPI.domFilterer instanceof Object === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const noCosmeticFiltering =
|
||||
vAPI.domFilterer instanceof Object === false ||
|
||||
vAPI.noSpecificCosmeticFiltering === true;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1529
|
||||
// In addition to inline styles, harden the element picker styles by using
|
||||
|
|
Loading…
Reference in New Issue