1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-16 15:33:38 +01:00

Keep moving related scriptlets into separate files

This commit is contained in:
Raymond Hill 2024-11-08 11:22:31 -05:00
parent ce4908b341
commit e5a088738d
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
8 changed files with 350 additions and 339 deletions

View File

@ -22,6 +22,7 @@
web page context.
*/
import { registerScriptlet } from './base.js';
import { runAt } from './run-at.js';
import { safeSelf } from './safe-self.js';
@ -95,13 +96,13 @@ export function setAttrFn(
};
runAt(( ) => { start(); }, 'idle');
}
setAttrFn.details = {
registerScriptlet(setAttrFn, {
name: 'set-attr.fn',
dependencies: [
runAt,
safeSelf,
],
};
});
/**
* @scriptlet set-attr
@ -149,14 +150,14 @@ export function setAttr(
setAttrFn(logPrefix, selector, attr, value);
}
setAttr.details = {
registerScriptlet(setAttr, {
name: 'set-attr.js',
dependencies: [
safeSelf,
setAttrFn,
],
world: 'ISOLATED',
};
});
/**
* @trustedScriptlet trusted-set-attr
@ -188,7 +189,7 @@ export function trustedSetAttr(
const logPrefix = safe.makeLogPrefix('trusted-set-attr', selector, attr, value);
setAttrFn(logPrefix, selector, attr, value);
}
trustedSetAttr.details = {
registerScriptlet(trustedSetAttr, {
name: 'trusted-set-attr.js',
requiresTrust: true,
dependencies: [
@ -196,7 +197,7 @@ trustedSetAttr.details = {
setAttrFn,
],
world: 'ISOLATED',
};
});
/**
* @scriptlet remove-attr
@ -291,7 +292,7 @@ export function removeAttr(
};
runAt(( ) => { start(); }, behavior.split(/\s+/));
}
removeAttr.details = {
registerScriptlet(removeAttr, {
name: 'remove-attr.js',
aliases: [
'ra.js',
@ -300,6 +301,6 @@ removeAttr.details = {
runAt,
safeSelf,
],
};
});
/******************************************************************************/

40
assets/resources/base.js Normal file
View File

@ -0,0 +1,40 @@
/*******************************************************************************
uBlock Origin - a comprehensive, efficient content blocker
Copyright (C) 2019-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
The scriptlets below are meant to be injected only into a
web page context.
*/
export const registeredScriptlets = [];
export const registerScriptlet = (fn, details) => {
if ( typeof details !== 'object' ) {
throw new ReferenceError('Missing scriptlet details');
}
details.fn = fn;
fn.details = details;
if ( Array.isArray(details.dependencies) ) {
details.dependencies.forEach((fn, i, array) => {
if ( typeof fn !== 'function' ) { return; }
array[i] = fn.details.name;
});
}
registeredScriptlets.push(details);
};

View File

@ -22,6 +22,7 @@
web page context.
*/
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
/******************************************************************************/
@ -47,9 +48,9 @@ export function getSafeCookieValuesFn() {
'yes', 'y', 'no', 'n',
];
}
getSafeCookieValuesFn.details = {
registerScriptlet(getSafeCookieValuesFn, {
name: 'get-safe-cookie-values.fn',
};
});
/******************************************************************************/
@ -63,9 +64,9 @@ export function getAllCookiesFn() {
return { key, value };
}).filter(s => s !== undefined);
}
getAllCookiesFn.details = {
registerScriptlet(getAllCookiesFn, {
name: 'get-all-cookies.fn',
};
});
/******************************************************************************/
@ -79,9 +80,9 @@ export function getCookieFn(
return s.slice(pos+1).trim();
}
}
getCookieFn.details = {
registerScriptlet(getCookieFn, {
name: 'get-cookie.fn',
};
});
/******************************************************************************/
@ -142,12 +143,12 @@ export function setCookieFn(
return done;
}
setCookieFn.details = {
registerScriptlet(setCookieFn, {
name: 'set-cookie.fn',
dependencies: [
'get-cookie.fn',
getCookieFn,
],
};
});
/**
* @scriptlet set-cookie
@ -200,27 +201,27 @@ export function setCookie(
safe.uboLog(logPrefix, 'Done');
}
}
setCookie.details = {
registerScriptlet(setCookie, {
name: 'set-cookie.js',
world: 'ISOLATED',
dependencies: [
'get-safe-cookie-values.fn',
'safe-self.fn',
'set-cookie.fn',
getSafeCookieValuesFn,
safeSelf,
setCookieFn,
],
};
});
// For compatibility with AdGuard
export function setCookieReload(name, value, path, ...args) {
setCookie(name, value, path, 'reload', '1', ...args);
}
setCookieReload.details = {
registerScriptlet(setCookieReload, {
name: 'set-cookie-reload.js',
world: 'ISOLATED',
dependencies: [
'set-cookie.js',
setCookie,
],
};
});
/**
* @trustedScriptlet trusted-set-cookie
@ -294,28 +295,28 @@ export function trustedSetCookie(
safe.uboLog(logPrefix, 'Done');
}
}
trustedSetCookie.details = {
registerScriptlet(trustedSetCookie, {
name: 'trusted-set-cookie.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
'safe-self.fn',
'set-cookie.fn',
safeSelf,
setCookieFn,
],
};
});
// For compatibility with AdGuard
export function trustedSetCookieReload(name, value, offsetExpiresSec, path, ...args) {
trustedSetCookie(name, value, offsetExpiresSec, path, 'reload', '1', ...args);
}
trustedSetCookieReload.details = {
registerScriptlet(trustedSetCookieReload, {
name: 'trusted-set-cookie-reload.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
'trusted-set-cookie.js',
trustedSetCookie,
],
};
});
/**
* @scriptlet remove-cookie
@ -396,15 +397,15 @@ export function removeCookie(
}, { passive: true });
}
}
removeCookie.details = {
registerScriptlet(removeCookie, {
name: 'remove-cookie.js',
aliases: [
'cookie-remover.js',
],
world: 'ISOLATED',
dependencies: [
'safe-self.fn',
safeSelf,
],
};
});
/******************************************************************************/

View File

@ -0,0 +1,237 @@
/*******************************************************************************
uBlock Origin - a comprehensive, efficient content blocker
Copyright (C) 2019-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
The scriptlets below are meant to be injected only into a
web page context.
*/
import { getSafeCookieValuesFn } from './cookie.js';
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
/******************************************************************************/
export function getAllLocalStorageFn(which = 'localStorage') {
const storage = self[which];
const out = [];
for ( let i = 0; i < storage.length; i++ ) {
const key = storage.key(i);
const value = storage.getItem(key);
return { key, value };
}
return out;
}
registerScriptlet(getAllLocalStorageFn, {
name: 'get-all-local-storage.fn',
});
/******************************************************************************/
export function setLocalStorageItemFn(
which = 'local',
trusted = false,
key = '',
value = '',
) {
if ( key === '' ) { return; }
// For increased compatibility with AdGuard
if ( value === 'emptyArr' ) {
value = '[]';
} else if ( value === 'emptyObj' ) {
value = '{}';
}
const trustedValues = [
'',
'undefined', 'null',
'{}', '[]', '""',
'$remove$',
...getSafeCookieValuesFn(),
];
if ( trusted ) {
if ( value.includes('$now$') ) {
value = value.replaceAll('$now$', Date.now());
}
if ( value.includes('$currentDate$') ) {
value = value.replaceAll('$currentDate$', `${Date()}`);
}
if ( value.includes('$currentISODate$') ) {
value = value.replaceAll('$currentISODate$', (new Date()).toISOString());
}
} else {
const normalized = value.toLowerCase();
const match = /^("?)(.+)\1$/.exec(normalized);
const unquoted = match && match[2] || normalized;
if ( trustedValues.includes(unquoted) === false ) {
if ( /^-?\d+$/.test(unquoted) === false ) { return; }
const n = parseInt(unquoted, 10) || 0;
if ( n < -32767 || n > 32767 ) { return; }
}
}
try {
const storage = self[`${which}Storage`];
if ( value === '$remove$' ) {
const safe = safeSelf();
const pattern = safe.patternToRegex(key, undefined, true );
const toRemove = [];
for ( let i = 0, n = storage.length; i < n; i++ ) {
const key = storage.key(i);
if ( pattern.test(key) ) { toRemove.push(key); }
}
for ( const key of toRemove ) {
storage.removeItem(key);
}
} else {
storage.setItem(key, `${value}`);
}
} catch(ex) {
}
}
registerScriptlet(setLocalStorageItemFn, {
name: 'set-local-storage-item.fn',
dependencies: [
getSafeCookieValuesFn,
safeSelf,
],
});
/******************************************************************************/
export function removeCacheStorageItem(
cacheNamePattern = '',
requestPattern = ''
) {
if ( cacheNamePattern === '' ) { return; }
const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern);
const cacheStorage = self.caches;
if ( cacheStorage instanceof Object === false ) { return; }
const reCache = safe.patternToRegex(cacheNamePattern, undefined, true);
const reRequest = safe.patternToRegex(requestPattern, undefined, true);
cacheStorage.keys().then(cacheNames => {
for ( const cacheName of cacheNames ) {
if ( reCache.test(cacheName) === false ) { continue; }
if ( requestPattern === '' ) {
cacheStorage.delete(cacheName).then(result => {
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}`);
}
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`);
});
continue;
}
cacheStorage.open(cacheName).then(cache => {
cache.keys().then(requests => {
for ( const request of requests ) {
if ( reRequest.test(request.url) === false ) { continue; }
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`);
}
cache.delete(request).then(result => {
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`);
});
}
});
});
}
});
}
registerScriptlet(removeCacheStorageItem, {
name: 'remove-cache-storage-item.fn',
world: 'ISOLATED',
dependencies: [
safeSelf,
],
});
/*******************************************************************************
*
* set-local-storage-item.js
* set-session-storage-item.js
*
* Set a local/session storage entry to a specific, allowed value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js
*
**/
export function setLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', false, key, value);
}
registerScriptlet(setLocalStorageItem, {
name: 'set-local-storage-item.js',
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
export function setSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', false, key, value);
}
registerScriptlet(setSessionStorageItem, {
name: 'set-session-storage-item.js',
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
/*******************************************************************************
*
* trusted-set-local-storage-item.js
*
* Set a local storage entry to an arbitrary value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js
*
**/
export function trustedSetLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', true, key, value);
}
registerScriptlet(trustedSetLocalStorageItem, {
name: 'trusted-set-local-storage-item.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});
export function trustedSetSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', true, key, value);
}
registerScriptlet(trustedSetSessionStorageItem, {
name: 'trusted-set-session-storage-item.js',
requiresTrust: true,
world: 'ISOLATED',
dependencies: [
setLocalStorageItemFn,
],
});

View File

@ -22,6 +22,7 @@
web page context.
*/
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
/* eslint no-prototype-builtins: 0 */
@ -72,9 +73,26 @@ export function runAt(fn, when) {
const args = [ 'readystatechange', onStateChange, { capture: true } ];
safe.addEventListener.apply(document, args);
}
runAt.details = {
registerScriptlet(runAt, {
name: 'run-at.fn',
dependencies: [
safeSelf,
],
};
});
/******************************************************************************/
function runAtHtmlElementFn(fn) {
if ( document.documentElement ) {
fn();
return;
}
const observer = new MutationObserver(( ) => {
observer.disconnect();
fn();
});
observer.observe(document, { childList: true });
}
registerScriptlet(runAtHtmlElementFn, {
name: 'run-at-html-element.fn',
});

View File

@ -22,6 +22,8 @@
web page context.
*/
import { registerScriptlet } from './base.js';
/******************************************************************************/
// Externally added to the private namespace in which scriptlets execute.
@ -213,6 +215,6 @@ export function safeSelf() {
}
return safe;
}
safeSelf.details = {
registerScriptlet(safeSelf, {
name: 'safe-self.fn',
};
});

View File

@ -22,70 +22,24 @@
web page context.
*/
import {
getAllCookiesFn,
getCookieFn,
getSafeCookieValuesFn,
removeCookie,
setCookie,
setCookieFn,
setCookieReload,
trustedSetCookie,
trustedSetCookieReload,
} from './cookie.js';
import {
removeAttr,
setAttr,
setAttrFn,
trustedSetAttr,
} from './attribute.js';
import './attribute.js';
import './cookie.js';
import './localstorage.js';
import './run-at.js';
import './safe-self.js';
import { getAllCookiesFn } from './cookie.js';
import { getAllLocalStorageFn } from './localstorage.js';
import { registeredScriptlets } from './base.js';
import { runAt } from './run-at.js';
import { safeSelf } from './safe-self.js';
/* eslint no-prototype-builtins: 0 */
// Externally added to the private namespace in which scriptlets execute.
/* global scriptletGlobals */
export const builtinScriptlets = [];
/* eslint no-prototype-builtins: 0 */
/******************************************************************************/
// Register scriptlets declared in other files.
const registerScriptlet = fn => {
const details = fn.details;
if ( typeof details !== 'object' ) {
throw new ReferenceError('Unknown scriptlet function');
}
details.fn = fn;
if ( Array.isArray(details.dependencies) ) {
details.dependencies.forEach((fn, i, array) => {
if ( typeof fn !== 'function' ) { return; }
array[i] = fn.details.name;
});
}
builtinScriptlets.push(details);
};
registerScriptlet(safeSelf);
registerScriptlet(removeAttr);
registerScriptlet(setAttrFn);
registerScriptlet(setAttr);
registerScriptlet(trustedSetAttr);
registerScriptlet(getAllCookiesFn);
registerScriptlet(getCookieFn);
registerScriptlet(getSafeCookieValuesFn);
registerScriptlet(removeCookie);
registerScriptlet(setCookie);
registerScriptlet(setCookieFn);
registerScriptlet(setCookieReload);
registerScriptlet(trustedSetCookie);
registerScriptlet(trustedSetCookieReload);
export const builtinScriptlets = registeredScriptlets;
/*******************************************************************************
@ -141,34 +95,6 @@ function shouldDebug(details) {
/******************************************************************************/
builtinScriptlets.push({
name: 'run-at.fn',
fn: runAt,
dependencies: [
'safe-self.fn',
],
});
/******************************************************************************/
builtinScriptlets.push({
name: 'run-at-html-element.fn',
fn: runAtHtmlElementFn,
});
function runAtHtmlElementFn(fn) {
if ( document.documentElement ) {
fn();
return;
}
const observer = new MutationObserver(( ) => {
observer.disconnect();
fn();
});
observer.observe(document, { childList: true });
}
/******************************************************************************/
// Reference:
// https://github.com/AdguardTeam/Scriptlets/blob/master/wiki/about-scriptlets.md#prevent-xhr
//
@ -823,97 +749,6 @@ function objectFindOwnerFn(
/******************************************************************************/
builtinScriptlets.push({
name: 'get-all-local-storage.fn',
fn: getAllLocalStorageFn,
});
function getAllLocalStorageFn(which = 'localStorage') {
const storage = self[which];
const out = [];
for ( let i = 0; i < storage.length; i++ ) {
const key = storage.key(i);
const value = storage.getItem(key);
return { key, value };
}
return out;
}
/******************************************************************************/
builtinScriptlets.push({
name: 'set-local-storage-item.fn',
fn: setLocalStorageItemFn,
dependencies: [
'get-safe-cookie-values.fn',
'safe-self.fn',
],
});
function setLocalStorageItemFn(
which = 'local',
trusted = false,
key = '',
value = '',
) {
if ( key === '' ) { return; }
// For increased compatibility with AdGuard
if ( value === 'emptyArr' ) {
value = '[]';
} else if ( value === 'emptyObj' ) {
value = '{}';
}
const trustedValues = [
'',
'undefined', 'null',
'{}', '[]', '""',
'$remove$',
...getSafeCookieValuesFn(),
];
if ( trusted ) {
if ( value.includes('$now$') ) {
value = value.replaceAll('$now$', Date.now());
}
if ( value.includes('$currentDate$') ) {
value = value.replaceAll('$currentDate$', `${Date()}`);
}
if ( value.includes('$currentISODate$') ) {
value = value.replaceAll('$currentISODate$', (new Date()).toISOString());
}
} else {
const normalized = value.toLowerCase();
const match = /^("?)(.+)\1$/.exec(normalized);
const unquoted = match && match[2] || normalized;
if ( trustedValues.includes(unquoted) === false ) {
if ( /^\d+$/.test(unquoted) === false ) { return; }
const n = parseInt(unquoted, 10);
if ( n > 32767 ) { return; }
}
}
try {
const storage = self[`${which}Storage`];
if ( value === '$remove$' ) {
const safe = safeSelf();
const pattern = safe.patternToRegex(key, undefined, true );
const toRemove = [];
for ( let i = 0, n = storage.length; i < n; i++ ) {
const key = storage.key(i);
if ( pattern.test(key) ) { toRemove.push(key); }
}
for ( const key of toRemove ) {
storage.removeItem(key);
}
} else {
storage.setItem(key, `${value}`);
}
} catch(ex) {
}
}
/******************************************************************************/
builtinScriptlets.push({
name: 'matches-stack-trace.fn',
fn: matchesStackTrace,
@ -3569,43 +3404,6 @@ function removeNodeText(
replaceNodeTextFn(nodeName, '', '', 'includes', includes || '', ...extraArgs);
}
/*******************************************************************************
*
* set-local-storage-item.js
* set-session-storage-item.js
*
* Set a local/session storage entry to a specific, allowed value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-local-storage-item.js
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/set-session-storage-item.js
*
**/
builtinScriptlets.push({
name: 'set-local-storage-item.js',
fn: setLocalStorageItem,
world: 'ISOLATED',
dependencies: [
'set-local-storage-item.fn',
],
});
function setLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', false, key, value);
}
builtinScriptlets.push({
name: 'set-session-storage-item.js',
fn: setSessionStorageItem,
world: 'ISOLATED',
dependencies: [
'set-local-storage-item.fn',
],
});
function setSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', false, key, value);
}
/*******************************************************************************
*
* @scriptlet prevent-canvas
@ -3693,57 +3491,6 @@ function multiup() {
document.addEventListener('click', handler, { capture: true });
}
/******************************************************************************/
builtinScriptlets.push({
name: 'remove-cache-storage-item.js',
fn: removeCacheStorageItem,
world: 'ISOLATED',
dependencies: [
'safe-self.fn',
],
});
function removeCacheStorageItem(
cacheNamePattern = '',
requestPattern = ''
) {
if ( cacheNamePattern === '' ) { return; }
const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern);
const cacheStorage = self.caches;
if ( cacheStorage instanceof Object === false ) { return; }
const reCache = safe.patternToRegex(cacheNamePattern, undefined, true);
const reRequest = safe.patternToRegex(requestPattern, undefined, true);
cacheStorage.keys().then(cacheNames => {
for ( const cacheName of cacheNames ) {
if ( reCache.test(cacheName) === false ) { continue; }
if ( requestPattern === '' ) {
cacheStorage.delete(cacheName).then(result => {
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}`);
}
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`);
});
continue;
}
cacheStorage.open(cacheName).then(cache => {
cache.keys().then(requests => {
for ( const request of requests ) {
if ( reRequest.test(request.url) === false ) { continue; }
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`);
}
cache.delete(request).then(result => {
if ( result !== true ) { return; }
safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`);
});
}
});
});
}
});
}
/*******************************************************************************
@ -3831,43 +3578,6 @@ function trustedSetConstant(
setConstantFn(true, ...args);
}
/*******************************************************************************
*
* trusted-set-local-storage-item.js
*
* Set a local storage entry to an arbitrary value.
*
* Reference:
* https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-set-local-storage-item.js
*
**/
builtinScriptlets.push({
name: 'trusted-set-local-storage-item.js',
requiresTrust: true,
fn: trustedSetLocalStorageItem,
world: 'ISOLATED',
dependencies: [
'set-local-storage-item.fn',
],
});
function trustedSetLocalStorageItem(key = '', value = '') {
setLocalStorageItemFn('local', true, key, value);
}
builtinScriptlets.push({
name: 'trusted-set-session-storage-item.js',
requiresTrust: true,
fn: trustedSetSessionStorageItem,
world: 'ISOLATED',
dependencies: [
'set-local-storage-item.fn',
],
});
function trustedSetSessionStorageItem(key = '', value = '') {
setLocalStorageItemFn('session', true, key, value);
}
/*******************************************************************************
*
* trusted-replace-fetch-response.js

View File

@ -333,6 +333,8 @@ class RedirectEngine {
}
}
this.modifyTime = Date.now();
}).catch(reason => {
console.error(reason);
}),
];