-
Notifications
You must be signed in to change notification settings - Fork 13
Fork Sync: Update from parent repository #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
MS store validator rejects those rules in static rulesets.
Related discussion: uBlockOrigin/uBlock-issues#3878
- Make place for more dynamic regex-based rules when there is a risk session regex-based rules could interfere - Do not prune `allow` strict-block rules as they do not contribute toward the overall regex-based rule count Possibly related issue: uBlockOrigin/uBOL-home#556
@Scriptlet prevent-dialog @description Programmatically close `dialog` elements. @param [selector] Optional. The dialog element must matches `dialog{selector}` for the prevention to take place. @Usage: example.com##+js(prevent-dialog)
|
[puLL-Merge] - brave/uBlock@301 Diffdiff --git src/js/redirect-resources.js src/js/redirect-resources.js
index f1dd5c27ded58..26cb0b6540bb4 100644
--- src/js/redirect-resources.js
+++ src/js/redirect-resources.js
@@ -190,4 +190,7 @@ export default new Map([
[ 'scorecardresearch_beacon.js', {
alias: 'scorecardresearch.com/beacon.js',
} ],
+ [ 'sensors-analytics.js', {
+ data: 'text',
+ } ],
]);
diff --git src/js/resources/json-edit.js src/js/resources/json-edit.js
index e5d72c60772aa..a95bc8c63921c 100644
--- src/js/resources/json-edit.js
+++ src/js/resources/json-edit.js
@@ -193,6 +193,7 @@ function editInboundObjectFn(
const argPos = parseInt(argPosRaw, 10);
if ( isNaN(argPos) ) { return; }
const getArgPos = args => {
+ if ( Array.isArray(args) === false ) { return; }
if ( argPos >= 0 ) {
if ( args.length <= argPos ) { return; }
return argPos;
--- /dev/null
+++ src/js/resources/prevent-dialog.js
@@ -0,0 +1,72 @@
+/*******************************************************************************
+
+ uBlock Origin - a comprehensive, efficient content blocker
+ Copyright (C) 2025-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
+
+*/
+
+import { registerScriptlet } from './base.js';
+import { safeSelf } from './safe-self.js';
+
+/**
+ * @scriptlet prevent-dialog
+ *
+ * @description
+ * Programmatically close `dialog` elements.
+ *
+ * @param [selector]
+ * Optional. The dialog element must matches `dialog{selector}` for the
+ * prevention to take place.
+ *
+ * @usage:
+ * example.com##+js(prevent-dialog)
+ *
+ * */
+
+export function preventDialog(
+ selector = '',
+) {
+ const safe = safeSelf();
+ const logPrefix = safe.makeLogPrefix('prevent-dialog', selector);
+ const prevent = ( ) => {
+ debouncer = undefined;
+ const elems = document.querySelectorAll(`dialog${selector}`);
+ for ( const elem of elems ) {
+ if ( typeof elem.close !== 'function' ) { continue; }
+ if ( elem.open === false ) { continue; }
+ elem.close();
+ safe.uboLog(logPrefix, 'Closed');
+ }
+ };
+ let debouncer;
+ const observer = new MutationObserver(( ) => {
+ if ( debouncer !== undefined ) { return; }
+ debouncer = requestAnimationFrame(prevent);
+ });
+ observer.observe(document, {
+ attributes: true,
+ childList: true,
+ subtree: true,
+ });
+}
+registerScriptlet(preventDialog, {
+ name: 'prevent-dialog.js',
+ dependencies: [
+ safeSelf,
+ ],
+});
diff --git src/js/resources/prevent-fetch.js src/js/resources/prevent-fetch.js
index ba2565a69b48b..5bf03e0818f95 100644
--- src/js/resources/prevent-fetch.js
+++ src/js/resources/prevent-fetch.js
@@ -20,7 +20,11 @@
*/
-import { generateContentFn } from './utils.js';
+import {
+ generateContentFn,
+ matchObjectPropertiesFn,
+ parsePropertiesToMatchFn,
+} from './utils.js';
import { proxyApplyFn } from './proxy-apply.js';
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
@@ -43,20 +47,7 @@ function preventFetchFn(
responseType
);
const extraArgs = safe.getExtraArgs(Array.from(arguments), 4);
- const needles = [];
- for ( const condition of safe.String_split.call(propsToMatch, /\s+/) ) {
- if ( condition === '' ) { continue; }
- const pos = condition.indexOf(':');
- let key, value;
- if ( pos !== -1 ) {
- key = condition.slice(0, pos);
- value = condition.slice(pos + 1);
- } else {
- key = 'url';
- value = condition;
- }
- needles.push({ key, pattern: safe.initPattern(value, { canNegate: true }) });
- }
+ const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url');
const validResponseProps = {
ok: [ false, true ],
statusText: [ '', 'Not Found' ],
@@ -84,43 +75,41 @@ function preventFetchFn(
responseProps.type = { value: responseType };
}
}
+ const fetchProps = (src, out) => {
+ if ( typeof src !== 'object' || src === null ) { return; }
+ const props = [
+ 'body', 'cache', 'credentials', 'duplex', 'headers',
+ 'integrity', 'keepalive', 'method', 'mode', 'priority',
+ 'redirect', 'referrer', 'referrerPolicy', 'signal',
+ ];
+ for ( const prop of props ) {
+ if ( src[prop] === undefined ) { continue; }
+ out[prop] = src[prop];
+ }
+ };
+ const fetchDetails = args => {
+ const out = {};
+ if ( args[0] instanceof self.Request ) {
+ out.url = `${args[0].url}`;
+ fetchProps(args[0], out);
+ } else {
+ out.url = `${args[0]}`;
+ }
+ fetchProps(args[1], out);
+ return out;
+ };
proxyApplyFn('fetch', function fetch(context) {
const { callArgs } = context;
- const details = callArgs[0] instanceof self.Request
- ? callArgs[0]
- : Object.assign({ url: callArgs[0] }, callArgs[1]);
- let proceed = true;
- try {
- const props = new Map();
- for ( const prop in details ) {
- let v = details[prop];
- if ( typeof v !== 'string' ) {
- try { v = safe.JSON_stringify(v); }
- catch { }
- }
- if ( typeof v !== 'string' ) { continue; }
- props.set(prop, v);
- }
- if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
- const out = Array.from(props).map(a => `${a[0]}:${a[1]}`);
- safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
- }
- if ( propsToMatch === '' && responseBody === '' ) {
- return context.reflect();
- }
- proceed = needles.length === 0;
- for ( const { key, pattern } of needles ) {
- if (
- pattern.expect && props.has(key) === false ||
- safe.testPattern(pattern, props.get(key)) === false
- ) {
- proceed = true;
- break;
- }
- }
- } catch {
+ const details = fetchDetails(callArgs);
+ if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
+ const out = Array.from(Object.entries(details)).map(a => `${a[0]}:${a[1]}`);
+ safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
+ }
+ if ( propsToMatch === '' && responseBody === '' ) {
+ return context.reflect();
}
- if ( proceed ) {
+ const matched = matchObjectPropertiesFn(propNeedles, details);
+ if ( matched === undefined || matched.length === 0 ) {
return context.reflect();
}
return Promise.resolve(generateContentFn(trusted, responseBody)).then(text => {
@@ -148,6 +137,8 @@ registerScriptlet(preventFetchFn, {
name: 'prevent-fetch.fn',
dependencies: [
generateContentFn,
+ matchObjectPropertiesFn,
+ parsePropertiesToMatchFn,
proxyApplyFn,
safeSelf,
],
diff --git src/js/resources/replace-argument.js src/js/resources/replace-argument.js
index 62867cbf261d0..1a305389bf5ce 100644
--- src/js/resources/replace-argument.js
+++ src/js/resources/replace-argument.js
@@ -72,6 +72,7 @@ export function trustedReplaceArgument(
const parsed = parseReplaceFn(argraw.slice(5));
if ( parsed === undefined ) { return; }
replacer = arg => `${arg}`.replace(replacer.re, replacer.replacement);
+ Object.assign(replacer, parsed);
} else if ( argraw.startsWith('add:') ) {
const delta = parseFloat(argraw.slice(4));
if ( isNaN(delta) ) { return; }
diff --git src/js/resources/scriptlets.js src/js/resources/scriptlets.js
index 19fc628d51739..c935fdb9e92db 100755
--- src/js/resources/scriptlets.js
+++ src/js/resources/scriptlets.js
@@ -27,6 +27,7 @@ import './json-edit.js';
import './json-prune.js';
import './noeval.js';
import './object-prune.js';
+import './prevent-dialog.js';
import './prevent-fetch.js';
import './prevent-innerHTML.js';
import './prevent-settimeout.js';
@@ -1589,6 +1590,7 @@ builtinScriptlets.push({
name: 'm3u-prune.js',
fn: m3uPrune,
dependencies: [
+ 'proxy-apply.fn',
'safe-self.fn',
],
});
@@ -1704,28 +1706,30 @@ function m3uPrune(
if ( arg instanceof Request ) { return arg.url; }
return String(arg);
};
- const realFetch = self.fetch;
- self.fetch = new Proxy(self.fetch, {
- apply: function(target, thisArg, args) {
- if ( reUrl.test(urlFromArg(args[0])) === false ) {
- return Reflect.apply(target, thisArg, args);
- }
- return realFetch(...args).then(realResponse =>
- realResponse.text().then(text => {
- const response = new Response(pruner(text), {
- status: realResponse.status,
- statusText: realResponse.statusText,
- headers: realResponse.headers,
- });
- if ( toLog.length !== 0 ) {
- toLog.unshift(logPrefix);
- safe.uboLog(toLog.join('\n'));
- }
- return response;
- })
- );
+ proxyApplyFn('fetch', async function fetch(context) {
+ const args = context.callArgs;
+ const fetchPromise = context.reflect();
+ if ( reUrl.test(urlFromArg(args[0])) === false ) { return fetchPromise; }
+ const responseBefore = await fetchPromise;
+ const responseClone = responseBefore.clone();
+ const textBefore = await responseClone.text();
+ const textAfter = pruner(textBefore);
+ if ( textAfter === textBefore ) { return responseBefore; }
+ const responseAfter = new Response(textAfter, {
+ status: responseBefore.status,
+ statusText: responseBefore.statusText,
+ headers: responseBefore.headers,
+ });
+ Object.defineProperties(responseAfter, {
+ url: { value: responseBefore.url },
+ type: { value: responseBefore.type },
+ });
+ if ( toLog.length !== 0 ) {
+ toLog.unshift(logPrefix);
+ safe.uboLog(toLog.join('\n'));
}
- });
+ return responseAfter;
+ })
self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, {
apply: async (target, thisArg, args) => {
if ( reUrl.test(urlFromArg(args[1])) === false ) {
--- /dev/null
+++ src/web_accessible_resources/sensors-analytics.js
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+ uBlock Origin - a browser extension to block requests.
+ Copyright (C) 2025-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
+*/
+
+(function() {
+ 'use strict';
+ const noopfn = function() {
+ };
+ window.sensorsDataAnalytic201505 = {
+ init: noopfn,
+ quick: noopfn,
+ register: noopfn,
+ track: noopfn,
+ };
+})();
DescriptionThis PR adds and enhances several scriptlets for content blocking in uBlock Origin:
The changes improve code maintainability by consolidating property matching logic and add new blocking capabilities for unwanted UI elements and analytics. Possible Issues
Security Hotspots
Privacy Hotspots
ChangesChangessrc/js/redirect-resources.js
src/js/resources/json-edit.js
src/js/resources/prevent-dialog.js (New File)
src/js/resources/prevent-fetch.js
src/js/resources/replace-argument.js
src/js/resources/scriptlets.js
|
This PR was automatically created by a GitHub Action triggered by a cron schedule. Please review the changes and merge if appropriate.