mirror of https://github.com/gorhill/uBlock.git
Further modularize uBO's codebase
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1664 Modularization is a necessary step toward possibly publishing a more complete nodejs package to allow using uBO's filtering capabilities outside of the uBO extension. Additionally, as per feedback, remove undue usage of console output as per feedback: - https://github.com/uBlockOrigin/uBlock-issues/issues/1664#issuecomment-888451032
This commit is contained in:
parent
d7cd6d72f6
commit
62b6826dd5
|
@ -29,10 +29,10 @@ import './lib/punycode.js';
|
|||
import './lib/publicsuffixlist/publicsuffixlist.js';
|
||||
|
||||
import globals from './js/globals.js';
|
||||
import snfe from './js/static-net-filtering.js';
|
||||
import { FilteringContext } from './js/filtering-context.js';
|
||||
import { LineIterator } from './js/text-iterators.js';
|
||||
import { StaticFilteringParser } from './js/static-filtering-parser.js';
|
||||
import { staticNetFilteringEngine } from './js/static-net-filtering.js';
|
||||
|
||||
import {
|
||||
CompiledListReader,
|
||||
|
@ -41,33 +41,31 @@ import {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function compileList(rawText, writer) {
|
||||
function compileList(rawText, writer, options = {}) {
|
||||
const lineIter = new LineIterator(rawText);
|
||||
const parser = new StaticFilteringParser(true);
|
||||
const events = Array.isArray(options.events) ? options.events : undefined;
|
||||
|
||||
parser.setMaxTokenLength(staticNetFilteringEngine.MAX_TOKEN_LENGTH);
|
||||
parser.setMaxTokenLength(snfe.MAX_TOKEN_LENGTH);
|
||||
|
||||
while ( lineIter.eot() === false ) {
|
||||
let line = lineIter.next();
|
||||
|
||||
while ( line.endsWith(' \\') ) {
|
||||
if ( lineIter.peek(4) !== ' ' ) { break; }
|
||||
line = line.slice(0, -2).trim() + lineIter.next().trim();
|
||||
}
|
||||
parser.analyze(line);
|
||||
|
||||
if ( parser.shouldIgnore() ) { continue; }
|
||||
if ( parser.category !== parser.CATStaticNetFilter ) { continue; }
|
||||
if ( parser.patternHasUnicode() && parser.toASCII() === false ) {
|
||||
continue;
|
||||
}
|
||||
if ( staticNetFilteringEngine.compile(parser, writer) ) { continue; }
|
||||
if ( staticNetFilteringEngine.error !== undefined ) {
|
||||
console.info(JSON.stringify({
|
||||
realm: 'message',
|
||||
if ( snfe.compile(parser, writer) ) { continue; }
|
||||
if ( snfe.error !== undefined && events !== undefined ) {
|
||||
options.events.push({
|
||||
type: 'error',
|
||||
text: staticNetFilteringEngine.error
|
||||
}));
|
||||
text: snfe.error
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,13 +77,13 @@ function applyList(name, raw) {
|
|||
writer.properties.set('name', name);
|
||||
const compiled = compileList(raw, writer);
|
||||
const reader = new CompiledListReader(compiled);
|
||||
staticNetFilteringEngine.fromCompiled(reader);
|
||||
snfe.fromCompiled(reader);
|
||||
}
|
||||
|
||||
function enableWASM(path) {
|
||||
return Promise.all([
|
||||
globals.publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`),
|
||||
staticNetFilteringEngine.enableWASM(`${path}/js`),
|
||||
snfe.enableWASM(`${path}/js`),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -94,35 +92,32 @@ function pslInit(raw) {
|
|||
const require = createRequire(import.meta.url); // jshint ignore:line
|
||||
raw = require('./data/effective_tld_names.json');
|
||||
if ( typeof raw !== 'string' || raw.trim() === '' ) {
|
||||
console.info('Unable to populate public suffix list');
|
||||
console.error('Unable to populate public suffix list');
|
||||
return;
|
||||
}
|
||||
}
|
||||
globals.publicSuffixList.parse(raw, globals.punycode.toASCII);
|
||||
console.info('Public suffix list populated');
|
||||
}
|
||||
|
||||
function restart(lists) {
|
||||
function restart(lists, options = {}) {
|
||||
// Remove all filters
|
||||
reset();
|
||||
|
||||
if ( Array.isArray(lists) && lists.length !== 0 ) {
|
||||
// Populate filtering engine with filter lists
|
||||
for ( const { name, raw } of lists ) {
|
||||
applyList(name, raw);
|
||||
applyList(name, raw, options);
|
||||
}
|
||||
// Commit changes
|
||||
staticNetFilteringEngine.freeze();
|
||||
staticNetFilteringEngine.optimize();
|
||||
snfe.freeze();
|
||||
snfe.optimize();
|
||||
}
|
||||
|
||||
console.info('Static network filtering engine populated');
|
||||
|
||||
return staticNetFilteringEngine;
|
||||
return snfe;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
staticNetFilteringEngine.reset();
|
||||
snfe.reset();
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
@ -51,7 +51,7 @@ function fetch(listName) {
|
|||
}
|
||||
*/
|
||||
|
||||
pslInit();
|
||||
await pslInit();
|
||||
|
||||
const snfe = await Promise.all([
|
||||
fetch('easylist'),
|
||||
|
|
|
@ -5,37 +5,17 @@
|
|||
<title>uBlock Origin</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="js/console.js"></script>
|
||||
<script src="lib/lz4/lz4-block-codec-any.js"></script>
|
||||
<script src="js/webext.js"></script>
|
||||
<script src="js/vapi.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-background.js" type="module"></script>
|
||||
<script src="js/vapi-background-ext.js" type="module"></script><!-- platform-specific to extend common code paths -->
|
||||
<script src="js/background.js" type="module"></script>
|
||||
<script src="js/traffic.js" type="module"></script>
|
||||
<script src="js/utils.js" type="module"></script>
|
||||
<script src="js/lz4.js" type="module"></script>
|
||||
<script src="js/cachestorage.js" type="module"></script>
|
||||
<script src="js/assets.js" type="module"></script>
|
||||
<script src="js/redirect-engine.js" type="module"></script>
|
||||
<script src="js/dynamic-net-filtering.js" type="module"></script>
|
||||
<script src="js/url-net-filtering.js" type="module"></script>
|
||||
<script src="js/static-ext-filtering.js" type="module"></script>
|
||||
<script src="js/cosmetic-filtering.js" type="module"></script>
|
||||
<script src="js/scriptlet-filtering.js" type="module"></script>
|
||||
<script src="js/html-filtering.js" type="module"></script>
|
||||
<script src="js/httpheader-filtering.js" type="module"></script>
|
||||
<script src="js/hnswitches.js" type="module"></script>
|
||||
<script src="js/ublock.js" type="module"></script>
|
||||
<script src="js/storage.js" type="module"></script>
|
||||
<script src="js/logger.js" type="module"></script>
|
||||
<script src="js/pagestore.js" type="module"></script>
|
||||
<script src="js/tab.js" type="module"></script>
|
||||
<script src="js/messaging.js" type="module"></script>
|
||||
<script src="js/text-encode.js" type="module"></script>
|
||||
<script src="js/contextmenu.js" type="module"></script>
|
||||
<script src="js/reverselookup.js" type="module"></script>
|
||||
<script src="js/start.js" type="module"></script>
|
||||
<script src="js/commands.js" type="module"></script>
|
||||
</body>
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import cacheStorage from './cachestorage.js';
|
||||
import logger from './logger.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -31,7 +33,7 @@ const reIsExternalPath = /^(?:[a-z-]+):\/\//;
|
|||
const reIsUserAsset = /^user-/;
|
||||
const errorCantConnectTo = vAPI.i18n('errorCantConnectTo');
|
||||
|
||||
const api = {};
|
||||
const assets = {};
|
||||
|
||||
// A hint for various pieces of code to take measures if possible to save
|
||||
// bandwidth of remote servers.
|
||||
|
@ -41,13 +43,13 @@ let remoteServerFriendly = false;
|
|||
|
||||
const observers = [];
|
||||
|
||||
api.addObserver = function(observer) {
|
||||
assets.addObserver = function(observer) {
|
||||
if ( observers.indexOf(observer) === -1 ) {
|
||||
observers.push(observer);
|
||||
}
|
||||
};
|
||||
|
||||
api.removeObserver = function(observer) {
|
||||
assets.removeObserver = function(observer) {
|
||||
let pos;
|
||||
while ( (pos = observers.indexOf(observer)) !== -1 ) {
|
||||
observers.splice(pos, 1);
|
||||
|
@ -65,11 +67,11 @@ const fireNotification = function(topic, details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.fetch = function(url, options = {}) {
|
||||
assets.fetch = function(url, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Start of executor
|
||||
|
||||
const timeoutAfter = µBlock.hiddenSettings.assetFetchTimeout * 1000 || 30000;
|
||||
const timeoutAfter = µb.hiddenSettings.assetFetchTimeout * 1000 || 30000;
|
||||
const xhr = new XMLHttpRequest();
|
||||
let contentLoaded = 0;
|
||||
let timeoutTimer;
|
||||
|
@ -86,7 +88,7 @@ api.fetch = function(url, options = {}) {
|
|||
};
|
||||
|
||||
const fail = function(details, msg) {
|
||||
µBlock.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: msg,
|
||||
|
@ -154,7 +156,7 @@ api.fetch = function(url, options = {}) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.fetchText = async function(url) {
|
||||
assets.fetchText = async function(url) {
|
||||
const isExternal = reIsExternalPath.test(url);
|
||||
let actualUrl = isExternal ? url : vAPI.getURL(url);
|
||||
|
||||
|
@ -171,7 +173,7 @@ api.fetchText = async function(url) {
|
|||
// servers.
|
||||
if ( isExternal && remoteServerFriendly !== true ) {
|
||||
const cacheBypassToken =
|
||||
µBlock.hiddenSettings.updateAssetBypassBrowserCache
|
||||
µb.hiddenSettings.updateAssetBypassBrowserCache
|
||||
? Math.floor(Date.now() / 1000) % 86413
|
||||
: Math.floor(Date.now() / 3600000) % 13;
|
||||
const queryValue = `_=${cacheBypassToken}`;
|
||||
|
@ -185,7 +187,7 @@ api.fetchText = async function(url) {
|
|||
|
||||
let details = { content: '' };
|
||||
try {
|
||||
details = await api.fetch(actualUrl);
|
||||
details = await assets.fetch(actualUrl);
|
||||
|
||||
// Consider an empty result to be an error
|
||||
if ( stringIsNotEmpty(details.content) === false ) {
|
||||
|
@ -223,7 +225,7 @@ api.fetchText = async function(url) {
|
|||
// https://github.com/gorhill/uBlock/issues/3331
|
||||
// Support the seamless loading of sublists.
|
||||
|
||||
api.fetchFilterList = async function(mainlistURL) {
|
||||
assets.fetchFilterList = async function(mainlistURL) {
|
||||
const toParsedURL = url => {
|
||||
try {
|
||||
return new URL(url.trim());
|
||||
|
@ -265,7 +267,7 @@ api.fetchFilterList = async function(mainlistURL) {
|
|||
}
|
||||
if ( result instanceof Object === false ) { continue; }
|
||||
const content = result.content;
|
||||
const slices = µBlock.preparseDirectives.split(content);
|
||||
const slices = µb.preparseDirectives.split(content);
|
||||
for ( let i = 0, n = slices.length - 1; i < n; i++ ) {
|
||||
const slice = content.slice(slices[i+0], slices[i+1]);
|
||||
if ( (i & 1) !== 0 ) {
|
||||
|
@ -288,7 +290,7 @@ api.fetchFilterList = async function(mainlistURL) {
|
|||
out.push(
|
||||
slice.slice(lastIndex, match.index + match[0].length),
|
||||
`! >>>>>>>> ${subURL}\n`,
|
||||
api.fetchText(subURL),
|
||||
assets.fetchText(subURL),
|
||||
`! <<<<<<<< ${subURL}\n`
|
||||
);
|
||||
lastIndex = reInclude.lastIndex;
|
||||
|
@ -346,7 +348,7 @@ let assetSourceRegistryPromise,
|
|||
|
||||
const getAssetSourceRegistry = function() {
|
||||
if ( assetSourceRegistryPromise === undefined ) {
|
||||
assetSourceRegistryPromise = µBlock.cacheStorage.get(
|
||||
assetSourceRegistryPromise = cacheStorage.get(
|
||||
'assetSourceRegistry'
|
||||
).then(bin => {
|
||||
if (
|
||||
|
@ -356,12 +358,12 @@ const getAssetSourceRegistry = function() {
|
|||
assetSourceRegistry = bin.assetSourceRegistry;
|
||||
return assetSourceRegistry;
|
||||
}
|
||||
return api.fetchText(
|
||||
µBlock.assetsBootstrapLocation || 'assets/assets.json'
|
||||
return assets.fetchText(
|
||||
µb.assetsBootstrapLocation || 'assets/assets.json'
|
||||
).then(details => {
|
||||
return details.content !== ''
|
||||
? details
|
||||
: api.fetchText('assets/assets.json');
|
||||
: assets.fetchText('assets/assets.json');
|
||||
}).then(details => {
|
||||
updateAssetSourceRegistry(details.content, true);
|
||||
return assetSourceRegistry;
|
||||
|
@ -418,7 +420,7 @@ const saveAssetSourceRegistry = (( ) => {
|
|||
let timer;
|
||||
const save = function() {
|
||||
timer = undefined;
|
||||
µBlock.cacheStorage.set({ assetSourceRegistry });
|
||||
cacheStorage.set({ assetSourceRegistry });
|
||||
};
|
||||
return function(lazily) {
|
||||
if ( timer !== undefined ) {
|
||||
|
@ -464,13 +466,13 @@ const updateAssetSourceRegistry = function(json, silent) {
|
|||
saveAssetSourceRegistry();
|
||||
};
|
||||
|
||||
api.registerAssetSource = async function(assetKey, details) {
|
||||
assets.registerAssetSource = async function(assetKey, details) {
|
||||
await getAssetSourceRegistry();
|
||||
registerAssetSource(assetKey, details);
|
||||
saveAssetSourceRegistry(true);
|
||||
};
|
||||
|
||||
api.unregisterAssetSource = async function(assetKey) {
|
||||
assets.unregisterAssetSource = async function(assetKey) {
|
||||
await getAssetSourceRegistry();
|
||||
unregisterAssetSource(assetKey);
|
||||
saveAssetSourceRegistry(true);
|
||||
|
@ -489,7 +491,7 @@ let assetCacheRegistry = {};
|
|||
|
||||
const getAssetCacheRegistry = function() {
|
||||
if ( assetCacheRegistryPromise === undefined ) {
|
||||
assetCacheRegistryPromise = µBlock.cacheStorage.get(
|
||||
assetCacheRegistryPromise = cacheStorage.get(
|
||||
'assetCacheRegistry'
|
||||
).then(bin => {
|
||||
if (
|
||||
|
@ -523,7 +525,7 @@ const saveAssetCacheRegistry = (( ) => {
|
|||
let timer;
|
||||
const save = function() {
|
||||
timer = undefined;
|
||||
µBlock.cacheStorage.set({ assetCacheRegistry });
|
||||
cacheStorage.set({ assetCacheRegistry });
|
||||
};
|
||||
return function(lazily) {
|
||||
if ( timer !== undefined ) { clearTimeout(timer); }
|
||||
|
@ -547,7 +549,7 @@ const assetCacheRead = async function(assetKey, updateReadTime = false) {
|
|||
|
||||
const [ , bin ] = await Promise.all([
|
||||
getAssetCacheRegistry(),
|
||||
µBlock.cacheStorage.get(internalKey),
|
||||
cacheStorage.get(internalKey),
|
||||
]);
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
|
@ -593,7 +595,7 @@ const assetCacheWrite = async function(assetKey, details) {
|
|||
if ( typeof options.url === 'string' ) {
|
||||
entry.remoteURL = options.url;
|
||||
}
|
||||
µBlock.cacheStorage.set({
|
||||
cacheStorage.set({
|
||||
assetCacheRegistry,
|
||||
[`cache/${assetKey}`]: content
|
||||
});
|
||||
|
@ -623,8 +625,8 @@ const assetCacheRemove = async function(pattern) {
|
|||
}
|
||||
if ( removedContent.length !== 0 ) {
|
||||
await Promise.all([
|
||||
µBlock.cacheStorage.remove(removedContent),
|
||||
µBlock.cacheStorage.set({ assetCacheRegistry }),
|
||||
cacheStorage.remove(removedContent),
|
||||
cacheStorage.set({ assetCacheRegistry }),
|
||||
]);
|
||||
}
|
||||
for ( let i = 0; i < removedEntries.length; i++ ) {
|
||||
|
@ -658,7 +660,7 @@ const assetCacheMarkAsDirty = async function(pattern, exclude) {
|
|||
mustSave = true;
|
||||
}
|
||||
if ( mustSave ) {
|
||||
µBlock.cacheStorage.set({ assetCacheRegistry });
|
||||
cacheStorage.set({ assetCacheRegistry });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -708,8 +710,8 @@ const saveUserAsset = function(assetKey, content) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.get = async function(assetKey, options = {}) {
|
||||
if ( assetKey === µBlock.userFiltersPath ) {
|
||||
assets.get = async function(assetKey, options = {}) {
|
||||
if ( assetKey === µb.userFiltersPath ) {
|
||||
return readUserAsset(assetKey);
|
||||
}
|
||||
|
||||
|
@ -770,8 +772,8 @@ api.get = async function(assetKey, options = {}) {
|
|||
continue;
|
||||
}
|
||||
const details = assetDetails.content === 'filters'
|
||||
? await api.fetchFilterList(contentURL)
|
||||
: await api.fetchText(contentURL);
|
||||
? await assets.fetchFilterList(contentURL)
|
||||
: await assets.fetchText(contentURL);
|
||||
if ( details.content === '' ) { continue; }
|
||||
if ( reIsExternalPath.test(contentURL) && options.dontCache !== true ) {
|
||||
assetCacheWrite(assetKey, {
|
||||
|
@ -832,8 +834,8 @@ const getRemote = async function(assetKey) {
|
|||
if ( reIsExternalPath.test(contentURL) === false ) { continue; }
|
||||
|
||||
const result = assetDetails.content === 'filters'
|
||||
? await api.fetchFilterList(contentURL)
|
||||
: await api.fetchText(contentURL);
|
||||
? await assets.fetchFilterList(contentURL)
|
||||
: await assets.fetchText(contentURL);
|
||||
|
||||
// Failure
|
||||
if ( stringIsNotEmpty(result.content) === false ) {
|
||||
|
@ -861,7 +863,7 @@ const getRemote = async function(assetKey) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.put = async function(assetKey, content) {
|
||||
assets.put = async function(assetKey, content) {
|
||||
return reIsUserAsset.test(assetKey)
|
||||
? await saveUserAsset(assetKey, content)
|
||||
: await assetCacheWrite(assetKey, content);
|
||||
|
@ -869,7 +871,7 @@ api.put = async function(assetKey, content) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.metadata = async function() {
|
||||
assets.metadata = async function() {
|
||||
await Promise.all([
|
||||
getAssetSourceRegistry(),
|
||||
getAssetCacheRegistry(),
|
||||
|
@ -888,7 +890,7 @@ api.metadata = async function() {
|
|||
assetEntry.isDefault =
|
||||
assetEntry.off === undefined ||
|
||||
assetEntry.off === true &&
|
||||
µBlock.listMatchesEnvironment(assetEntry);
|
||||
µb.listMatchesEnvironment(assetEntry);
|
||||
}
|
||||
if ( cacheEntry ) {
|
||||
assetEntry.cached = true;
|
||||
|
@ -911,13 +913,13 @@ api.metadata = async function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
api.purge = assetCacheMarkAsDirty;
|
||||
assets.purge = assetCacheMarkAsDirty;
|
||||
|
||||
api.remove = function(pattern) {
|
||||
assets.remove = function(pattern) {
|
||||
return assetCacheRemove(pattern);
|
||||
};
|
||||
|
||||
api.rmrf = function() {
|
||||
assets.rmrf = function() {
|
||||
return assetCacheRemove(/./);
|
||||
};
|
||||
|
||||
|
@ -1014,7 +1016,7 @@ const updateDone = function() {
|
|||
fireNotification('after-assets-updated', { assetKeys: assetKeys });
|
||||
};
|
||||
|
||||
api.updateStart = function(details) {
|
||||
assets.updateStart = function(details) {
|
||||
const oldUpdateDelay = updaterAssetDelay;
|
||||
const newUpdateDelay = typeof details.delay === 'number'
|
||||
? details.delay
|
||||
|
@ -1031,7 +1033,7 @@ api.updateStart = function(details) {
|
|||
updateFirst();
|
||||
};
|
||||
|
||||
api.updateStop = function() {
|
||||
assets.updateStop = function() {
|
||||
if ( updaterTimer ) {
|
||||
clearTimeout(updaterTimer);
|
||||
updaterTimer = undefined;
|
||||
|
@ -1041,15 +1043,13 @@ api.updateStop = function() {
|
|||
}
|
||||
};
|
||||
|
||||
api.isUpdating = function() {
|
||||
assets.isUpdating = function() {
|
||||
return updaterStatus === 'updating' &&
|
||||
updaterAssetDelay <= µBlock.hiddenSettings.manualUpdateAssetFetchPeriod;
|
||||
updaterAssetDelay <= µb.hiddenSettings.manualUpdateAssetFetchPeriod;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.assets = api;
|
||||
export default assets;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
/******************************************************************************/
|
||||
|
||||
import globals from './globals.js';
|
||||
import logger from './logger.js';
|
||||
import { FilteringContext } from './filtering-context.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
|
@ -31,11 +33,6 @@ import {
|
|||
originFromURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import { FilteringContext } from './filtering-context.js';
|
||||
import { CompiledListWriter } from './static-filtering-io.js';
|
||||
import { StaticFilteringParser } from './static-filtering-parser.js';
|
||||
import { staticNetFilteringEngine } from './static-net-filtering.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Not all platforms may have properly declared vAPI.webextFlavor.
|
||||
|
@ -333,7 +330,6 @@ const µBlock = { // jshint ignore:line
|
|||
if ( this.tabDomain === undefined ) {
|
||||
void this.getTabDomain();
|
||||
}
|
||||
const logger = µBlock.logger;
|
||||
const filters = this.filter;
|
||||
// Many filters may have been applied to the current context
|
||||
if ( Array.isArray(filters) === false ) {
|
||||
|
@ -347,9 +343,6 @@ const µBlock = { // jshint ignore:line
|
|||
};
|
||||
|
||||
µBlock.filteringContext = new µBlock.FilteringContext();
|
||||
µBlock.CompiledListWriter = CompiledListWriter;
|
||||
µBlock.StaticFilteringParser = StaticFilteringParser;
|
||||
µBlock.staticNetFilteringEngine = staticNetFilteringEngine;
|
||||
|
||||
globals.µBlock = µBlock;
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import lz4Codec from './lz4.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -54,431 +55,434 @@ import µBlock from './background.js';
|
|||
// https://github.com/uBlockOrigin/uBlock-issues/issues/409
|
||||
// Allow forcing the use of webext storage on Firefox.
|
||||
|
||||
µBlock.cacheStorage = (function() {
|
||||
const STORAGE_NAME = 'uBlock0CacheStorage';
|
||||
|
||||
const STORAGE_NAME = 'uBlock0CacheStorage';
|
||||
// Default to webext storage.
|
||||
const storageLocal = webext.storage.local;
|
||||
|
||||
// Default to webext storage.
|
||||
const localStorage = webext.storage.local;
|
||||
const api = {
|
||||
name: 'browser.storage.local',
|
||||
get: localStorage.get,
|
||||
set: localStorage.set,
|
||||
remove: localStorage.remove,
|
||||
clear: localStorage.clear,
|
||||
getBytesInUse: localStorage.getBytesInUse,
|
||||
select: function(selectedBackend) {
|
||||
let actualBackend = selectedBackend;
|
||||
if ( actualBackend === undefined || actualBackend === 'unset' ) {
|
||||
actualBackend = vAPI.webextFlavor.soup.has('firefox')
|
||||
? 'indexedDB'
|
||||
: 'browser.storage.local';
|
||||
}
|
||||
if ( actualBackend === 'indexedDB' ) {
|
||||
return selectIDB().then(success => {
|
||||
if ( success || selectedBackend === 'indexedDB' ) {
|
||||
clearWebext();
|
||||
return 'indexedDB';
|
||||
}
|
||||
clearIDB();
|
||||
return 'browser.storage.local';
|
||||
});
|
||||
}
|
||||
if ( actualBackend === 'browser.storage.local' ) {
|
||||
const cacheStorage = {
|
||||
name: 'browser.storage.local',
|
||||
get: storageLocal.get.bind(storageLocal),
|
||||
set: storageLocal.set.bind(storageLocal),
|
||||
remove: storageLocal.remove.bind(storageLocal),
|
||||
clear: storageLocal.clear.bind(storageLocal),
|
||||
// Not all platforms support getBytesInUse
|
||||
getBytesInUse: storageLocal.getBytesInUse
|
||||
? storageLocal.getBytesInUse.bind(storageLocal)
|
||||
: undefined,
|
||||
select: function(selectedBackend) {
|
||||
let actualBackend = selectedBackend;
|
||||
if ( actualBackend === undefined || actualBackend === 'unset' ) {
|
||||
actualBackend = vAPI.webextFlavor.soup.has('firefox')
|
||||
? 'indexedDB'
|
||||
: 'browser.storage.local';
|
||||
}
|
||||
if ( actualBackend === 'indexedDB' ) {
|
||||
return selectIDB().then(success => {
|
||||
if ( success || selectedBackend === 'indexedDB' ) {
|
||||
clearWebext();
|
||||
return 'indexedDB';
|
||||
}
|
||||
clearIDB();
|
||||
}
|
||||
return Promise.resolve('browser.storage.local');
|
||||
|
||||
},
|
||||
error: undefined
|
||||
return 'browser.storage.local';
|
||||
});
|
||||
}
|
||||
if ( actualBackend === 'browser.storage.local' ) {
|
||||
clearIDB();
|
||||
}
|
||||
return Promise.resolve('browser.storage.local');
|
||||
|
||||
},
|
||||
error: undefined
|
||||
};
|
||||
|
||||
// Reassign API entries to that of indexedDB-based ones
|
||||
const selectIDB = async function() {
|
||||
let db;
|
||||
let dbPromise;
|
||||
let dbTimer;
|
||||
|
||||
const noopfn = function () {
|
||||
};
|
||||
|
||||
// Reassign API entries to that of indexedDB-based ones
|
||||
const selectIDB = async function() {
|
||||
let db;
|
||||
let dbPromise;
|
||||
let dbTimer;
|
||||
const disconnect = function() {
|
||||
if ( dbTimer !== undefined ) {
|
||||
clearTimeout(dbTimer);
|
||||
dbTimer = undefined;
|
||||
}
|
||||
if ( db instanceof IDBDatabase ) {
|
||||
db.close();
|
||||
db = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const noopfn = function () {
|
||||
};
|
||||
|
||||
const disconnect = function() {
|
||||
if ( dbTimer !== undefined ) {
|
||||
clearTimeout(dbTimer);
|
||||
const keepAlive = function() {
|
||||
if ( dbTimer !== undefined ) {
|
||||
clearTimeout(dbTimer);
|
||||
}
|
||||
dbTimer = vAPI.setTimeout(
|
||||
( ) => {
|
||||
dbTimer = undefined;
|
||||
}
|
||||
if ( db instanceof IDBDatabase ) {
|
||||
db.close();
|
||||
db = undefined;
|
||||
}
|
||||
};
|
||||
disconnect();
|
||||
},
|
||||
Math.max(
|
||||
µb.hiddenSettings.autoUpdateAssetFetchPeriod * 2 * 1000,
|
||||
180000
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const keepAlive = function() {
|
||||
if ( dbTimer !== undefined ) {
|
||||
clearTimeout(dbTimer);
|
||||
}
|
||||
dbTimer = vAPI.setTimeout(
|
||||
( ) => {
|
||||
dbTimer = undefined;
|
||||
disconnect();
|
||||
},
|
||||
Math.max(
|
||||
µBlock.hiddenSettings.autoUpdateAssetFetchPeriod * 2 * 1000,
|
||||
180000
|
||||
)
|
||||
);
|
||||
};
|
||||
// https://github.com/gorhill/uBlock/issues/3156
|
||||
// I have observed that no event was fired in Tor Browser 7.0.7 +
|
||||
// medium security level after the request to open the database was
|
||||
// created. When this occurs, I have also observed that the `error`
|
||||
// property was already set, so this means uBO can detect here whether
|
||||
// the database can be opened successfully. A try-catch block is
|
||||
// necessary when reading the `error` property because we are not
|
||||
// allowed to read this propery outside of event handlers in newer
|
||||
// implementation of IDBRequest (my understanding).
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/3156
|
||||
// I have observed that no event was fired in Tor Browser 7.0.7 +
|
||||
// medium security level after the request to open the database was
|
||||
// created. When this occurs, I have also observed that the `error`
|
||||
// property was already set, so this means uBO can detect here whether
|
||||
// the database can be opened successfully. A try-catch block is
|
||||
// necessary when reading the `error` property because we are not
|
||||
// allowed to read this propery outside of event handlers in newer
|
||||
// implementation of IDBRequest (my understanding).
|
||||
|
||||
const getDb = function() {
|
||||
keepAlive();
|
||||
if ( db !== undefined ) {
|
||||
return Promise.resolve(db);
|
||||
}
|
||||
if ( dbPromise !== undefined ) {
|
||||
return dbPromise;
|
||||
}
|
||||
dbPromise = new Promise(resolve => {
|
||||
let req;
|
||||
try {
|
||||
req = indexedDB.open(STORAGE_NAME, 1);
|
||||
if ( req.error ) {
|
||||
console.log(req.error);
|
||||
req = undefined;
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
if ( req === undefined ) {
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
return resolve(null);
|
||||
}
|
||||
req.onupgradeneeded = function(ev) {
|
||||
if ( ev.oldVersion === 1 ) { return; }
|
||||
try {
|
||||
const db = ev.target.result;
|
||||
db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
||||
} catch(ex) {
|
||||
req.onerror();
|
||||
}
|
||||
};
|
||||
req.onsuccess = function(ev) {
|
||||
if ( resolve === undefined ) { return; }
|
||||
req = undefined;
|
||||
db = ev.target.result;
|
||||
dbPromise = undefined;
|
||||
resolve(db);
|
||||
resolve = undefined;
|
||||
};
|
||||
req.onerror = req.onblocked = function() {
|
||||
if ( resolve === undefined ) { return; }
|
||||
req = undefined;
|
||||
console.log(this.error);
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
};
|
||||
setTimeout(( ) => {
|
||||
if ( resolve === undefined ) { return; }
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
}, 5000);
|
||||
});
|
||||
const getDb = function() {
|
||||
keepAlive();
|
||||
if ( db !== undefined ) {
|
||||
return Promise.resolve(db);
|
||||
}
|
||||
if ( dbPromise !== undefined ) {
|
||||
return dbPromise;
|
||||
};
|
||||
|
||||
const fromBlob = function(data) {
|
||||
if ( data instanceof Blob === false ) {
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
const blobReader = new FileReader();
|
||||
blobReader.onloadend = ev => {
|
||||
resolve(new Uint8Array(ev.target.result));
|
||||
};
|
||||
blobReader.readAsArrayBuffer(data);
|
||||
});
|
||||
};
|
||||
|
||||
const toBlob = function(data) {
|
||||
const value = data instanceof Uint8Array
|
||||
? new Blob([ data ])
|
||||
: data;
|
||||
return Promise.resolve(value);
|
||||
};
|
||||
|
||||
const compress = function(store, key, data) {
|
||||
return µBlock.lz4Codec.encode(data, toBlob).then(value => {
|
||||
store.push({ key, value });
|
||||
});
|
||||
};
|
||||
|
||||
const decompress = function(store, key, data) {
|
||||
return µBlock.lz4Codec.decode(data, fromBlob).then(data => {
|
||||
store[key] = data;
|
||||
});
|
||||
};
|
||||
|
||||
const getFromDb = async function(keys, keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
if ( keys.length === 0 ) { return callback(keyvalStore); }
|
||||
const promises = [];
|
||||
const gotOne = function() {
|
||||
if ( typeof this.result !== 'object' ) { return; }
|
||||
const { key, value } = this.result;
|
||||
keyvalStore[key] = value;
|
||||
if ( value instanceof Blob === false ) { return; }
|
||||
promises.push(decompress(keyvalStore, key, value));
|
||||
};
|
||||
}
|
||||
dbPromise = new Promise(resolve => {
|
||||
let req;
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
Promise.all(promises).then(( ) => {
|
||||
callback(keyvalStore);
|
||||
});
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const key of keys ) {
|
||||
const req = table.get(key);
|
||||
req.onsuccess = gotOne;
|
||||
req.onerror = noopfn;
|
||||
req = indexedDB.open(STORAGE_NAME, 1);
|
||||
if ( req.error ) {
|
||||
console.log(req.error);
|
||||
req = undefined;
|
||||
}
|
||||
} catch(ex) {
|
||||
}
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.getFromDb() failed: ${reason}`);
|
||||
callback();
|
||||
if ( req === undefined ) {
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
return resolve(null);
|
||||
}
|
||||
};
|
||||
req.onupgradeneeded = function(ev) {
|
||||
if ( ev.oldVersion === 1 ) { return; }
|
||||
try {
|
||||
const db = ev.target.result;
|
||||
db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
||||
} catch(ex) {
|
||||
req.onerror();
|
||||
}
|
||||
};
|
||||
req.onsuccess = function(ev) {
|
||||
if ( resolve === undefined ) { return; }
|
||||
req = undefined;
|
||||
db = ev.target.result;
|
||||
dbPromise = undefined;
|
||||
resolve(db);
|
||||
resolve = undefined;
|
||||
};
|
||||
req.onerror = req.onblocked = function() {
|
||||
if ( resolve === undefined ) { return; }
|
||||
req = undefined;
|
||||
console.log(this.error);
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
};
|
||||
setTimeout(( ) => {
|
||||
if ( resolve === undefined ) { return; }
|
||||
db = null;
|
||||
dbPromise = undefined;
|
||||
resolve(null);
|
||||
resolve = undefined;
|
||||
}, 5000);
|
||||
});
|
||||
return dbPromise;
|
||||
};
|
||||
|
||||
const visitAllFromDb = async function(visitFn) {
|
||||
const fromBlob = function(data) {
|
||||
if ( data instanceof Blob === false ) {
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
const blobReader = new FileReader();
|
||||
blobReader.onloadend = ev => {
|
||||
resolve(new Uint8Array(ev.target.result));
|
||||
};
|
||||
blobReader.readAsArrayBuffer(data);
|
||||
});
|
||||
};
|
||||
|
||||
const toBlob = function(data) {
|
||||
const value = data instanceof Uint8Array
|
||||
? new Blob([ data ])
|
||||
: data;
|
||||
return Promise.resolve(value);
|
||||
};
|
||||
|
||||
const compress = function(store, key, data) {
|
||||
return lz4Codec.encode(data, toBlob).then(value => {
|
||||
store.push({ key, value });
|
||||
});
|
||||
};
|
||||
|
||||
const decompress = function(store, key, data) {
|
||||
return lz4Codec.decode(data, fromBlob).then(data => {
|
||||
store[key] = data;
|
||||
});
|
||||
};
|
||||
|
||||
const getFromDb = async function(keys, keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
if ( keys.length === 0 ) { return callback(keyvalStore); }
|
||||
const promises = [];
|
||||
const gotOne = function() {
|
||||
if ( typeof this.result !== 'object' ) { return; }
|
||||
const { key, value } = this.result;
|
||||
keyvalStore[key] = value;
|
||||
if ( value instanceof Blob === false ) { return; }
|
||||
promises.push(decompress(keyvalStore, key, value));
|
||||
};
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return visitFn(); }
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => visitFn();
|
||||
transaction.onabort = ( ) => {
|
||||
Promise.all(promises).then(( ) => {
|
||||
callback(keyvalStore);
|
||||
});
|
||||
};
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
const req = table.openCursor();
|
||||
req.onsuccess = function(ev) {
|
||||
let cursor = ev.target && ev.target.result;
|
||||
if ( !cursor ) { return; }
|
||||
let entry = cursor.value;
|
||||
visitFn(entry);
|
||||
cursor.continue();
|
||||
};
|
||||
};
|
||||
|
||||
const getAllFromDb = function(callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
const promises = [];
|
||||
const keyvalStore = {};
|
||||
visitAllFromDb(entry => {
|
||||
if ( entry === undefined ) {
|
||||
Promise.all(promises).then(( ) => {
|
||||
callback(keyvalStore);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { key, value } = entry;
|
||||
keyvalStore[key] = value;
|
||||
if ( entry.value instanceof Blob === false ) { return; }
|
||||
promises.push(decompress(keyvalStore, key, value));
|
||||
}).catch(reason => {
|
||||
console.info(`cacheStorage.getAllFromDb() failed: ${reason}`);
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/141
|
||||
// Mind that IDBDatabase.transaction() and IDBObjectStore.put()
|
||||
// can throw:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/transaction
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/put
|
||||
|
||||
const putToDb = async function(keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
const keys = Object.keys(keyvalStore);
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
const promises = [ getDb() ];
|
||||
const entries = [];
|
||||
const dontCompress =
|
||||
µBlock.hiddenSettings.cacheStorageCompression !== true;
|
||||
for ( const key of keys ) {
|
||||
const value = keyvalStore[key];
|
||||
const isString = typeof value === 'string';
|
||||
if ( isString === false || dontCompress ) {
|
||||
entries.push({ key, value });
|
||||
continue;
|
||||
}
|
||||
promises.push(compress(entries, key, value));
|
||||
}
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
callback = undefined;
|
||||
cb();
|
||||
};
|
||||
try {
|
||||
const results = await Promise.all(promises);
|
||||
const db = results[0];
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(
|
||||
STORAGE_NAME,
|
||||
'readwrite'
|
||||
);
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = finish;
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const entry of entries ) {
|
||||
table.put(entry);
|
||||
}
|
||||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteFromDb = async function(input, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
const keys = Array.isArray(input) ? input.slice() : [ input ];
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
callback = undefined;
|
||||
cb();
|
||||
};
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = finish;
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const key of keys ) {
|
||||
table.delete(key);
|
||||
}
|
||||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
const clearDb = async function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
callback();
|
||||
};
|
||||
transaction.objectStore(STORAGE_NAME).clear();
|
||||
}
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.clearDb() failed: ${reason}`);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
await getDb();
|
||||
if ( !db ) { return false; }
|
||||
|
||||
api.name = 'indexedDB';
|
||||
api.get = function get(keys) {
|
||||
return new Promise(resolve => {
|
||||
if ( keys === null ) {
|
||||
return getAllFromDb(bin => resolve(bin));
|
||||
}
|
||||
let toRead, output = {};
|
||||
if ( typeof keys === 'string' ) {
|
||||
toRead = [ keys ];
|
||||
} else if ( Array.isArray(keys) ) {
|
||||
toRead = keys;
|
||||
} else /* if ( typeof keys === 'object' ) */ {
|
||||
toRead = Object.keys(keys);
|
||||
output = keys;
|
||||
}
|
||||
getFromDb(toRead, output, bin => resolve(bin));
|
||||
});
|
||||
};
|
||||
api.set = function set(keys) {
|
||||
return new Promise(resolve => {
|
||||
putToDb(keys, details => resolve(details));
|
||||
});
|
||||
};
|
||||
api.remove = function remove(keys) {
|
||||
return new Promise(resolve => {
|
||||
deleteFromDb(keys, ( ) => resolve());
|
||||
});
|
||||
};
|
||||
api.clear = function clear() {
|
||||
return new Promise(resolve => {
|
||||
clearDb(( ) => resolve());
|
||||
});
|
||||
};
|
||||
api.getBytesInUse = function getBytesInUse() {
|
||||
return Promise.resolve(0);
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
||||
// Delete cache-related entries from webext storage.
|
||||
const clearWebext = async function() {
|
||||
const bin = await webext.storage.local.get('assetCacheRegistry');
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
bin.assetCacheRegistry instanceof Object === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const toRemove = [
|
||||
'assetCacheRegistry',
|
||||
'assetSourceRegistry',
|
||||
'resourcesSelfie',
|
||||
'selfie'
|
||||
];
|
||||
for ( const key in bin.assetCacheRegistry ) {
|
||||
if ( bin.assetCacheRegistry.hasOwnProperty(key) ) {
|
||||
toRemove.push('cache/' + key);
|
||||
const req = table.get(key);
|
||||
req.onsuccess = gotOne;
|
||||
req.onerror = noopfn;
|
||||
}
|
||||
}
|
||||
webext.storage.local.remove(toRemove);
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.getFromDb() failed: ${reason}`);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const clearIDB = function() {
|
||||
const visitAllFromDb = async function(visitFn) {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return visitFn(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readonly');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => visitFn();
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
const req = table.openCursor();
|
||||
req.onsuccess = function(ev) {
|
||||
let cursor = ev.target && ev.target.result;
|
||||
if ( !cursor ) { return; }
|
||||
let entry = cursor.value;
|
||||
visitFn(entry);
|
||||
cursor.continue();
|
||||
};
|
||||
};
|
||||
|
||||
const getAllFromDb = function(callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
const promises = [];
|
||||
const keyvalStore = {};
|
||||
visitAllFromDb(entry => {
|
||||
if ( entry === undefined ) {
|
||||
Promise.all(promises).then(( ) => {
|
||||
callback(keyvalStore);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const { key, value } = entry;
|
||||
keyvalStore[key] = value;
|
||||
if ( entry.value instanceof Blob === false ) { return; }
|
||||
promises.push(decompress(keyvalStore, key, value));
|
||||
}).catch(reason => {
|
||||
console.info(`cacheStorage.getAllFromDb() failed: ${reason}`);
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/141
|
||||
// Mind that IDBDatabase.transaction() and IDBObjectStore.put()
|
||||
// can throw:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/transaction
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/put
|
||||
|
||||
const putToDb = async function(keyvalStore, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
const keys = Object.keys(keyvalStore);
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
const promises = [ getDb() ];
|
||||
const entries = [];
|
||||
const dontCompress =
|
||||
µb.hiddenSettings.cacheStorageCompression !== true;
|
||||
for ( const key of keys ) {
|
||||
const value = keyvalStore[key];
|
||||
const isString = typeof value === 'string';
|
||||
if ( isString === false || dontCompress ) {
|
||||
entries.push({ key, value });
|
||||
continue;
|
||||
}
|
||||
promises.push(compress(entries, key, value));
|
||||
}
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
callback = undefined;
|
||||
cb();
|
||||
};
|
||||
try {
|
||||
indexedDB.deleteDatabase(STORAGE_NAME);
|
||||
} catch(ex) {
|
||||
const results = await Promise.all(promises);
|
||||
const db = results[0];
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(
|
||||
STORAGE_NAME,
|
||||
'readwrite'
|
||||
);
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = finish;
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const entry of entries ) {
|
||||
table.put(entry);
|
||||
}
|
||||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
return api;
|
||||
}());
|
||||
const deleteFromDb = async function(input, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
const keys = Array.isArray(input) ? input.slice() : [ input ];
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
const finish = ( ) => {
|
||||
if ( callback === undefined ) { return; }
|
||||
let cb = callback;
|
||||
callback = undefined;
|
||||
cb();
|
||||
};
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = finish;
|
||||
const table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( const key of keys ) {
|
||||
table.delete(key);
|
||||
}
|
||||
} catch (ex) {
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
const clearDb = async function(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
try {
|
||||
const db = await getDb();
|
||||
if ( !db ) { return callback(); }
|
||||
const transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete =
|
||||
transaction.onerror =
|
||||
transaction.onabort = ( ) => {
|
||||
callback();
|
||||
};
|
||||
transaction.objectStore(STORAGE_NAME).clear();
|
||||
}
|
||||
catch(reason) {
|
||||
console.info(`cacheStorage.clearDb() failed: ${reason}`);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
await getDb();
|
||||
if ( !db ) { return false; }
|
||||
|
||||
cacheStorage.name = 'indexedDB';
|
||||
cacheStorage.get = function get(keys) {
|
||||
return new Promise(resolve => {
|
||||
if ( keys === null ) {
|
||||
return getAllFromDb(bin => resolve(bin));
|
||||
}
|
||||
let toRead, output = {};
|
||||
if ( typeof keys === 'string' ) {
|
||||
toRead = [ keys ];
|
||||
} else if ( Array.isArray(keys) ) {
|
||||
toRead = keys;
|
||||
} else /* if ( typeof keys === 'object' ) */ {
|
||||
toRead = Object.keys(keys);
|
||||
output = keys;
|
||||
}
|
||||
getFromDb(toRead, output, bin => resolve(bin));
|
||||
});
|
||||
};
|
||||
cacheStorage.set = function set(keys) {
|
||||
return new Promise(resolve => {
|
||||
putToDb(keys, details => resolve(details));
|
||||
});
|
||||
};
|
||||
cacheStorage.remove = function remove(keys) {
|
||||
return new Promise(resolve => {
|
||||
deleteFromDb(keys, ( ) => resolve());
|
||||
});
|
||||
};
|
||||
cacheStorage.clear = function clear() {
|
||||
return new Promise(resolve => {
|
||||
clearDb(( ) => resolve());
|
||||
});
|
||||
};
|
||||
cacheStorage.getBytesInUse = function getBytesInUse() {
|
||||
return Promise.resolve(0);
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/328
|
||||
// Delete cache-related entries from webext storage.
|
||||
const clearWebext = async function() {
|
||||
const bin = await webext.storage.local.get('assetCacheRegistry');
|
||||
if (
|
||||
bin instanceof Object === false ||
|
||||
bin.assetCacheRegistry instanceof Object === false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const toRemove = [
|
||||
'assetCacheRegistry',
|
||||
'assetSourceRegistry',
|
||||
'resourcesSelfie',
|
||||
'selfie'
|
||||
];
|
||||
for ( const key in bin.assetCacheRegistry ) {
|
||||
if ( bin.assetCacheRegistry.hasOwnProperty(key) ) {
|
||||
toRemove.push('cache/' + key);
|
||||
}
|
||||
}
|
||||
webext.storage.local.remove(toRemove);
|
||||
};
|
||||
|
||||
const clearIDB = function() {
|
||||
try {
|
||||
indexedDB.deleteDatabase(STORAGE_NAME);
|
||||
} catch(ex) {
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export default cacheStorage;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -24,24 +24,23 @@
|
|||
/******************************************************************************/
|
||||
|
||||
import { hostnameFromURI } from './uri-utils.js';
|
||||
import µBlock from './background.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.canUseShortcuts = vAPI.commands instanceof Object;
|
||||
µb.canUseShortcuts = vAPI.commands instanceof Object;
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/386
|
||||
// Firefox 74 and above has complete shotcut assignment user interface.
|
||||
µBlock.canUpdateShortcuts =
|
||||
µBlock.canUseShortcuts &&
|
||||
µb.canUpdateShortcuts =
|
||||
µb.canUseShortcuts &&
|
||||
vAPI.webextFlavor.soup.has('firefox') &&
|
||||
typeof vAPI.commands.update === 'function';
|
||||
|
||||
if ( µBlock.canUpdateShortcuts ) {
|
||||
if ( µb.canUpdateShortcuts ) {
|
||||
self.addEventListener(
|
||||
'webextFlavor',
|
||||
( ) => {
|
||||
const µb = µBlock;
|
||||
µb.canUpdateShortcuts = vAPI.webextFlavor.major < 74;
|
||||
if ( µb.canUpdateShortcuts === false ) { return; }
|
||||
vAPI.storage.get('commandShortcuts').then(bin => {
|
||||
|
@ -65,7 +64,7 @@ if ( µBlock.canUpdateShortcuts ) {
|
|||
// *****************************************************************************
|
||||
// start of local namespace
|
||||
|
||||
if ( µBlock.canUseShortcuts === false ) { return; }
|
||||
if ( µb.canUseShortcuts === false ) { return; }
|
||||
|
||||
const relaxBlockingMode = (( ) => {
|
||||
const reloadTimers = new Map();
|
||||
|
@ -73,7 +72,6 @@ const relaxBlockingMode = (( ) => {
|
|||
return function(tab) {
|
||||
if ( tab instanceof Object === false || tab.id <= 0 ) { return; }
|
||||
|
||||
const µb = µBlock;
|
||||
const normalURL = µb.normalizeTabURL(tab.id, tab.url);
|
||||
|
||||
if ( µb.getNetFilteringSwitch(normalURL) === false ) { return; }
|
||||
|
@ -161,8 +159,6 @@ const relaxBlockingMode = (( ) => {
|
|||
})();
|
||||
|
||||
vAPI.commands.onCommand.addListener(async command => {
|
||||
const µb = µBlock;
|
||||
|
||||
switch ( command ) {
|
||||
case 'launch-element-picker':
|
||||
case 'launch-element-zapper': {
|
||||
|
|
|
@ -21,15 +21,39 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
self.log = (function() {
|
||||
const noopFunc = function() {};
|
||||
const info = function(s) { console.log(`[uBO] ${s}`); };
|
||||
return {
|
||||
get verbosity( ) { return; },
|
||||
set verbosity(level) {
|
||||
this.info = console.info = level === 'info' ? info : noopFunc;
|
||||
},
|
||||
info: noopFunc,
|
||||
print: info,
|
||||
/******************************************************************************/
|
||||
|
||||
function ubologSet(state = false) {
|
||||
if ( state ) {
|
||||
if ( ubolog.process instanceof Function ) {
|
||||
ubolog.process();
|
||||
}
|
||||
ubolog = ubologDo;
|
||||
} else {
|
||||
ubolog = ubologIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
function ubologDo(...args) {
|
||||
console.info('[uBO]', ...args);
|
||||
}
|
||||
|
||||
function ubologIgnore() {
|
||||
}
|
||||
|
||||
let ubolog = (( ) => {
|
||||
const pending = [];
|
||||
const store = function(...args) {
|
||||
pending.push(args);
|
||||
};
|
||||
store.process = function() {
|
||||
for ( const args of pending ) {
|
||||
ubologDo(...args);
|
||||
}
|
||||
};
|
||||
return store;
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export { ubolog, ubologSet };
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.contextMenu = (( ) => {
|
||||
const contextMenu = (( ) => {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -61,8 +61,8 @@ const onBlockElement = function(details, tab) {
|
|||
}
|
||||
}
|
||||
|
||||
µBlock.epickerArgs.mouse = true;
|
||||
µBlock.elementPickerExec(tab.id, 0, `${tagName}\t${src}`);
|
||||
µb.epickerArgs.mouse = true;
|
||||
µb.elementPickerExec(tab.id, 0, `${tagName}\t${src}`);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -70,8 +70,8 @@ const onBlockElement = function(details, tab) {
|
|||
const onBlockElementInFrame = function(details, tab) {
|
||||
if ( tab === undefined ) { return; }
|
||||
if ( /^https?:\/\//.test(details.frameUrl) === false ) { return; }
|
||||
µBlock.epickerArgs.mouse = false;
|
||||
µBlock.elementPickerExec(tab.id, details.frameId);
|
||||
µb.epickerArgs.mouse = false;
|
||||
µb.elementPickerExec(tab.id, details.frameId);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -87,7 +87,7 @@ const onSubscribeToList = function(details) {
|
|||
const url = parsedURL.searchParams.get('location');
|
||||
if ( url === null ) { return; }
|
||||
const title = parsedURL.searchParams.get('title') || '?';
|
||||
const hash = µBlock.selectedFilterLists.indexOf(parsedURL) !== -1
|
||||
const hash = µb.selectedFilterLists.indexOf(parsedURL) !== -1
|
||||
? '#subscribed'
|
||||
: '';
|
||||
vAPI.tabs.open({
|
||||
|
@ -104,7 +104,7 @@ const onSubscribeToList = function(details) {
|
|||
|
||||
const onTemporarilyAllowLargeMediaElements = function(details, tab) {
|
||||
if ( tab === undefined ) { return; }
|
||||
let pageStore = µBlock.pageStoreFromTabId(tab.id);
|
||||
const pageStore = µb.pageStoreFromTabId(tab.id);
|
||||
if ( pageStore === null ) { return; }
|
||||
pageStore.temporarilyAllowLargeMediaElements(true);
|
||||
};
|
||||
|
@ -166,8 +166,8 @@ let currentBits = 0;
|
|||
|
||||
const update = function(tabId = undefined) {
|
||||
let newBits = 0;
|
||||
if ( µBlock.userSettings.contextMenuEnabled && tabId !== undefined ) {
|
||||
const pageStore = µBlock.pageStoreFromTabId(tabId);
|
||||
if ( µb.userSettings.contextMenuEnabled && tabId !== undefined ) {
|
||||
const pageStore = µb.pageStoreFromTabId(tabId);
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
if ( pageStore.shouldApplySpecificCosmeticFilters(0) ) {
|
||||
newBits |= 0b0001;
|
||||
|
@ -206,7 +206,7 @@ const update = function(tabId = undefined) {
|
|||
// looked up after closing a window.
|
||||
|
||||
vAPI.contextMenu.onMustUpdate = async function(tabId = undefined) {
|
||||
if ( µBlock.userSettings.contextMenuEnabled === false ) {
|
||||
if ( µb.userSettings.contextMenuEnabled === false ) {
|
||||
return update();
|
||||
}
|
||||
if ( tabId !== undefined ) {
|
||||
|
@ -222,3 +222,9 @@ return { update: vAPI.contextMenu.onMustUpdate };
|
|||
/******************************************************************************/
|
||||
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export default contextMenu;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,17 +23,22 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import logger from './logger.js';
|
||||
import µb from './background.js';
|
||||
|
||||
import {
|
||||
StaticExtFilteringHostnameDB,
|
||||
StaticExtFilteringSessionDB,
|
||||
} from './static-ext-filtering-db.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
entityFromDomain,
|
||||
hostnameFromURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const µb = µBlock;
|
||||
const cosmeticSurveyingMissCountMax =
|
||||
parseInt(vAPI.localStorage.getItem('cosmeticSurveyingMissCountMax'), 10) ||
|
||||
15;
|
||||
|
@ -205,10 +210,10 @@ const FilterContainer = function() {
|
|||
this.selectorCacheTimer = null;
|
||||
|
||||
// specific filters
|
||||
this.specificFilters = new µb.staticExtFilteringEngine.HostnameBasedDB(2);
|
||||
this.specificFilters = new StaticExtFilteringHostnameDB(2);
|
||||
|
||||
// temporary filters
|
||||
this.sessionFilterDB = new µb.staticExtFilteringEngine.SessionDB();
|
||||
this.sessionFilterDB = new StaticExtFilteringSessionDB();
|
||||
|
||||
// low generic cosmetic filters, organized by id/class then simple/complex.
|
||||
this.lowlyGeneric = Object.create(null);
|
||||
|
@ -390,7 +395,7 @@ FilterContainer.prototype.compileGenericHideSelector = function(
|
|||
const { raw, compiled, pseudoclass } = parser.result;
|
||||
if ( compiled === undefined ) {
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid generic cosmetic filter in ${who}: ${raw}`
|
||||
|
@ -437,7 +442,7 @@ FilterContainer.prototype.compileGenericHideSelector = function(
|
|||
return this.compileSpecificSelector(parser, '', false, writer);
|
||||
}
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid generic cosmetic filter in ${who}: ##${raw}`
|
||||
|
@ -493,7 +498,7 @@ FilterContainer.prototype.compileGenericUnhideSelector = function(
|
|||
const { raw, compiled } = parser.result;
|
||||
if ( compiled === undefined ) {
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid cosmetic filter in ${who}: #@#${raw}`
|
||||
|
@ -523,7 +528,7 @@ FilterContainer.prototype.compileSpecificSelector = function(
|
|||
const { raw, compiled, exception } = parser.result;
|
||||
if ( compiled === undefined ) {
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid cosmetic filter in ${who}: ##${raw}`
|
||||
|
@ -1169,8 +1174,8 @@ FilterContainer.prototype.benchmark = async function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
const cosmeticFilteringEngine = new FilterContainer();
|
||||
|
||||
µBlock.cosmeticFilteringEngine = new FilterContainer();
|
||||
export default cosmeticFilteringEngine;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
import '../lib/punycode.js';
|
||||
|
||||
import globals from './globals.js';
|
||||
import µb from './background.js';
|
||||
import { domainFromHostname } from './uri-utils.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -266,7 +266,7 @@ const Matrix = class {
|
|||
|
||||
|
||||
evaluateCellZ(srcHostname, desHostname, type) {
|
||||
µBlock.decomposeHostname(srcHostname, this.decomposedSource);
|
||||
µb.decomposeHostname(srcHostname, this.decomposedSource);
|
||||
this.type = type;
|
||||
const bitOffset = typeBitOffsets[type];
|
||||
for ( const shn of this.decomposedSource ) {
|
||||
|
@ -296,7 +296,7 @@ const Matrix = class {
|
|||
// Precedence: from most specific to least specific
|
||||
|
||||
// Specific-destination, any party, any type
|
||||
µBlock.decomposeHostname(desHostname, this.decomposedDestination);
|
||||
µb.decomposeHostname(desHostname, this.decomposedDestination);
|
||||
for ( const dhn of this.decomposedDestination ) {
|
||||
if ( dhn === '*' ) { break; }
|
||||
this.y = dhn;
|
||||
|
@ -509,13 +509,13 @@ const Matrix = class {
|
|||
|
||||
|
||||
async benchmark() {
|
||||
const requests = await µBlock.loadBenchmarkDataset();
|
||||
const requests = await µb.loadBenchmarkDataset();
|
||||
if ( Array.isArray(requests) === false || requests.length === 0 ) {
|
||||
log.print('No requests found to benchmark');
|
||||
console.info('No requests found to benchmark');
|
||||
return;
|
||||
}
|
||||
log.print(`Benchmarking sessionFirewall.evaluateCellZY()...`);
|
||||
const fctxt = µBlock.filteringContext.duplicate();
|
||||
console.info(`Benchmarking sessionFirewall.evaluateCellZY()...`);
|
||||
const fctxt = µb.filteringContext.duplicate();
|
||||
const t0 = self.performance.now();
|
||||
for ( const request of requests ) {
|
||||
fctxt.setURL(request.url);
|
||||
|
@ -529,8 +529,8 @@ const Matrix = class {
|
|||
}
|
||||
const t1 = self.performance.now();
|
||||
const dur = t1 - t0;
|
||||
log.print(`Evaluated ${requests.length} requests in ${dur.toFixed(0)} ms`);
|
||||
log.print(`\tAverage: ${(dur / requests.length).toFixed(3)} ms per request`);
|
||||
console.info(`Evaluated ${requests.length} requests in ${dur.toFixed(0)} ms`);
|
||||
console.info(`\tAverage: ${(dur / requests.length).toFixed(3)} ms per request`);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -544,11 +544,9 @@ Matrix.prototype.magicId = 1;
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
const sessionFirewall = new Matrix();
|
||||
const permanentFirewall = new Matrix();
|
||||
|
||||
µBlock.Firewall = Matrix;
|
||||
|
||||
µBlock.sessionFirewall = new µBlock.Firewall();
|
||||
µBlock.permanentFirewall = new µBlock.Firewall();
|
||||
export { permanentFirewall, sessionFirewall };
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
import '../lib/punycode.js';
|
||||
|
||||
import globals from './globals.js';
|
||||
import µb from './background.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -228,7 +228,7 @@ HnSwitches.prototype.evaluateZ = function(switchName, hostname) {
|
|||
return false;
|
||||
}
|
||||
this.n = switchName;
|
||||
µBlock.decomposeHostname(hostname, this.decomposedSource);
|
||||
µb.decomposeHostname(hostname, this.decomposedSource);
|
||||
for ( const shn of this.decomposedSource ) {
|
||||
let bits = this.switches.get(shn);
|
||||
if ( bits !== undefined ) {
|
||||
|
@ -323,11 +323,9 @@ HnSwitches.prototype.removeFromRuleParts = function(parts) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
const sessionSwitches = new HnSwitches();
|
||||
const permanentSwitches = new HnSwitches();
|
||||
|
||||
µBlock.HnSwitches = HnSwitches;
|
||||
|
||||
µBlock.sessionSwitches = new HnSwitches();
|
||||
µBlock.permanentSwitches = new HnSwitches();
|
||||
export { permanentSwitches, sessionSwitches };
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -796,7 +796,7 @@ const getWasmModule = (( ) => {
|
|||
).then(
|
||||
WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
log.info(reason);
|
||||
console.info(reason);
|
||||
});
|
||||
|
||||
return wasmModulePromise;
|
||||
|
|
|
@ -23,22 +23,28 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import logger from './logger.js';
|
||||
import µb from './background.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
StaticExtFilteringHostnameDB,
|
||||
StaticExtFilteringSessionDB,
|
||||
} from './static-ext-filtering-db.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const µb = µBlock;
|
||||
const pselectors = new Map();
|
||||
const duplicates = new Set();
|
||||
|
||||
const filterDB = new µb.staticExtFilteringEngine.HostnameBasedDB(2);
|
||||
const sessionFilterDB = new µb.staticExtFilteringEngine.SessionDB();
|
||||
const filterDB = new StaticExtFilteringHostnameDB(2);
|
||||
const sessionFilterDB = new StaticExtFilteringSessionDB();
|
||||
|
||||
let acceptedCount = 0;
|
||||
let discardedCount = 0;
|
||||
let docRegister;
|
||||
|
||||
const api = {
|
||||
const htmlFilteringEngine = {
|
||||
get acceptedCount() {
|
||||
return acceptedCount;
|
||||
},
|
||||
|
@ -237,7 +243,7 @@ PSelector.prototype.operatorToTaskMap = new Map([
|
|||
PSelector.prototype.invalid = false;
|
||||
|
||||
const logOne = function(details, exception, selector) {
|
||||
µBlock.filteringContext
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(details.tabId)
|
||||
.setRealm('extended')
|
||||
|
@ -263,7 +269,7 @@ const applyProceduralSelector = function(details, selector) {
|
|||
node.remove();
|
||||
modified = true;
|
||||
}
|
||||
if ( modified && µb.logger.enabled ) {
|
||||
if ( modified && logger.enabled ) {
|
||||
logOne(details, 0, pselector.raw);
|
||||
}
|
||||
return modified;
|
||||
|
@ -276,13 +282,13 @@ const applyCSSSelector = function(details, selector) {
|
|||
node.remove();
|
||||
modified = true;
|
||||
}
|
||||
if ( modified && µb.logger.enabled ) {
|
||||
if ( modified && logger.enabled ) {
|
||||
logOne(details, 0, selector);
|
||||
}
|
||||
return modified;
|
||||
};
|
||||
|
||||
api.reset = function() {
|
||||
htmlFilteringEngine.reset = function() {
|
||||
filterDB.clear();
|
||||
pselectors.clear();
|
||||
duplicates.clear();
|
||||
|
@ -290,16 +296,16 @@ api.reset = function() {
|
|||
discardedCount = 0;
|
||||
};
|
||||
|
||||
api.freeze = function() {
|
||||
htmlFilteringEngine.freeze = function() {
|
||||
duplicates.clear();
|
||||
filterDB.collectGarbage();
|
||||
};
|
||||
|
||||
api.compile = function(parser, writer) {
|
||||
htmlFilteringEngine.compile = function(parser, writer) {
|
||||
const { raw, compiled, exception } = parser.result;
|
||||
if ( compiled === undefined ) {
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid HTML filter in ${who}: ##${raw}`
|
||||
|
@ -325,14 +331,14 @@ api.compile = function(parser, writer) {
|
|||
}
|
||||
};
|
||||
|
||||
api.compileTemporary = function(parser) {
|
||||
htmlFilteringEngine.compileTemporary = function(parser) {
|
||||
return {
|
||||
session: sessionFilterDB,
|
||||
selector: parser.result.compiled,
|
||||
};
|
||||
};
|
||||
|
||||
api.fromCompiledContent = function(reader) {
|
||||
htmlFilteringEngine.fromCompiledContent = function(reader) {
|
||||
// Don't bother loading filters if stream filtering is not supported.
|
||||
if ( µb.canFilterResponseData === false ) { return; }
|
||||
|
||||
|
@ -351,11 +357,11 @@ api.fromCompiledContent = function(reader) {
|
|||
}
|
||||
};
|
||||
|
||||
api.getSession = function() {
|
||||
htmlFilteringEngine.getSession = function() {
|
||||
return sessionFilterDB;
|
||||
};
|
||||
|
||||
api.retrieve = function(details) {
|
||||
htmlFilteringEngine.retrieve = function(details) {
|
||||
const hostname = details.hostname;
|
||||
|
||||
const plains = new Set();
|
||||
|
@ -384,7 +390,7 @@ api.retrieve = function(details) {
|
|||
// Do not filter if the site is under an `allow` rule.
|
||||
if (
|
||||
µb.userSettings.advancedUserEnabled &&
|
||||
µb.sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -413,7 +419,7 @@ api.retrieve = function(details) {
|
|||
}
|
||||
};
|
||||
|
||||
api.apply = function(doc, details) {
|
||||
htmlFilteringEngine.apply = function(doc, details) {
|
||||
docRegister = doc;
|
||||
let modified = false;
|
||||
for ( const selector of details.selectors.plains ) {
|
||||
|
@ -430,19 +436,17 @@ api.apply = function(doc, details) {
|
|||
return modified;
|
||||
};
|
||||
|
||||
api.toSelfie = function() {
|
||||
htmlFilteringEngine.toSelfie = function() {
|
||||
return filterDB.toSelfie();
|
||||
};
|
||||
|
||||
api.fromSelfie = function(selfie) {
|
||||
htmlFilteringEngine.fromSelfie = function(selfie) {
|
||||
filterDB.fromSelfie(selfie);
|
||||
pselectors.clear();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.htmlFilteringEngine = api;
|
||||
export default htmlFilteringEngine;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,15 +23,21 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import logger from './logger.js';
|
||||
import µb from './background.js';
|
||||
import { entityFromDomain } from './uri-utils.js';
|
||||
import µBlock from './background.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
StaticExtFilteringHostnameDB,
|
||||
StaticExtFilteringSessionDB,
|
||||
} from './static-ext-filtering-db.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const µb = µBlock;
|
||||
const duplicates = new Set();
|
||||
const filterDB = new µb.staticExtFilteringEngine.HostnameBasedDB(1);
|
||||
const sessionFilterDB = new µb.staticExtFilteringEngine.SessionDB();
|
||||
const filterDB = new StaticExtFilteringHostnameDB(1);
|
||||
const sessionFilterDB = new StaticExtFilteringSessionDB();
|
||||
|
||||
const $headers = new Set();
|
||||
const $exceptions = new Set();
|
||||
|
@ -62,7 +68,7 @@ const logOne = function(isException, token, fctxt) {
|
|||
.toLogger();
|
||||
};
|
||||
|
||||
const api = {
|
||||
const httpheaderFilteringEngine = {
|
||||
get acceptedCount() {
|
||||
return acceptedCount;
|
||||
},
|
||||
|
@ -71,19 +77,19 @@ const api = {
|
|||
}
|
||||
};
|
||||
|
||||
api.reset = function() {
|
||||
httpheaderFilteringEngine.reset = function() {
|
||||
filterDB.clear();
|
||||
duplicates.clear();
|
||||
acceptedCount = 0;
|
||||
discardedCount = 0;
|
||||
};
|
||||
|
||||
api.freeze = function() {
|
||||
httpheaderFilteringEngine.freeze = function() {
|
||||
duplicates.clear();
|
||||
filterDB.collectGarbage();
|
||||
};
|
||||
|
||||
api.compile = function(parser, writer) {
|
||||
httpheaderFilteringEngine.compile = function(parser, writer) {
|
||||
writer.select(µb.compiledHTTPHeaderSection);
|
||||
|
||||
const { compiled, exception } = parser.result;
|
||||
|
@ -117,7 +123,7 @@ api.compile = function(parser, writer) {
|
|||
}
|
||||
};
|
||||
|
||||
api.compileTemporary = function(parser) {
|
||||
httpheaderFilteringEngine.compileTemporary = function(parser) {
|
||||
return {
|
||||
session: sessionFilterDB,
|
||||
selector: parser.result.compiled.slice(15, -1),
|
||||
|
@ -129,7 +135,7 @@ api.compileTemporary = function(parser) {
|
|||
// ^ ^
|
||||
// 15 -1
|
||||
|
||||
api.fromCompiledContent = function(reader) {
|
||||
httpheaderFilteringEngine.fromCompiledContent = function(reader) {
|
||||
reader.select(µb.compiledHTTPHeaderSection);
|
||||
|
||||
while ( reader.next() ) {
|
||||
|
@ -146,11 +152,11 @@ api.fromCompiledContent = function(reader) {
|
|||
}
|
||||
};
|
||||
|
||||
api.getSession = function() {
|
||||
httpheaderFilteringEngine.getSession = function() {
|
||||
return sessionFilterDB;
|
||||
};
|
||||
|
||||
api.apply = function(fctxt, headers) {
|
||||
httpheaderFilteringEngine.apply = function(fctxt, headers) {
|
||||
if ( filterDB.size === 0 ) { return; }
|
||||
|
||||
const hostname = fctxt.getHostname();
|
||||
|
@ -178,13 +184,12 @@ api.apply = function(fctxt, headers) {
|
|||
// Do not filter response headers if the site is under an `allow` rule.
|
||||
if (
|
||||
µb.userSettings.advancedUserEnabled &&
|
||||
µb.sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasGlobalException = $exceptions.has('');
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
|
||||
let modified = false;
|
||||
|
||||
|
@ -194,13 +199,13 @@ api.apply = function(fctxt, headers) {
|
|||
if ( i === -1 ) { break; }
|
||||
const isExcepted = hasGlobalException || $exceptions.has(name);
|
||||
if ( isExcepted ) {
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logOne(true, hasGlobalException ? '' : name, fctxt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
headers.splice(i, 1);
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logOne(false, name, fctxt);
|
||||
}
|
||||
modified = true;
|
||||
|
@ -210,18 +215,16 @@ api.apply = function(fctxt, headers) {
|
|||
return modified;
|
||||
};
|
||||
|
||||
api.toSelfie = function() {
|
||||
httpheaderFilteringEngine.toSelfie = function() {
|
||||
return filterDB.toSelfie();
|
||||
};
|
||||
|
||||
api.fromSelfie = function(selfie) {
|
||||
httpheaderFilteringEngine.fromSelfie = function(selfie) {
|
||||
filterDB.fromSelfie(selfie);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µb.httpheaderFilteringEngine = api;
|
||||
export default httpheaderFilteringEngine;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,10 +23,6 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
let buffer = null;
|
||||
let lastReadTime = 0;
|
||||
let writePtr = 0;
|
||||
|
@ -40,10 +36,10 @@ const janitor = ( ) => {
|
|||
buffer !== null &&
|
||||
lastReadTime < (Date.now() - logBufferObsoleteAfter)
|
||||
) {
|
||||
api.enabled = false;
|
||||
logger.enabled = false;
|
||||
buffer = null;
|
||||
writePtr = 0;
|
||||
api.ownerId = undefined;
|
||||
logger.ownerId = undefined;
|
||||
vAPI.messaging.broadcast({ what: 'loggerDisabled' });
|
||||
}
|
||||
if ( buffer !== null ) {
|
||||
|
@ -58,7 +54,7 @@ const boxEntry = function(details) {
|
|||
return JSON.stringify(details);
|
||||
};
|
||||
|
||||
const api = {
|
||||
const logger = {
|
||||
enabled: false,
|
||||
ownerId: undefined,
|
||||
writeOne: function(details) {
|
||||
|
@ -87,8 +83,6 @@ const api = {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.logger = api;
|
||||
export default logger;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
@ -46,7 +46,7 @@ let ttlTimer;
|
|||
let ttlDelay = 60000;
|
||||
|
||||
const init = function() {
|
||||
ttlDelay = µBlock.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 + 15000;
|
||||
ttlDelay = µb.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 + 15000;
|
||||
if ( lz4CodecInstance === null ) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ const init = function() {
|
|||
}
|
||||
if ( pendingInitialization === undefined ) {
|
||||
let flavor;
|
||||
if ( µBlock.hiddenSettings.disableWebAssembly === true ) {
|
||||
if ( µb.hiddenSettings.disableWebAssembly === true ) {
|
||||
flavor = 'js';
|
||||
}
|
||||
pendingInitialization = lz4BlockCodec.createInstance(flavor)
|
||||
|
@ -155,7 +155,7 @@ const decodeValue = function(inputArray) {
|
|||
return s;
|
||||
};
|
||||
|
||||
µBlock.lz4Codec = {
|
||||
const lz4Codec = {
|
||||
// Arguments:
|
||||
// dataIn: must be a string
|
||||
// Returns:
|
||||
|
@ -199,3 +199,7 @@ const decodeValue = function(inputArray) {
|
|||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export default lz4Codec;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -26,7 +26,30 @@
|
|||
import '../lib/publicsuffixlist/publicsuffixlist.js';
|
||||
import '../lib/punycode.js';
|
||||
|
||||
import cacheStorage from './cachestorage.js';
|
||||
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
||||
import globals from './globals.js';
|
||||
import logger from './logger.js';
|
||||
import lz4Codec from './lz4.js';
|
||||
import io from './assets.js';
|
||||
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
||||
import staticExtFilteringEngine from './static-ext-filtering.js';
|
||||
import staticFilteringReverseLookup from './reverselookup.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
import { StaticFilteringParser } from './static-filtering-parser.js';
|
||||
import { webRequest } from './traffic.js';
|
||||
|
||||
import {
|
||||
permanentFirewall,
|
||||
sessionFirewall,
|
||||
} from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
permanentSwitches,
|
||||
sessionSwitches,
|
||||
} from './hnswitches.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
|
@ -36,8 +59,10 @@ import {
|
|||
isNetworkURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import { StaticFilteringParser } from './static-filtering-parser.js';
|
||||
import µBlock from './background.js';
|
||||
import {
|
||||
permanentURLFiltering,
|
||||
sessionURLFiltering,
|
||||
} from './url-net-filtering.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -56,8 +81,6 @@ import µBlock from './background.js';
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
const clickToLoad = function(request, sender) {
|
||||
const { tabId, frameId } = sender;
|
||||
if ( tabId === undefined || frameId === undefined ) { return false; }
|
||||
|
@ -81,7 +104,7 @@ const onMessage = function(request, sender, callback) {
|
|||
switch ( request.what ) {
|
||||
case 'getAssetContent':
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/417
|
||||
µb.assets.get(request.url, {
|
||||
io.get(request.url, {
|
||||
dontCache: true,
|
||||
needSourceURL: true,
|
||||
}).then(result => {
|
||||
|
@ -90,7 +113,7 @@ const onMessage = function(request, sender, callback) {
|
|||
return;
|
||||
|
||||
case 'listsFromNetFilter':
|
||||
µb.staticFilteringReverseLookup.fromNetFilter(
|
||||
staticFilteringReverseLookup.fromNetFilter(
|
||||
request.rawFilter
|
||||
).then(response => {
|
||||
callback(response);
|
||||
|
@ -98,7 +121,7 @@ const onMessage = function(request, sender, callback) {
|
|||
return;
|
||||
|
||||
case 'listsFromCosmeticFilter':
|
||||
µb.staticFilteringReverseLookup.fromCosmeticFilter(
|
||||
staticFilteringReverseLookup.fromCosmeticFilter(
|
||||
request
|
||||
).then(response => {
|
||||
callback(response);
|
||||
|
@ -115,9 +138,9 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
case 'sfneBenchmark':
|
||||
µb.loadBenchmarkDataset().then(requests => {
|
||||
µb.staticNetFilteringEngine.benchmark(
|
||||
staticNetFilteringEngine.benchmark(
|
||||
requests,
|
||||
{ redirectEngine: µb.redirectEngine }
|
||||
{ redirectEngine }
|
||||
).then(result => {
|
||||
callback(result);
|
||||
});
|
||||
|
@ -146,7 +169,7 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
case 'forceUpdateAssets':
|
||||
µb.scheduleAssetUpdater(0);
|
||||
µb.assets.updateStart({
|
||||
io.updateStart({
|
||||
delay: µb.hiddenSettings.manualUpdateAssetFetchPeriod
|
||||
});
|
||||
break;
|
||||
|
@ -241,8 +264,6 @@ vAPI.messaging.setup(onMessage);
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
const createCounts = ( ) => {
|
||||
return {
|
||||
blocked: { any: 0, frame: 0, script: 0 },
|
||||
|
@ -291,7 +312,7 @@ const firewallRuleTypes = [
|
|||
|
||||
const getFirewallRules = function(src, out) {
|
||||
const ruleset = out.firewallRules = {};
|
||||
const df = µb.sessionFirewall;
|
||||
const df = sessionFirewall;
|
||||
|
||||
for ( const type of firewallRuleTypes ) {
|
||||
const r = df.lookupRuleData('*', '*', type);
|
||||
|
@ -358,26 +379,26 @@ const popupDataFromTabId = function(tabId, tabTitle) {
|
|||
r.contentLastModified = pageStore.contentLastModified;
|
||||
getFirewallRules(rootHostname, r);
|
||||
r.canElementPicker = isNetworkURI(r.rawURL);
|
||||
r.noPopups = µb.sessionSwitches.evaluateZ(
|
||||
r.noPopups = sessionSwitches.evaluateZ(
|
||||
'no-popups',
|
||||
rootHostname
|
||||
);
|
||||
r.popupBlockedCount = pageStore.popupBlockedCount;
|
||||
r.noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
|
||||
r.noCosmeticFiltering = sessionSwitches.evaluateZ(
|
||||
'no-cosmetic-filtering',
|
||||
rootHostname
|
||||
);
|
||||
r.noLargeMedia = µb.sessionSwitches.evaluateZ(
|
||||
r.noLargeMedia = sessionSwitches.evaluateZ(
|
||||
'no-large-media',
|
||||
rootHostname
|
||||
);
|
||||
r.largeMediaCount = pageStore.largeMediaCount;
|
||||
r.noRemoteFonts = µb.sessionSwitches.evaluateZ(
|
||||
r.noRemoteFonts = sessionSwitches.evaluateZ(
|
||||
'no-remote-fonts',
|
||||
rootHostname
|
||||
);
|
||||
r.remoteFontCount = pageStore.remoteFontCount;
|
||||
r.noScripting = µb.sessionSwitches.evaluateZ(
|
||||
r.noScripting = sessionSwitches.evaluateZ(
|
||||
'no-scripting',
|
||||
rootHostname
|
||||
);
|
||||
|
@ -386,14 +407,14 @@ const popupDataFromTabId = function(tabId, tabTitle) {
|
|||
getFirewallRules(undefined, r);
|
||||
}
|
||||
|
||||
r.matrixIsDirty = µb.sessionFirewall.hasSameRules(
|
||||
µb.permanentFirewall,
|
||||
r.matrixIsDirty = sessionFirewall.hasSameRules(
|
||||
permanentFirewall,
|
||||
rootHostname,
|
||||
r.hostnameDict
|
||||
) === false;
|
||||
if ( r.matrixIsDirty === false ) {
|
||||
r.matrixIsDirty = µb.sessionSwitches.hasSameRules(
|
||||
µb.permanentSwitches,
|
||||
r.matrixIsDirty = sessionSwitches.hasSameRules(
|
||||
permanentSwitches,
|
||||
rootHostname
|
||||
) === false;
|
||||
}
|
||||
|
@ -470,17 +491,17 @@ const onMessage = function(request, sender, callback) {
|
|||
break;
|
||||
|
||||
case 'revertFirewallRules':
|
||||
µb.sessionFirewall.copyRules(
|
||||
µb.permanentFirewall,
|
||||
sessionFirewall.copyRules(
|
||||
permanentFirewall,
|
||||
request.srcHostname,
|
||||
request.desHostnames
|
||||
);
|
||||
µb.sessionSwitches.copyRules(
|
||||
µb.permanentSwitches,
|
||||
sessionSwitches.copyRules(
|
||||
permanentSwitches,
|
||||
request.srcHostname
|
||||
);
|
||||
// https://github.com/gorhill/uBlock/issues/188
|
||||
µb.cosmeticFilteringEngine.removeFromSelectorCache(
|
||||
cosmeticFilteringEngine.removeFromSelectorCache(
|
||||
request.srcHostname,
|
||||
'net'
|
||||
);
|
||||
|
@ -490,8 +511,8 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
case 'saveFirewallRules':
|
||||
if (
|
||||
µb.permanentFirewall.copyRules(
|
||||
µb.sessionFirewall,
|
||||
permanentFirewall.copyRules(
|
||||
sessionFirewall,
|
||||
request.srcHostname,
|
||||
request.desHostnames
|
||||
)
|
||||
|
@ -499,8 +520,8 @@ const onMessage = function(request, sender, callback) {
|
|||
µb.savePermanentFirewallRules();
|
||||
}
|
||||
if (
|
||||
µb.permanentSwitches.copyRules(
|
||||
µb.sessionSwitches,
|
||||
permanentSwitches.copyRules(
|
||||
sessionSwitches,
|
||||
request.srcHostname
|
||||
)
|
||||
) {
|
||||
|
@ -556,8 +577,6 @@ vAPI.messaging.listen({
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
const retrieveContentScriptParameters = async function(sender, request) {
|
||||
if ( µb.readyToFilter !== true ) { return; }
|
||||
const { tabId, frameId } = sender;
|
||||
|
@ -575,7 +594,6 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
request.url = pageStore.getEffectiveFrameURL(sender);
|
||||
}
|
||||
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
const noSpecificCosmeticFiltering =
|
||||
pageStore.shouldApplySpecificCosmeticFilters(frameId) === false;
|
||||
const noGenericCosmeticFiltering =
|
||||
|
@ -594,13 +612,13 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
request.entity = entityFromDomain(request.domain);
|
||||
|
||||
response.specificCosmeticFilters =
|
||||
µb.cosmeticFilteringEngine.retrieveSpecificSelectors(request, response);
|
||||
cosmeticFilteringEngine.retrieveSpecificSelectors(request, response);
|
||||
|
||||
// The procedural filterer's code is loaded only when needed and must be
|
||||
// present before returning response to caller.
|
||||
if (
|
||||
Array.isArray(response.specificCosmeticFilters.proceduralFilters) || (
|
||||
loggerEnabled &&
|
||||
logger.enabled &&
|
||||
response.specificCosmeticFilters.exceptedFilters.length !== 0
|
||||
)
|
||||
) {
|
||||
|
@ -620,14 +638,14 @@ const retrieveContentScriptParameters = async function(sender, request) {
|
|||
µb.canInjectScriptletsNow === false ||
|
||||
isNetworkURI(sender.frameURL) === false
|
||||
) {
|
||||
response.scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
||||
response.scriptlets = scriptletFilteringEngine.retrieve(request);
|
||||
}
|
||||
|
||||
// https://github.com/NanoMeow/QuickReports/issues/6#issuecomment-414516623
|
||||
// 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 ) {
|
||||
if ( logger.enabled ) {
|
||||
if (
|
||||
noSpecificCosmeticFiltering === false ||
|
||||
noGenericCosmeticFiltering === false
|
||||
|
@ -666,7 +684,7 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
switch ( request.what ) {
|
||||
case 'cosmeticFiltersInjected':
|
||||
µb.cosmeticFilteringEngine.addToSelectorCache(request);
|
||||
cosmeticFilteringEngine.addToSelectorCache(request);
|
||||
break;
|
||||
|
||||
case 'getCollapsibleBlockedRequests':
|
||||
|
@ -674,7 +692,7 @@ const onMessage = function(request, sender, callback) {
|
|||
id: request.id,
|
||||
hash: request.hash,
|
||||
netSelectorCacheCountMax:
|
||||
µb.cosmeticFilteringEngine.netSelectorCacheCountMax,
|
||||
cosmeticFilteringEngine.netSelectorCacheCountMax,
|
||||
};
|
||||
if (
|
||||
µb.userSettings.collapseBlocked &&
|
||||
|
@ -705,7 +723,7 @@ const onMessage = function(request, sender, callback) {
|
|||
request.tabId = sender.tabId;
|
||||
request.frameId = sender.frameId;
|
||||
response = {
|
||||
result: µb.cosmeticFilteringEngine.retrieveGenericSelectors(request),
|
||||
result: cosmeticFilteringEngine.retrieveGenericSelectors(request),
|
||||
};
|
||||
break;
|
||||
|
||||
|
@ -735,8 +753,6 @@ vAPI.messaging.listen({
|
|||
// >>>>> start of local scope
|
||||
|
||||
const onMessage = function(request, sender, callback) {
|
||||
const µb = µBlock;
|
||||
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
// The procedural filterer must be present in case the user wants to
|
||||
|
@ -801,7 +817,7 @@ const fromBase64 = function(encoded) {
|
|||
}
|
||||
let u8array;
|
||||
try {
|
||||
u8array = µBlock.denseBase64.decode(encoded);
|
||||
u8array = µb.denseBase64.decode(encoded);
|
||||
} catch(ex) {
|
||||
}
|
||||
return Promise.resolve(u8array !== undefined ? u8array : encoded);
|
||||
|
@ -809,22 +825,22 @@ const fromBase64 = function(encoded) {
|
|||
|
||||
const toBase64 = function(data) {
|
||||
const value = data instanceof Uint8Array
|
||||
? µBlock.denseBase64.encode(data)
|
||||
? µb.denseBase64.encode(data)
|
||||
: data;
|
||||
return Promise.resolve(value);
|
||||
};
|
||||
|
||||
const compress = function(json) {
|
||||
return µBlock.lz4Codec.encode(json, toBase64);
|
||||
return lz4Codec.encode(json, toBase64);
|
||||
};
|
||||
|
||||
const decompress = function(encoded) {
|
||||
return µBlock.lz4Codec.decode(encoded, fromBase64);
|
||||
return lz4Codec.decode(encoded, fromBase64);
|
||||
};
|
||||
|
||||
const onMessage = function(request, sender, callback) {
|
||||
// Cloud storage support is optional.
|
||||
if ( µBlock.cloudStorageSupported !== true ) {
|
||||
if ( µb.cloudStorageSupported !== true ) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
@ -833,7 +849,7 @@ const onMessage = function(request, sender, callback) {
|
|||
switch ( request.what ) {
|
||||
case 'cloudGetOptions':
|
||||
vAPI.cloud.getOptions(function(options) {
|
||||
options.enabled = µBlock.userSettings.cloudStorageEnabled === true;
|
||||
options.enabled = µb.userSettings.cloudStorageEnabled === true;
|
||||
callback(options);
|
||||
});
|
||||
return;
|
||||
|
@ -849,7 +865,7 @@ const onMessage = function(request, sender, callback) {
|
|||
});
|
||||
|
||||
case 'cloudPush':
|
||||
if ( µBlock.hiddenSettings.cloudStorageCompression ) {
|
||||
if ( µb.hiddenSettings.cloudStorageCompression ) {
|
||||
request.encode = compress;
|
||||
}
|
||||
return vAPI.cloud.push(request).then(result => {
|
||||
|
@ -901,8 +917,6 @@ vAPI.messaging.listen({
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
// Settings
|
||||
const getLocalData = async function() {
|
||||
const data = Object.assign({}, µb.restoreBackupSettings);
|
||||
|
@ -924,9 +938,9 @@ const backupUserData = async function() {
|
|||
hiddenSettings:
|
||||
µb.getModifiedSettings(µb.hiddenSettings, µb.hiddenSettingsDefault),
|
||||
whitelist: µb.arrayFromWhitelist(µb.netWhitelist),
|
||||
dynamicFilteringString: µb.permanentFirewall.toString(),
|
||||
urlFilteringString: µb.permanentURLFiltering.toString(),
|
||||
hostnameSwitchesString: µb.permanentSwitches.toString(),
|
||||
dynamicFilteringString: permanentFirewall.toString(),
|
||||
urlFilteringString: permanentURLFiltering.toString(),
|
||||
hostnameSwitchesString: permanentSwitches.toString(),
|
||||
userFilters: userFilters.content,
|
||||
};
|
||||
|
||||
|
@ -962,17 +976,17 @@ const restoreUserData = async function(request) {
|
|||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1102
|
||||
// Ensure all currently cached assets are flushed from storage AND memory.
|
||||
µb.assets.rmrf();
|
||||
io.rmrf();
|
||||
|
||||
// If we are going to restore all, might as well wipe out clean local
|
||||
// storages
|
||||
await Promise.all([
|
||||
µb.cacheStorage.clear(),
|
||||
cacheStorage.clear(),
|
||||
vAPI.storage.clear(),
|
||||
]);
|
||||
|
||||
// Restore block stats
|
||||
µBlock.saveLocalSettings();
|
||||
µb.saveLocalSettings();
|
||||
|
||||
// Restore user data
|
||||
vAPI.storage.set(userData.userSettings);
|
||||
|
@ -980,7 +994,7 @@ const restoreUserData = async function(request) {
|
|||
// Restore advanced settings.
|
||||
let hiddenSettings = userData.hiddenSettings;
|
||||
if ( hiddenSettings instanceof Object === false ) {
|
||||
hiddenSettings = µBlock.hiddenSettingsFromString(
|
||||
hiddenSettings = µb.hiddenSettingsFromString(
|
||||
userData.hiddenSettingsString || ''
|
||||
);
|
||||
}
|
||||
|
@ -1027,7 +1041,7 @@ const restoreUserData = async function(request) {
|
|||
// quite attached to numbers
|
||||
const resetUserData = async function() {
|
||||
await Promise.all([
|
||||
µb.cacheStorage.clear(),
|
||||
cacheStorage.clear(),
|
||||
vAPI.storage.clear(),
|
||||
]);
|
||||
|
||||
|
@ -1056,17 +1070,17 @@ const getLists = async function(callback) {
|
|||
autoUpdate: µb.userSettings.autoUpdate,
|
||||
available: null,
|
||||
cache: null,
|
||||
cosmeticFilterCount: µb.cosmeticFilteringEngine.getFilterCount(),
|
||||
cosmeticFilterCount: cosmeticFilteringEngine.getFilterCount(),
|
||||
current: µb.availableFilterLists,
|
||||
ignoreGenericCosmeticFilters: µb.userSettings.ignoreGenericCosmeticFilters,
|
||||
isUpdating: µb.assets.isUpdating(),
|
||||
netFilterCount: µb.staticNetFilteringEngine.getFilterCount(),
|
||||
isUpdating: io.isUpdating(),
|
||||
netFilterCount: staticNetFilteringEngine.getFilterCount(),
|
||||
parseCosmeticFilters: µb.userSettings.parseAllABPHideFilters,
|
||||
userFiltersPath: µb.userFiltersPath
|
||||
};
|
||||
const [ lists, metadata ] = await Promise.all([
|
||||
µb.getAvailableLists(),
|
||||
µb.assets.metadata(),
|
||||
io.metadata(),
|
||||
]);
|
||||
r.available = lists;
|
||||
prepListEntries(r.available);
|
||||
|
@ -1099,14 +1113,14 @@ const getOriginHints = function() {
|
|||
const getRules = function() {
|
||||
return {
|
||||
permanentRules:
|
||||
µb.permanentFirewall.toArray().concat(
|
||||
µb.permanentSwitches.toArray(),
|
||||
µb.permanentURLFiltering.toArray()
|
||||
permanentFirewall.toArray().concat(
|
||||
permanentSwitches.toArray(),
|
||||
permanentURLFiltering.toArray()
|
||||
),
|
||||
sessionRules:
|
||||
µb.sessionFirewall.toArray().concat(
|
||||
µb.sessionSwitches.toArray(),
|
||||
µb.sessionURLFiltering.toArray()
|
||||
sessionFirewall.toArray().concat(
|
||||
sessionSwitches.toArray(),
|
||||
sessionURLFiltering.toArray()
|
||||
),
|
||||
pslSelfie: globals.publicSuffixList.toSelfie(),
|
||||
};
|
||||
|
@ -1115,13 +1129,13 @@ const getRules = function() {
|
|||
const modifyRuleset = function(details) {
|
||||
let swRuleset, hnRuleset, urlRuleset;
|
||||
if ( details.permanent ) {
|
||||
swRuleset = µb.permanentSwitches;
|
||||
hnRuleset = µb.permanentFirewall;
|
||||
urlRuleset = µb.permanentURLFiltering;
|
||||
swRuleset = permanentSwitches;
|
||||
hnRuleset = permanentFirewall;
|
||||
urlRuleset = permanentURLFiltering;
|
||||
} else {
|
||||
swRuleset = µb.sessionSwitches;
|
||||
hnRuleset = µb.sessionFirewall;
|
||||
urlRuleset = µb.sessionURLFiltering;
|
||||
swRuleset = sessionSwitches;
|
||||
hnRuleset = sessionFirewall;
|
||||
urlRuleset = sessionURLFiltering;
|
||||
}
|
||||
let toRemove = new Set(details.toRemove.trim().split(/\s*[\n\r]+\s*/));
|
||||
for ( let rule of toRemove ) {
|
||||
|
@ -1240,7 +1254,7 @@ const onMessage = function(request, sender, callback) {
|
|||
case 'getAutoCompleteDetails':
|
||||
response = {};
|
||||
if ( (request.hintUpdateToken || 0) === 0 ) {
|
||||
response.redirectResources = µb.redirectEngine.getResourceDetails();
|
||||
response.redirectResources = redirectEngine.getResourceDetails();
|
||||
response.preparseDirectiveTokens = µb.preparseDirectives.getTokens();
|
||||
response.preparseDirectiveHints = µb.preparseDirectives.getHints();
|
||||
response.expertMode = µb.hiddenSettings.filterAuthorMode;
|
||||
|
@ -1257,22 +1271,22 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
case 'modifyRuleset':
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/772
|
||||
µb.cosmeticFilteringEngine.removeFromSelectorCache('*');
|
||||
cosmeticFilteringEngine.removeFromSelectorCache('*');
|
||||
modifyRuleset(request);
|
||||
response = getRules();
|
||||
break;
|
||||
|
||||
case 'purgeAllCaches':
|
||||
if ( request.hard ) {
|
||||
µb.assets.remove(/./);
|
||||
io.remove(/./);
|
||||
} else {
|
||||
µb.assets.purge(/./, 'public_suffix_list.dat');
|
||||
io.purge(/./, 'public_suffix_list.dat');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'purgeCache':
|
||||
µb.assets.purge(request.assetKey);
|
||||
µb.assets.remove('compiled/' + request.assetKey);
|
||||
io.purge(request.assetKey);
|
||||
io.remove('compiled/' + request.assetKey);
|
||||
break;
|
||||
|
||||
case 'readHiddenSettings':
|
||||
|
@ -1325,7 +1339,6 @@ vAPI.messaging.listen({
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
const extensionOriginURL = vAPI.getURL('');
|
||||
const documentBlockedURL = vAPI.getURL('document-blocked.html');
|
||||
|
||||
|
@ -1333,7 +1346,7 @@ const getLoggerData = async function(details, activeTabId, callback) {
|
|||
const response = {
|
||||
activeTabId,
|
||||
colorBlind: µb.userSettings.colorBlindFriendly,
|
||||
entries: µb.logger.readAll(details.ownerId),
|
||||
entries: logger.readAll(details.ownerId),
|
||||
filterAuthorMode: µb.hiddenSettings.filterAuthorMode,
|
||||
tabIdsToken: µb.pageStoresToken,
|
||||
tooltips: µb.userSettings.tooltipsDisabled === false
|
||||
|
@ -1386,8 +1399,8 @@ const getURLFilteringData = function(details) {
|
|||
dirty: false,
|
||||
colors: colors
|
||||
};
|
||||
const suf = µb.sessionURLFiltering;
|
||||
const puf = µb.permanentURLFiltering;
|
||||
const suf = sessionURLFiltering;
|
||||
const puf = permanentURLFiltering;
|
||||
const urls = details.urls;
|
||||
const context = details.context;
|
||||
const type = details.type;
|
||||
|
@ -1416,7 +1429,7 @@ const compileTemporaryException = function(filter) {
|
|||
const parser = new StaticFilteringParser();
|
||||
parser.analyze(filter);
|
||||
if ( parser.shouldDiscard() ) { return; }
|
||||
return µb.staticExtFilteringEngine.compileTemporary(parser);
|
||||
return staticExtFilteringEngine.compileTemporary(parser);
|
||||
};
|
||||
|
||||
const toggleTemporaryException = function(details) {
|
||||
|
@ -1443,8 +1456,8 @@ const onMessage = function(request, sender, callback) {
|
|||
switch ( request.what ) {
|
||||
case 'readAll':
|
||||
if (
|
||||
µb.logger.ownerId !== undefined &&
|
||||
µb.logger.ownerId !== request.ownerId
|
||||
logger.ownerId !== undefined &&
|
||||
logger.ownerId !== request.ownerId
|
||||
) {
|
||||
return callback({ unavailable: true });
|
||||
}
|
||||
|
@ -1466,14 +1479,14 @@ const onMessage = function(request, sender, callback) {
|
|||
break;
|
||||
|
||||
case 'releaseView':
|
||||
if ( request.ownerId === µb.logger.ownerId ) {
|
||||
µb.logger.ownerId = undefined;
|
||||
if ( request.ownerId === logger.ownerId ) {
|
||||
logger.ownerId = undefined;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'saveURLFilteringRules':
|
||||
response = µb.permanentURLFiltering.copyRules(
|
||||
µb.sessionURLFiltering,
|
||||
response = permanentURLFiltering.copyRules(
|
||||
sessionURLFiltering,
|
||||
request.context,
|
||||
request.urls,
|
||||
request.type
|
||||
|
@ -1539,7 +1552,7 @@ const onMessage = function(request, sender, callback) {
|
|||
break;
|
||||
|
||||
case 'temporarilyWhitelistDocument':
|
||||
µBlock.webRequest.strictBlockBypass(request.hostname);
|
||||
webRequest.strictBlockBypass(request.hostname);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1568,10 +1581,8 @@ vAPI.messaging.listen({
|
|||
{
|
||||
// >>>>> start of local scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
const logCosmeticFilters = function(tabId, details) {
|
||||
if ( µb.logger.enabled === false ) { return; }
|
||||
if ( logger.enabled === false ) { return; }
|
||||
|
||||
const filter = { source: 'cosmetic', raw: '' };
|
||||
const fctxt = µb.filteringContext.duplicate();
|
||||
|
@ -1588,7 +1599,7 @@ const logCosmeticFilters = function(tabId, details) {
|
|||
};
|
||||
|
||||
const logCSPViolations = function(pageStore, request) {
|
||||
if ( µb.logger.enabled === false || pageStore === null ) {
|
||||
if ( logger.enabled === false || pageStore === null ) {
|
||||
return false;
|
||||
}
|
||||
if ( request.violations.length === 0 ) {
|
||||
|
@ -1606,7 +1617,7 @@ const logCSPViolations = function(pageStore, request) {
|
|||
cspData = new Map();
|
||||
|
||||
const staticDirectives =
|
||||
µb.staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp');
|
||||
staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp');
|
||||
if ( staticDirectives !== undefined ) {
|
||||
for ( const directive of staticDirectives ) {
|
||||
if ( directive.result !== 1 ) { continue; }
|
||||
|
@ -1691,7 +1702,7 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
switch ( request.what ) {
|
||||
case 'inlinescriptFound':
|
||||
if ( µb.logger.enabled && pageStore !== null ) {
|
||||
if ( logger.enabled && pageStore !== null ) {
|
||||
const fctxt = µb.filteringContext.duplicate();
|
||||
fctxt.fromTabId(tabId)
|
||||
.setType('inline-script')
|
||||
|
|
|
@ -23,14 +23,21 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import contextMenu from './contextmenu.js';
|
||||
import logger from './logger.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
import { sessionSwitches } from './hnswitches.js';
|
||||
import { sessionURLFiltering } from './url-net-filtering.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
hostnameFromURI,
|
||||
isNetworkURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
A PageRequestStore object is used to store net requests in two ways:
|
||||
|
@ -42,10 +49,6 @@ To create a log of net requests
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const NetFilteringResultCache = class {
|
||||
constructor() {
|
||||
this.init();
|
||||
|
@ -217,18 +220,18 @@ const FrameStore = class {
|
|||
}
|
||||
this._cosmeticFilteringBits = 0b11;
|
||||
{
|
||||
const result = µb.staticNetFilteringEngine.matchRequestReverse(
|
||||
const result = staticNetFilteringEngine.matchRequestReverse(
|
||||
'specifichide',
|
||||
this.rawURL
|
||||
);
|
||||
if ( result !== 0 && µb.logger.enabled ) {
|
||||
µBlock.filteringContext
|
||||
if ( result !== 0 && logger.enabled ) {
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('network')
|
||||
.setType('specifichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.setFilter(staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
if ( result === 2 ) {
|
||||
|
@ -236,18 +239,18 @@ const FrameStore = class {
|
|||
}
|
||||
}
|
||||
{
|
||||
const result = µb.staticNetFilteringEngine.matchRequestReverse(
|
||||
const result = staticNetFilteringEngine.matchRequestReverse(
|
||||
'generichide',
|
||||
this.rawURL
|
||||
);
|
||||
if ( result !== 0 && µb.logger.enabled ) {
|
||||
µBlock.filteringContext
|
||||
if ( result !== 0 && logger.enabled ) {
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('network')
|
||||
.setType('generichide')
|
||||
.setFilter(µb.staticNetFilteringEngine.toLogData())
|
||||
.setFilter(staticNetFilteringEngine.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
if ( result === 2 ) {
|
||||
|
@ -559,18 +562,18 @@ const PageStore = class {
|
|||
if ( this._noCosmeticFiltering === undefined ) {
|
||||
this._noCosmeticFiltering = this.getNetFilteringSwitch() === false;
|
||||
if ( this._noCosmeticFiltering === false ) {
|
||||
this._noCosmeticFiltering = µb.sessionSwitches.evaluateZ(
|
||||
this._noCosmeticFiltering = sessionSwitches.evaluateZ(
|
||||
'no-cosmetic-filtering',
|
||||
this.tabHostname
|
||||
) === true;
|
||||
if ( this._noCosmeticFiltering && µb.logger.enabled ) {
|
||||
if ( this._noCosmeticFiltering && logger.enabled ) {
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(this.tabId)
|
||||
.setURL(this.rawURL)
|
||||
.setRealm('cosmetic')
|
||||
.setType('dom')
|
||||
.setFilter(µb.sessionSwitches.toLogData())
|
||||
.setFilter(sessionSwitches.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
}
|
||||
|
@ -620,12 +623,12 @@ const PageStore = class {
|
|||
allFrames: true,
|
||||
runAt: 'document_idle',
|
||||
});
|
||||
µb.contextMenu.update(this.tabId);
|
||||
contextMenu.update(this.tabId);
|
||||
}
|
||||
|
||||
temporarilyAllowLargeMediaElements(state) {
|
||||
this.largeMediaCount = 0;
|
||||
µb.contextMenu.update(this.tabId);
|
||||
contextMenu.update(this.tabId);
|
||||
if ( state ) {
|
||||
this.allowLargeMediaElementsUntil = 0;
|
||||
this.allowLargeMediaElementsRegex = undefined;
|
||||
|
@ -784,32 +787,32 @@ const PageStore = class {
|
|||
}
|
||||
|
||||
const requestType = fctxt.type;
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
const loggerEnabled = logger.enabled;
|
||||
|
||||
// Dynamic URL filtering.
|
||||
let result = µb.sessionURLFiltering.evaluateZ(
|
||||
let result = sessionURLFiltering.evaluateZ(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.url,
|
||||
requestType
|
||||
);
|
||||
if ( result !== 0 && loggerEnabled ) {
|
||||
fctxt.filter = µb.sessionURLFiltering.toLogData();
|
||||
fctxt.filter = sessionURLFiltering.toLogData();
|
||||
}
|
||||
|
||||
// Dynamic hostname/type filtering.
|
||||
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
||||
result = µb.sessionFirewall.evaluateCellZY(
|
||||
result = sessionFirewall.evaluateCellZY(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.getHostname(),
|
||||
requestType
|
||||
);
|
||||
if ( result !== 0 && result !== 3 && loggerEnabled ) {
|
||||
fctxt.filter = µb.sessionFirewall.toLogData();
|
||||
fctxt.filter = sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
// Static filtering has lowest precedence.
|
||||
const snfe = µb.staticNetFilteringEngine;
|
||||
const snfe = staticNetFilteringEngine;
|
||||
if ( result === 0 || result === 3 ) {
|
||||
result = snfe.matchRequest(fctxt);
|
||||
if ( result !== 0 ) {
|
||||
|
@ -873,19 +876,19 @@ const PageStore = class {
|
|||
|
||||
if ( this.getNetFilteringSwitch(fctxt) === false ) { return 0; }
|
||||
|
||||
let result = µb.staticNetFilteringEngine.matchHeaders(fctxt, headers);
|
||||
let result = staticNetFilteringEngine.matchHeaders(fctxt, headers);
|
||||
if ( result === 0 ) { return 0; }
|
||||
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
const loggerEnabled = logger.enabled;
|
||||
if ( loggerEnabled ) {
|
||||
fctxt.filter = µb.staticNetFilteringEngine.toLogData();
|
||||
fctxt.filter = staticNetFilteringEngine.toLogData();
|
||||
}
|
||||
|
||||
// Dynamic filtering allow rules
|
||||
// URL filtering
|
||||
if (
|
||||
result === 1 &&
|
||||
µb.sessionURLFiltering.evaluateZ(
|
||||
sessionURLFiltering.evaluateZ(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.url,
|
||||
fctxt.type
|
||||
|
@ -893,14 +896,14 @@ const PageStore = class {
|
|||
) {
|
||||
result = 2;
|
||||
if ( loggerEnabled ) {
|
||||
fctxt.filter = µb.sessionURLFiltering.toLogData();
|
||||
fctxt.filter = sessionURLFiltering.toLogData();
|
||||
}
|
||||
}
|
||||
// Hostname filtering
|
||||
if (
|
||||
result === 1 &&
|
||||
µb.userSettings.advancedUserEnabled &&
|
||||
µb.sessionFirewall.evaluateCellZY(
|
||||
sessionFirewall.evaluateCellZY(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.getHostname(),
|
||||
fctxt.type
|
||||
|
@ -908,7 +911,7 @@ const PageStore = class {
|
|||
) {
|
||||
result = 2;
|
||||
if ( loggerEnabled ) {
|
||||
fctxt.filter = µb.sessionFirewall.toLogData();
|
||||
fctxt.filter = sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -916,24 +919,24 @@ const PageStore = class {
|
|||
}
|
||||
|
||||
redirectBlockedRequest(fctxt) {
|
||||
const directives = µb.staticNetFilteringEngine.redirectRequest(
|
||||
µb.redirectEngine,
|
||||
const directives = staticNetFilteringEngine.redirectRequest(
|
||||
redirectEngine,
|
||||
fctxt
|
||||
);
|
||||
if ( directives === undefined ) { return; }
|
||||
if ( µb.logger.enabled !== true ) { return; }
|
||||
if ( logger.enabled !== true ) { return; }
|
||||
fctxt.pushFilters(directives.map(a => a.logData()));
|
||||
if ( fctxt.redirectURL === undefined ) { return; }
|
||||
fctxt.pushFilter({
|
||||
source: 'redirect',
|
||||
raw: µb.redirectEngine.resourceNameRegister
|
||||
raw: redirectEngine.resourceNameRegister
|
||||
});
|
||||
}
|
||||
|
||||
redirectNonBlockedRequest(fctxt) {
|
||||
const directives = µb.staticNetFilteringEngine.filterQuery(fctxt);
|
||||
const directives = staticNetFilteringEngine.filterQuery(fctxt);
|
||||
if ( directives === undefined ) { return; }
|
||||
if ( µb.logger.enabled !== true ) { return; }
|
||||
if ( logger.enabled !== true ) { return; }
|
||||
fctxt.pushFilters(directives.map(a => a.logData()));
|
||||
if ( fctxt.redirectURL === undefined ) { return; }
|
||||
fctxt.pushFilter({
|
||||
|
@ -944,13 +947,13 @@ const PageStore = class {
|
|||
|
||||
filterCSPReport(fctxt) {
|
||||
if (
|
||||
µb.sessionSwitches.evaluateZ(
|
||||
sessionSwitches.evaluateZ(
|
||||
'no-csp-reports',
|
||||
fctxt.getHostname()
|
||||
)
|
||||
) {
|
||||
if ( µb.logger.enabled ) {
|
||||
fctxt.filter = µb.sessionSwitches.toLogData();
|
||||
if ( logger.enabled ) {
|
||||
fctxt.filter = sessionSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -962,13 +965,13 @@ const PageStore = class {
|
|||
this.remoteFontCount += 1;
|
||||
}
|
||||
if (
|
||||
µb.sessionSwitches.evaluateZ(
|
||||
sessionSwitches.evaluateZ(
|
||||
'no-remote-fonts',
|
||||
fctxt.getTabHostname()
|
||||
) !== false
|
||||
) {
|
||||
if ( µb.logger.enabled ) {
|
||||
fctxt.filter = µb.sessionSwitches.toLogData();
|
||||
if ( logger.enabled ) {
|
||||
fctxt.filter = sessionSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -982,15 +985,15 @@ const PageStore = class {
|
|||
}
|
||||
if (
|
||||
netFiltering === false ||
|
||||
µb.sessionSwitches.evaluateZ(
|
||||
sessionSwitches.evaluateZ(
|
||||
'no-scripting',
|
||||
fctxt.getTabHostname()
|
||||
) === false
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
if ( µb.logger.enabled ) {
|
||||
fctxt.filter = µb.sessionSwitches.toLogData();
|
||||
if ( logger.enabled ) {
|
||||
fctxt.filter = sessionSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -1019,7 +1022,7 @@ const PageStore = class {
|
|||
return 0;
|
||||
}
|
||||
if (
|
||||
µb.sessionSwitches.evaluateZ(
|
||||
sessionSwitches.evaluateZ(
|
||||
'no-large-media',
|
||||
fctxt.getTabHostname()
|
||||
) !== true
|
||||
|
@ -1039,8 +1042,8 @@ const PageStore = class {
|
|||
}, 500);
|
||||
}
|
||||
|
||||
if ( µb.logger.enabled ) {
|
||||
fctxt.filter = µb.sessionSwitches.toLogData();
|
||||
if ( logger.enabled ) {
|
||||
fctxt.filter = sessionSwitches.toLogData();
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -1069,14 +1072,14 @@ const PageStore = class {
|
|||
}
|
||||
}
|
||||
if ( exceptCname === undefined ) {
|
||||
const result = µb.staticNetFilteringEngine.matchRequestReverse(
|
||||
const result = staticNetFilteringEngine.matchRequestReverse(
|
||||
'cname',
|
||||
frameStore instanceof Object
|
||||
? frameStore.rawURL
|
||||
: fctxt.getDocOrigin()
|
||||
);
|
||||
exceptCname = result === 2
|
||||
? µb.staticNetFilteringEngine.toLogData()
|
||||
? staticNetFilteringEngine.toLogData()
|
||||
: false;
|
||||
if ( frameStore instanceof Object ) {
|
||||
frameStore.exceptCname = exceptCname;
|
||||
|
@ -1128,6 +1131,6 @@ PageStore.prototype.collapsibleResources = new Set([
|
|||
PageStore.junkyard = [];
|
||||
PageStore.junkyardMax = 10;
|
||||
|
||||
µb.PageStore = PageStore;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export { PageStore };
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import io from './assets.js';
|
||||
import µb from './background.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -408,7 +409,7 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
|
|||
// No more data, add the resource.
|
||||
const name = this.aliases.get(fields[0]) || fields[0];
|
||||
const mime = fields[1];
|
||||
const content = µBlock.orphanizeString(
|
||||
const content = µb.orphanizeString(
|
||||
fields.slice(2).join(encoded ? '' : '\n')
|
||||
);
|
||||
this.resources.set(
|
||||
|
@ -436,14 +437,11 @@ const removeTopCommentBlock = function(text) {
|
|||
/******************************************************************************/
|
||||
|
||||
RedirectEngine.prototype.loadBuiltinResources = function() {
|
||||
// TODO: remove once usage of uBO 1.20.4 is widespread.
|
||||
µBlock.assets.remove('ublock-resources');
|
||||
|
||||
this.resources = new Map();
|
||||
this.aliases = new Map();
|
||||
|
||||
const fetches = [
|
||||
µBlock.assets.fetchText(
|
||||
io.fetchText(
|
||||
'/assets/resources/scriptlets.js'
|
||||
).then(result => {
|
||||
const content = result.content;
|
||||
|
@ -505,7 +503,7 @@ RedirectEngine.prototype.loadBuiltinResources = function() {
|
|||
continue;
|
||||
}
|
||||
fetches.push(
|
||||
µBlock.assets.fetch(
|
||||
io.fetch(
|
||||
`/web_accessible_resources/${name}?secret=${vAPI.warSecret()}`,
|
||||
{ responseType: details.data }
|
||||
).then(
|
||||
|
@ -547,7 +545,7 @@ RedirectEngine.prototype.getResourceDetails = function() {
|
|||
const resourcesSelfieVersion = 5;
|
||||
|
||||
RedirectEngine.prototype.selfieFromResources = function() {
|
||||
µBlock.assets.put(
|
||||
io.put(
|
||||
'compiled/redirectEngine/resources',
|
||||
JSON.stringify({
|
||||
version: resourcesSelfieVersion,
|
||||
|
@ -558,7 +556,7 @@ RedirectEngine.prototype.selfieFromResources = function() {
|
|||
};
|
||||
|
||||
RedirectEngine.prototype.resourcesFromSelfie = async function() {
|
||||
const result = await µBlock.assets.get('compiled/redirectEngine/resources');
|
||||
const result = await io.get('compiled/redirectEngine/resources');
|
||||
let selfie;
|
||||
try {
|
||||
selfie = JSON.parse(result.content);
|
||||
|
@ -580,13 +578,13 @@ RedirectEngine.prototype.resourcesFromSelfie = async function() {
|
|||
};
|
||||
|
||||
RedirectEngine.prototype.invalidateResourcesSelfie = function() {
|
||||
µBlock.assets.remove('compiled/redirectEngine/resources');
|
||||
io.remove('compiled/redirectEngine/resources');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
const redirectEngine = new RedirectEngine();
|
||||
|
||||
µBlock.redirectEngine = new RedirectEngine();
|
||||
export { redirectEngine };
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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 local scope
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const reBlockStart = /^#block-start-(\d+)\n/gm;
|
||||
let listEntries = Object.create(null);
|
||||
|
||||
const extractBlocks = function(content, begId, endId) {
|
||||
reBlockStart.lastIndex = 0;
|
||||
const out = [];
|
||||
let match = reBlockStart.exec(content);
|
||||
while ( match !== null ) {
|
||||
const beg = match.index + match[0].length;
|
||||
const blockId = parseInt(match[1], 10);
|
||||
if ( blockId >= begId && blockId < endId ) {
|
||||
const end = content.indexOf('#block-end-' + match[1], beg);
|
||||
out.push(content.slice(beg, end));
|
||||
reBlockStart.lastIndex = end;
|
||||
}
|
||||
match = reBlockStart.exec(content);
|
||||
}
|
||||
return out.join('\n');
|
||||
};
|
||||
|
||||
// https://github.com/MajkiIT/polish-ads-filter/issues/14768#issuecomment-536006312
|
||||
// Avoid reporting badfilter-ed filters.
|
||||
|
||||
const fromNetFilter = function(details) {
|
||||
const lists = [];
|
||||
const compiledFilter = details.compiledFilter;
|
||||
|
||||
for ( const assetKey in listEntries ) {
|
||||
const entry = listEntries[assetKey];
|
||||
if ( entry === undefined ) { continue; }
|
||||
const content = extractBlocks(entry.content, 100, 101);
|
||||
let pos = 0;
|
||||
for (;;) {
|
||||
pos = content.indexOf(compiledFilter, pos);
|
||||
if ( pos === -1 ) { break; }
|
||||
// We need an exact match.
|
||||
// https://github.com/gorhill/uBlock/issues/1392
|
||||
// https://github.com/gorhill/uBlock/issues/835
|
||||
const notFound = pos !== 0 &&
|
||||
content.charCodeAt(pos - 1) !== 0x0A;
|
||||
pos += compiledFilter.length;
|
||||
if (
|
||||
notFound ||
|
||||
pos !== content.length && content.charCodeAt(pos) !== 0x0A
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
lists.push({
|
||||
assetKey: assetKey,
|
||||
title: entry.title,
|
||||
supportURL: entry.supportURL
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const response = {};
|
||||
response[details.rawFilter] = lists;
|
||||
|
||||
self.postMessage({ id: details.id, response });
|
||||
};
|
||||
|
||||
// Looking up filter lists from a cosmetic filter is a bit more complicated
|
||||
// than with network filters:
|
||||
//
|
||||
// The filter is its raw representation, not its compiled version. This is
|
||||
// because the cosmetic filtering engine can't translate a live cosmetic
|
||||
// filter into its compiled version. Reason is I do not want to burden
|
||||
// cosmetic filtering with the resource overhead of being able to recompile
|
||||
// live cosmetic filters. I want the cosmetic filtering code to be left
|
||||
// completely unaffected by reverse lookup requirements.
|
||||
//
|
||||
// Mainly, given a CSS selector and a hostname as context, we will derive
|
||||
// various versions of compiled filters and see if there are matches. This
|
||||
// way the whole CPU cost is incurred by the reverse lookup code -- in a
|
||||
// worker thread, and the cosmetic filtering engine incurs no cost at all.
|
||||
//
|
||||
// For this though, the reverse lookup code here needs some knowledge of
|
||||
// the inners of the cosmetic filtering engine.
|
||||
// FilterContainer.fromCompiledContent() is our reference code to create
|
||||
// the various compiled versions.
|
||||
|
||||
const fromCosmeticFilter = function(details) {
|
||||
const match = /^#@?#\^?/.exec(details.rawFilter);
|
||||
const prefix = match[0];
|
||||
const exception = prefix.charAt(1) === '@';
|
||||
const selector = details.rawFilter.slice(prefix.length);
|
||||
const isHtmlFilter = prefix.endsWith('^');
|
||||
const hostname = details.hostname;
|
||||
|
||||
// The longer the needle, the lower the number of false positives.
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1139
|
||||
// Mind that there is no guarantee a selector has `\w` characters.
|
||||
const needle = selector.match(/\w+|\*/g).reduce(function(a, b) {
|
||||
return a.length > b.length ? a : b;
|
||||
});
|
||||
|
||||
const regexFromLabels = (prefix, hn, suffix) =>
|
||||
new RegExp(
|
||||
prefix +
|
||||
hn.split('.').reduce((acc, item) => `(${acc}\\.)?${item}`) +
|
||||
suffix
|
||||
);
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/803
|
||||
// Support looking up selectors of the form `*##...`
|
||||
const reHostname = regexFromLabels('^', hostname, '$');
|
||||
let reEntity;
|
||||
{
|
||||
const domain = details.domain;
|
||||
const pos = domain.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
reEntity = regexFromLabels(
|
||||
'^(',
|
||||
hostname.slice(0, pos + hostname.length - domain.length),
|
||||
'\\.)?\\*$'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const hostnameMatches = hn => {
|
||||
return hn === '' ||
|
||||
reHostname.test(hn) ||
|
||||
reEntity !== undefined && reEntity.test(hn);
|
||||
};
|
||||
|
||||
const response = Object.create(null);
|
||||
|
||||
for ( const assetKey in listEntries ) {
|
||||
const entry = listEntries[assetKey];
|
||||
if ( entry === undefined ) { continue; }
|
||||
let content = extractBlocks(entry.content, 200, 1000),
|
||||
isProcedural,
|
||||
found;
|
||||
let pos = 0;
|
||||
while ( (pos = content.indexOf(needle, pos)) !== -1 ) {
|
||||
let beg = content.lastIndexOf('\n', pos);
|
||||
if ( beg === -1 ) { beg = 0; }
|
||||
let end = content.indexOf('\n', pos);
|
||||
if ( end === -1 ) { end = content.length; }
|
||||
pos = end;
|
||||
const fargs = JSON.parse(content.slice(beg, end));
|
||||
const filterType = fargs[0];
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2763
|
||||
if (
|
||||
filterType >= 0 &&
|
||||
filterType <= 5 &&
|
||||
details.ignoreGeneric
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not confuse cosmetic filters with HTML ones.
|
||||
if ( (filterType === 64) !== isHtmlFilter ) { continue; }
|
||||
|
||||
switch ( filterType ) {
|
||||
// Lowly generic cosmetic filters
|
||||
case 0: // simple id-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector.slice(1) ) { break; }
|
||||
if ( selector.charAt(0) !== '#' ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
case 2: // simple class-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector.slice(1) ) { break; }
|
||||
if ( selector.charAt(0) !== '.' ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
case 1: // complex id-based
|
||||
case 3: // complex class-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[2] !== selector ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
// Highly generic cosmetic filters
|
||||
case 4: // simple highly generic
|
||||
case 5: // complex highly generic
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
// Specific cosmetic filtering
|
||||
// Generic exception
|
||||
case 8:
|
||||
// HTML filtering
|
||||
// Response header filtering
|
||||
case 64:
|
||||
if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; }
|
||||
isProcedural = (fargs[2] & 0b010) !== 0;
|
||||
if (
|
||||
isProcedural === false && fargs[3] !== selector ||
|
||||
isProcedural && JSON.parse(fargs[3]).raw !== selector
|
||||
) {
|
||||
break;
|
||||
}
|
||||
if ( hostnameMatches(fargs[1]) === false ) { break; }
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/
|
||||
// Ignore match if specific cosmetic filters are disabled
|
||||
if (
|
||||
filterType === 8 &&
|
||||
exception === false &&
|
||||
details.ignoreSpecific
|
||||
) {
|
||||
break;
|
||||
}
|
||||
found = fargs[1] + prefix + selector;
|
||||
break;
|
||||
// Scriptlet injection
|
||||
case 32:
|
||||
if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; }
|
||||
if ( fargs[3] !== selector ) { break; }
|
||||
if ( hostnameMatches(fargs[1]) ) {
|
||||
found = fargs[1] + prefix + selector;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( found !== undefined ) {
|
||||
if ( response[found] === undefined ) {
|
||||
response[found] = [];
|
||||
}
|
||||
response[found].push({
|
||||
assetKey: assetKey,
|
||||
title: entry.title,
|
||||
supportURL: entry.supportURL
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.postMessage({ id: details.id, response });
|
||||
};
|
||||
|
||||
self.onmessage = function(e) { // jshint ignore:line
|
||||
const msg = e.data;
|
||||
|
||||
switch ( msg.what ) {
|
||||
case 'resetLists':
|
||||
listEntries = Object.create(null);
|
||||
break;
|
||||
|
||||
case 'setList':
|
||||
listEntries[msg.details.assetKey] = msg.details;
|
||||
break;
|
||||
|
||||
case 'fromNetFilter':
|
||||
fromNetFilter(msg);
|
||||
break;
|
||||
|
||||
case 'fromCosmeticFilter':
|
||||
fromCosmeticFilter(msg);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// <<<<< end of local scope
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
|
@ -23,462 +23,192 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
(( ) => {
|
||||
// >>>>> start of local scope
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { CompiledListWriter } from './static-filtering-io.js';
|
||||
import { StaticFilteringParser } from './static-filtering-parser.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
hostnameFromURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Worker context
|
||||
const workerTTL = 5 * 60 * 1000;
|
||||
const pendingResponses = new Map();
|
||||
|
||||
if (
|
||||
self.WorkerGlobalScope instanceof Object &&
|
||||
self instanceof self.WorkerGlobalScope
|
||||
) {
|
||||
const reBlockStart = /^#block-start-(\d+)\n/gm;
|
||||
let listEntries = Object.create(null);
|
||||
let worker = null;
|
||||
let workerTTLTimer;
|
||||
let needLists = true;
|
||||
let messageId = 1;
|
||||
|
||||
const extractBlocks = function(content, begId, endId) {
|
||||
reBlockStart.lastIndex = 0;
|
||||
const out = [];
|
||||
let match = reBlockStart.exec(content);
|
||||
while ( match !== null ) {
|
||||
const beg = match.index + match[0].length;
|
||||
const blockId = parseInt(match[1], 10);
|
||||
if ( blockId >= begId && blockId < endId ) {
|
||||
const end = content.indexOf('#block-end-' + match[1], beg);
|
||||
out.push(content.slice(beg, end));
|
||||
reBlockStart.lastIndex = end;
|
||||
}
|
||||
match = reBlockStart.exec(content);
|
||||
}
|
||||
return out.join('\n');
|
||||
};
|
||||
const onWorkerMessage = function(e) {
|
||||
const msg = e.data;
|
||||
const resolver = pendingResponses.get(msg.id);
|
||||
pendingResponses.delete(msg.id);
|
||||
resolver(msg.response);
|
||||
};
|
||||
|
||||
// https://github.com/MajkiIT/polish-ads-filter/issues/14768#issuecomment-536006312
|
||||
// Avoid reporting badfilter-ed filters.
|
||||
const stopWorker = function() {
|
||||
if ( workerTTLTimer !== undefined ) {
|
||||
clearTimeout(workerTTLTimer);
|
||||
workerTTLTimer = undefined;
|
||||
}
|
||||
if ( worker === null ) { return; }
|
||||
worker.terminate();
|
||||
worker = null;
|
||||
needLists = true;
|
||||
for ( const resolver of pendingResponses.values() ) {
|
||||
resolver();
|
||||
}
|
||||
pendingResponses.clear();
|
||||
};
|
||||
|
||||
const fromNetFilter = function(details) {
|
||||
const lists = [];
|
||||
const compiledFilter = details.compiledFilter;
|
||||
const initWorker = function() {
|
||||
if ( worker === null ) {
|
||||
worker = new Worker('js/reverselookup-worker.js');
|
||||
worker.onmessage = onWorkerMessage;
|
||||
}
|
||||
|
||||
for ( const assetKey in listEntries ) {
|
||||
const entry = listEntries[assetKey];
|
||||
if ( entry === undefined ) { continue; }
|
||||
const content = extractBlocks(entry.content, 100, 101);
|
||||
let pos = 0;
|
||||
for (;;) {
|
||||
pos = content.indexOf(compiledFilter, pos);
|
||||
if ( pos === -1 ) { break; }
|
||||
// We need an exact match.
|
||||
// https://github.com/gorhill/uBlock/issues/1392
|
||||
// https://github.com/gorhill/uBlock/issues/835
|
||||
const notFound = pos !== 0 &&
|
||||
content.charCodeAt(pos - 1) !== 0x0A;
|
||||
pos += compiledFilter.length;
|
||||
if (
|
||||
notFound ||
|
||||
pos !== content.length && content.charCodeAt(pos) !== 0x0A
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
lists.push({
|
||||
assetKey: assetKey,
|
||||
title: entry.title,
|
||||
supportURL: entry.supportURL
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The worker will be shutdown after n minutes without being used.
|
||||
if ( workerTTLTimer !== undefined ) {
|
||||
clearTimeout(workerTTLTimer);
|
||||
}
|
||||
workerTTLTimer = vAPI.setTimeout(stopWorker, workerTTL);
|
||||
|
||||
const response = {};
|
||||
response[details.rawFilter] = lists;
|
||||
if ( needLists === false ) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
needLists = false;
|
||||
|
||||
self.postMessage({ id: details.id, response });
|
||||
};
|
||||
const entries = new Map();
|
||||
|
||||
// Looking up filter lists from a cosmetic filter is a bit more complicated
|
||||
// than with network filters:
|
||||
//
|
||||
// The filter is its raw representation, not its compiled version. This is
|
||||
// because the cosmetic filtering engine can't translate a live cosmetic
|
||||
// filter into its compiled version. Reason is I do not want to burden
|
||||
// cosmetic filtering with the resource overhead of being able to recompile
|
||||
// live cosmetic filters. I want the cosmetic filtering code to be left
|
||||
// completely unaffected by reverse lookup requirements.
|
||||
//
|
||||
// Mainly, given a CSS selector and a hostname as context, we will derive
|
||||
// various versions of compiled filters and see if there are matches. This
|
||||
// way the whole CPU cost is incurred by the reverse lookup code -- in a
|
||||
// worker thread, and the cosmetic filtering engine incurs no cost at all.
|
||||
//
|
||||
// For this though, the reverse lookup code here needs some knowledge of
|
||||
// the inners of the cosmetic filtering engine.
|
||||
// FilterContainer.fromCompiledContent() is our reference code to create
|
||||
// the various compiled versions.
|
||||
const onListLoaded = function(details) {
|
||||
const entry = entries.get(details.assetKey);
|
||||
|
||||
const fromCosmeticFilter = function(details) {
|
||||
const match = /^#@?#\^?/.exec(details.rawFilter);
|
||||
const prefix = match[0];
|
||||
const exception = prefix.charAt(1) === '@';
|
||||
const selector = details.rawFilter.slice(prefix.length);
|
||||
const isHtmlFilter = prefix.endsWith('^');
|
||||
const hostname = details.hostname;
|
||||
|
||||
// The longer the needle, the lower the number of false positives.
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1139
|
||||
// Mind that there is no guarantee a selector has `\w` characters.
|
||||
const needle = selector.match(/\w+|\*/g).reduce(function(a, b) {
|
||||
return a.length > b.length ? a : b;
|
||||
});
|
||||
|
||||
const regexFromLabels = (prefix, hn, suffix) =>
|
||||
new RegExp(
|
||||
prefix +
|
||||
hn.split('.').reduce((acc, item) => `(${acc}\\.)?${item}`) +
|
||||
suffix
|
||||
);
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/803
|
||||
// Support looking up selectors of the form `*##...`
|
||||
const reHostname = regexFromLabels('^', hostname, '$');
|
||||
let reEntity;
|
||||
{
|
||||
const domain = details.domain;
|
||||
const pos = domain.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
reEntity = regexFromLabels(
|
||||
'^(',
|
||||
hostname.slice(0, pos + hostname.length - domain.length),
|
||||
'\\.)?\\*$'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const hostnameMatches = hn => {
|
||||
return hn === '' ||
|
||||
reHostname.test(hn) ||
|
||||
reEntity !== undefined && reEntity.test(hn);
|
||||
};
|
||||
|
||||
const response = Object.create(null);
|
||||
|
||||
for ( const assetKey in listEntries ) {
|
||||
const entry = listEntries[assetKey];
|
||||
if ( entry === undefined ) { continue; }
|
||||
let content = extractBlocks(entry.content, 200, 1000),
|
||||
isProcedural,
|
||||
found;
|
||||
let pos = 0;
|
||||
while ( (pos = content.indexOf(needle, pos)) !== -1 ) {
|
||||
let beg = content.lastIndexOf('\n', pos);
|
||||
if ( beg === -1 ) { beg = 0; }
|
||||
let end = content.indexOf('\n', pos);
|
||||
if ( end === -1 ) { end = content.length; }
|
||||
pos = end;
|
||||
const fargs = JSON.parse(content.slice(beg, end));
|
||||
const filterType = fargs[0];
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2763
|
||||
if (
|
||||
filterType >= 0 &&
|
||||
filterType <= 5 &&
|
||||
details.ignoreGeneric
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not confuse cosmetic filters with HTML ones.
|
||||
if ( (filterType === 64) !== isHtmlFilter ) { continue; }
|
||||
|
||||
switch ( filterType ) {
|
||||
// Lowly generic cosmetic filters
|
||||
case 0: // simple id-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector.slice(1) ) { break; }
|
||||
if ( selector.charAt(0) !== '#' ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
case 2: // simple class-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector.slice(1) ) { break; }
|
||||
if ( selector.charAt(0) !== '.' ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
case 1: // complex id-based
|
||||
case 3: // complex class-based
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[2] !== selector ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
// Highly generic cosmetic filters
|
||||
case 4: // simple highly generic
|
||||
case 5: // complex highly generic
|
||||
if ( exception ) { break; }
|
||||
if ( fargs[1] !== selector ) { break; }
|
||||
found = prefix + selector;
|
||||
break;
|
||||
// Specific cosmetic filtering
|
||||
// Generic exception
|
||||
case 8:
|
||||
// HTML filtering
|
||||
// Response header filtering
|
||||
case 64:
|
||||
if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; }
|
||||
isProcedural = (fargs[2] & 0b010) !== 0;
|
||||
if (
|
||||
isProcedural === false && fargs[3] !== selector ||
|
||||
isProcedural && JSON.parse(fargs[3]).raw !== selector
|
||||
) {
|
||||
break;
|
||||
}
|
||||
if ( hostnameMatches(fargs[1]) === false ) { break; }
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/d6vxzj/
|
||||
// Ignore match if specific cosmetic filters are disabled
|
||||
if (
|
||||
filterType === 8 &&
|
||||
exception === false &&
|
||||
details.ignoreSpecific
|
||||
) {
|
||||
break;
|
||||
}
|
||||
found = fargs[1] + prefix + selector;
|
||||
break;
|
||||
// Scriptlet injection
|
||||
case 32:
|
||||
if ( exception !== ((fargs[2] & 0b001) !== 0) ) { break; }
|
||||
if ( fargs[3] !== selector ) { break; }
|
||||
if ( hostnameMatches(fargs[1]) ) {
|
||||
found = fargs[1] + prefix + selector;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( found !== undefined ) {
|
||||
if ( response[found] === undefined ) {
|
||||
response[found] = [];
|
||||
}
|
||||
response[found].push({
|
||||
assetKey: assetKey,
|
||||
title: entry.title,
|
||||
supportURL: entry.supportURL
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.postMessage({ id: details.id, response });
|
||||
};
|
||||
|
||||
self.onmessage = function(e) { // jshint ignore:line
|
||||
const msg = e.data;
|
||||
|
||||
switch ( msg.what ) {
|
||||
case 'resetLists':
|
||||
listEntries = Object.create(null);
|
||||
break;
|
||||
|
||||
case 'setList':
|
||||
listEntries[msg.details.assetKey] = msg.details;
|
||||
break;
|
||||
|
||||
case 'fromNetFilter':
|
||||
fromNetFilter(msg);
|
||||
break;
|
||||
|
||||
case 'fromCosmeticFilter':
|
||||
fromCosmeticFilter(msg);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Main context
|
||||
|
||||
{
|
||||
if ( typeof µBlock !== 'object' ) { return; }
|
||||
|
||||
const workerTTL = 5 * 60 * 1000;
|
||||
const pendingResponses = new Map();
|
||||
|
||||
let worker = null;
|
||||
let workerTTLTimer;
|
||||
let needLists = true;
|
||||
let messageId = 1;
|
||||
|
||||
const onWorkerMessage = function(e) {
|
||||
const msg = e.data;
|
||||
const resolver = pendingResponses.get(msg.id);
|
||||
pendingResponses.delete(msg.id);
|
||||
resolver(msg.response);
|
||||
};
|
||||
|
||||
const stopWorker = function() {
|
||||
if ( workerTTLTimer !== undefined ) {
|
||||
clearTimeout(workerTTLTimer);
|
||||
workerTTLTimer = undefined;
|
||||
}
|
||||
if ( worker === null ) { return; }
|
||||
worker.terminate();
|
||||
worker = null;
|
||||
needLists = true;
|
||||
for ( const resolver of pendingResponses.values() ) {
|
||||
resolver();
|
||||
}
|
||||
pendingResponses.clear();
|
||||
};
|
||||
|
||||
const initWorker = function() {
|
||||
if ( worker === null ) {
|
||||
worker = new Worker('js/reverselookup.js');
|
||||
worker.onmessage = onWorkerMessage;
|
||||
}
|
||||
|
||||
// The worker will be shutdown after n minutes without being used.
|
||||
if ( workerTTLTimer !== undefined ) {
|
||||
clearTimeout(workerTTLTimer);
|
||||
}
|
||||
workerTTLTimer = vAPI.setTimeout(stopWorker, workerTTL);
|
||||
|
||||
if ( needLists === false ) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
needLists = false;
|
||||
|
||||
const entries = new Map();
|
||||
|
||||
const onListLoaded = function(details) {
|
||||
const entry = entries.get(details.assetKey);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/536
|
||||
// Use assetKey when there is no filter list title.
|
||||
|
||||
worker.postMessage({
|
||||
what: 'setList',
|
||||
details: {
|
||||
assetKey: details.assetKey,
|
||||
title: entry.title || details.assetKey,
|
||||
supportURL: entry.supportURL,
|
||||
content: details.content
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const µb = µBlock;
|
||||
for ( const listKey in µb.availableFilterLists ) {
|
||||
if ( µb.availableFilterLists.hasOwnProperty(listKey) === false ) {
|
||||
continue;
|
||||
}
|
||||
const entry = µb.availableFilterLists[listKey];
|
||||
if ( entry.off === true ) { continue; }
|
||||
entries.set(listKey, {
|
||||
title: listKey !== µb.userFiltersPath ?
|
||||
entry.title :
|
||||
vAPI.i18n('1pPageName'),
|
||||
supportURL: entry.supportURL || ''
|
||||
});
|
||||
}
|
||||
if ( entries.size === 0 ) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
for ( const listKey of entries.keys() ) {
|
||||
promises.push(
|
||||
µb.getCompiledFilterList(listKey).then(details => {
|
||||
onListLoaded(details);
|
||||
})
|
||||
);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
const fromNetFilter = async function(rawFilter) {
|
||||
if ( typeof rawFilter !== 'string' || rawFilter === '' ) { return; }
|
||||
|
||||
const µb = µBlock;
|
||||
const writer = new µb.CompiledListWriter();
|
||||
const parser = new µb.StaticFilteringParser();
|
||||
parser.setMaxTokenLength(µb.staticNetFilteringEngine.MAX_TOKEN_LENGTH);
|
||||
parser.analyze(rawFilter);
|
||||
|
||||
if ( µb.staticNetFilteringEngine.compile(parser, writer) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
await initWorker();
|
||||
|
||||
const id = messageId++;
|
||||
worker.postMessage({
|
||||
what: 'fromNetFilter',
|
||||
id: id,
|
||||
compiledFilter: writer.last(),
|
||||
rawFilter: rawFilter
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
pendingResponses.set(id, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
const fromCosmeticFilter = async function(details) {
|
||||
if (
|
||||
typeof details.rawFilter !== 'string' ||
|
||||
details.rawFilter === ''
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await initWorker();
|
||||
|
||||
const id = messageId++;
|
||||
const hostname = µBlock.hostnameFromURI(details.url);
|
||||
// https://github.com/gorhill/uBlock/issues/536
|
||||
// Use assetKey when there is no filter list title.
|
||||
|
||||
worker.postMessage({
|
||||
what: 'fromCosmeticFilter',
|
||||
id: id,
|
||||
domain: µBlock.domainFromHostname(hostname),
|
||||
hostname: hostname,
|
||||
ignoreGeneric:
|
||||
µBlock.staticNetFilteringEngine.matchRequestReverse(
|
||||
'generichide',
|
||||
details.url
|
||||
) === 2,
|
||||
ignoreSpecific:
|
||||
µBlock.staticNetFilteringEngine.matchRequestReverse(
|
||||
'specifichide',
|
||||
details.url
|
||||
) === 2,
|
||||
rawFilter: details.rawFilter
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
pendingResponses.set(id, resolve);
|
||||
what: 'setList',
|
||||
details: {
|
||||
assetKey: details.assetKey,
|
||||
title: entry.title || details.assetKey,
|
||||
supportURL: entry.supportURL,
|
||||
content: details.content
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// This tells the worker that filter lists may have changed.
|
||||
for ( const listKey in µb.availableFilterLists ) {
|
||||
if ( µb.availableFilterLists.hasOwnProperty(listKey) === false ) {
|
||||
continue;
|
||||
}
|
||||
const entry = µb.availableFilterLists[listKey];
|
||||
if ( entry.off === true ) { continue; }
|
||||
entries.set(listKey, {
|
||||
title: listKey !== µb.userFiltersPath ?
|
||||
entry.title :
|
||||
vAPI.i18n('1pPageName'),
|
||||
supportURL: entry.supportURL || ''
|
||||
});
|
||||
}
|
||||
if ( entries.size === 0 ) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const resetLists = function() {
|
||||
needLists = true;
|
||||
if ( worker === null ) { return; }
|
||||
worker.postMessage({ what: 'resetLists' });
|
||||
};
|
||||
const promises = [];
|
||||
for ( const listKey of entries.keys() ) {
|
||||
promises.push(
|
||||
µb.getCompiledFilterList(listKey).then(details => {
|
||||
onListLoaded(details);
|
||||
})
|
||||
);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
µBlock.staticFilteringReverseLookup = {
|
||||
fromNetFilter,
|
||||
fromCosmeticFilter,
|
||||
resetLists,
|
||||
shutdown: stopWorker
|
||||
};
|
||||
}
|
||||
const fromNetFilter = async function(rawFilter) {
|
||||
if ( typeof rawFilter !== 'string' || rawFilter === '' ) { return; }
|
||||
|
||||
const writer = new CompiledListWriter();
|
||||
const parser = new StaticFilteringParser();
|
||||
parser.setMaxTokenLength(staticNetFilteringEngine.MAX_TOKEN_LENGTH);
|
||||
parser.analyze(rawFilter);
|
||||
|
||||
if ( staticNetFilteringEngine.compile(parser, writer) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
await initWorker();
|
||||
|
||||
const id = messageId++;
|
||||
worker.postMessage({
|
||||
what: 'fromNetFilter',
|
||||
id: id,
|
||||
compiledFilter: writer.last(),
|
||||
rawFilter: rawFilter
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
pendingResponses.set(id, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
const fromCosmeticFilter = async function(details) {
|
||||
if (
|
||||
typeof details.rawFilter !== 'string' ||
|
||||
details.rawFilter === ''
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
await initWorker();
|
||||
|
||||
const id = messageId++;
|
||||
const hostname = hostnameFromURI(details.url);
|
||||
|
||||
worker.postMessage({
|
||||
what: 'fromCosmeticFilter',
|
||||
id: id,
|
||||
domain: domainFromHostname(hostname),
|
||||
hostname: hostname,
|
||||
ignoreGeneric:
|
||||
staticNetFilteringEngine.matchRequestReverse(
|
||||
'generichide',
|
||||
details.url
|
||||
) === 2,
|
||||
ignoreSpecific:
|
||||
staticNetFilteringEngine.matchRequestReverse(
|
||||
'specifichide',
|
||||
details.url
|
||||
) === 2,
|
||||
rawFilter: details.rawFilter
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
pendingResponses.set(id, resolve);
|
||||
});
|
||||
};
|
||||
|
||||
// This tells the worker that filter lists may have changed.
|
||||
|
||||
const resetLists = function() {
|
||||
needLists = true;
|
||||
if ( worker === null ) { return; }
|
||||
worker.postMessage({ what: 'resetLists' });
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// <<<<< end of local scope
|
||||
})();
|
||||
const staticFilteringReverseLookup = {
|
||||
fromNetFilter,
|
||||
fromCosmeticFilter,
|
||||
resetLists,
|
||||
shutdown: stopWorker
|
||||
};
|
||||
|
||||
export default staticFilteringReverseLookup;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,28 +23,35 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import logger from './logger.js';
|
||||
import µb from './background.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
StaticExtFilteringHostnameDB,
|
||||
StaticExtFilteringSessionDB,
|
||||
} from './static-ext-filtering-db.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
entityFromDomain,
|
||||
hostnameFromURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const µb = µBlock;
|
||||
const duplicates = new Set();
|
||||
const scriptletCache = new µb.MRUCache(32);
|
||||
const reEscapeScriptArg = /[\\'"]/g;
|
||||
|
||||
const scriptletDB = new µb.staticExtFilteringEngine.HostnameBasedDB(1);
|
||||
const sessionScriptletDB = new µb.staticExtFilteringEngine.SessionDB();
|
||||
const scriptletDB = new StaticExtFilteringHostnameDB(1);
|
||||
const sessionScriptletDB = new StaticExtFilteringSessionDB();
|
||||
|
||||
let acceptedCount = 0;
|
||||
let discardedCount = 0;
|
||||
|
||||
const api = {
|
||||
const scriptletFilteringEngine = {
|
||||
get acceptedCount() {
|
||||
return acceptedCount;
|
||||
},
|
||||
|
@ -132,7 +139,7 @@ const normalizeRawFilter = function(rawFilter) {
|
|||
if ( end === -1 ) { end = rawEnd; }
|
||||
const token = rawToken.slice(0, end).trim();
|
||||
const alias = token.endsWith('.js') ? token.slice(0, -3) : token;
|
||||
let normalized = µb.redirectEngine.aliases.get(`${alias}.js`);
|
||||
let normalized = redirectEngine.aliases.get(`${alias}.js`);
|
||||
normalized = normalized === undefined
|
||||
? alias
|
||||
: normalized.slice(0, -3);
|
||||
|
@ -212,7 +219,7 @@ const patchScriptlet = function(content, args) {
|
|||
};
|
||||
|
||||
const logOne = function(isException, token, details) {
|
||||
µBlock.filteringContext
|
||||
µb.filteringContext
|
||||
.duplicate()
|
||||
.fromTabId(details.tabId)
|
||||
.setRealm('extended')
|
||||
|
@ -226,19 +233,19 @@ const logOne = function(isException, token, details) {
|
|||
.toLogger();
|
||||
};
|
||||
|
||||
api.reset = function() {
|
||||
scriptletFilteringEngine.reset = function() {
|
||||
scriptletDB.clear();
|
||||
duplicates.clear();
|
||||
acceptedCount = 0;
|
||||
discardedCount = 0;
|
||||
};
|
||||
|
||||
api.freeze = function() {
|
||||
scriptletFilteringEngine.freeze = function() {
|
||||
duplicates.clear();
|
||||
scriptletDB.collectGarbage();
|
||||
};
|
||||
|
||||
api.compile = function(parser, writer) {
|
||||
scriptletFilteringEngine.compile = function(parser, writer) {
|
||||
writer.select(µb.compiledScriptletSection);
|
||||
|
||||
// Only exception filters are allowed to be global.
|
||||
|
@ -272,7 +279,7 @@ api.compile = function(parser, writer) {
|
|||
}
|
||||
};
|
||||
|
||||
api.compileTemporary = function(parser) {
|
||||
scriptletFilteringEngine.compileTemporary = function(parser) {
|
||||
return {
|
||||
session: sessionScriptletDB,
|
||||
selector: parser.result.compiled,
|
||||
|
@ -284,7 +291,7 @@ api.compileTemporary = function(parser) {
|
|||
// ^ ^
|
||||
// 4 -1
|
||||
|
||||
api.fromCompiledContent = function(reader) {
|
||||
scriptletFilteringEngine.fromCompiledContent = function(reader) {
|
||||
reader.select(µb.compiledScriptletSection);
|
||||
|
||||
while ( reader.next() ) {
|
||||
|
@ -301,7 +308,7 @@ api.fromCompiledContent = function(reader) {
|
|||
}
|
||||
};
|
||||
|
||||
api.getSession = function() {
|
||||
scriptletFilteringEngine.getSession = function() {
|
||||
return sessionScriptletDB;
|
||||
};
|
||||
|
||||
|
@ -309,12 +316,9 @@ const $scriptlets = new Set();
|
|||
const $exceptions = new Set();
|
||||
const $scriptletToCodeMap = new Map();
|
||||
|
||||
api.retrieve = function(request) {
|
||||
scriptletFilteringEngine.retrieve = function(request) {
|
||||
if ( scriptletDB.size === 0 ) { return; }
|
||||
|
||||
const reng = µb.redirectEngine;
|
||||
if ( !reng ) { return; }
|
||||
|
||||
const hostname = request.hostname;
|
||||
|
||||
$scriptlets.clear();
|
||||
|
@ -334,16 +338,14 @@ api.retrieve = function(request) {
|
|||
// Do not inject scriptlets if the site is under an `allow` rule.
|
||||
if (
|
||||
µb.userSettings.advancedUserEnabled &&
|
||||
µb.sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
|
||||
// Wholly disable scriptlet injection?
|
||||
if ( $exceptions.has('') ) {
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logOne(true, '', request);
|
||||
}
|
||||
return;
|
||||
|
@ -351,7 +353,7 @@ api.retrieve = function(request) {
|
|||
|
||||
$scriptletToCodeMap.clear();
|
||||
for ( const rawToken of $scriptlets ) {
|
||||
lookupScriptlet(rawToken, reng, $scriptletToCodeMap);
|
||||
lookupScriptlet(rawToken, redirectEngine, $scriptletToCodeMap);
|
||||
}
|
||||
if ( $scriptletToCodeMap.size === 0 ) { return; }
|
||||
|
||||
|
@ -362,7 +364,7 @@ api.retrieve = function(request) {
|
|||
if ( isException === false ) {
|
||||
out.push(code);
|
||||
}
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logOne(isException, rawToken, request);
|
||||
}
|
||||
}
|
||||
|
@ -390,11 +392,11 @@ api.retrieve = function(request) {
|
|||
return out.join('\n');
|
||||
};
|
||||
|
||||
api.hasScriptlet = function(hostname, exceptionBit, scriptlet) {
|
||||
scriptletFilteringEngine.hasScriptlet = function(hostname, exceptionBit, scriptlet) {
|
||||
return scriptletDB.hasStr(hostname, exceptionBit, scriptlet);
|
||||
};
|
||||
|
||||
api.injectNow = function(details) {
|
||||
scriptletFilteringEngine.injectNow = function(details) {
|
||||
if ( typeof details.frameId !== 'number' ) { return; }
|
||||
const request = {
|
||||
tabId: details.tabId,
|
||||
|
@ -406,7 +408,7 @@ api.injectNow = function(details) {
|
|||
};
|
||||
request.domain = domainFromHostname(request.hostname);
|
||||
request.entity = entityFromDomain(request.domain);
|
||||
const scriptlets = µb.scriptletFilteringEngine.retrieve(request);
|
||||
const scriptlets = this.retrieve(request);
|
||||
if ( scriptlets === undefined ) { return; }
|
||||
let code = contentscriptCode.assemble(request.hostname, scriptlets);
|
||||
if ( µb.hiddenSettings.debugScriptletInjector ) {
|
||||
|
@ -420,21 +422,21 @@ api.injectNow = function(details) {
|
|||
});
|
||||
};
|
||||
|
||||
api.toSelfie = function() {
|
||||
scriptletFilteringEngine.toSelfie = function() {
|
||||
return scriptletDB.toSelfie();
|
||||
};
|
||||
|
||||
api.fromSelfie = function(selfie) {
|
||||
scriptletFilteringEngine.fromSelfie = function(selfie) {
|
||||
scriptletDB.fromSelfie(selfie);
|
||||
};
|
||||
|
||||
api.benchmark = async function() {
|
||||
scriptletFilteringEngine.benchmark = async function() {
|
||||
const requests = await µb.loadBenchmarkDataset();
|
||||
if ( Array.isArray(requests) === false || requests.length === 0 ) {
|
||||
log.print('No requests found to benchmark');
|
||||
console.info('No requests found to benchmark');
|
||||
return;
|
||||
}
|
||||
log.print('Benchmarking scriptletFilteringEngine.retrieve()...');
|
||||
console.info('Benchmarking scriptletFilteringEngine.retrieve()...');
|
||||
const details = {
|
||||
domain: '',
|
||||
entity: '',
|
||||
|
@ -456,14 +458,12 @@ api.benchmark = async function() {
|
|||
}
|
||||
const t1 = self.performance.now();
|
||||
const dur = t1 - t0;
|
||||
log.print(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
|
||||
log.print(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
|
||||
console.info(`Evaluated ${count} requests in ${dur.toFixed(0)} ms`);
|
||||
console.info(`\tAverage: ${(dur / count).toFixed(3)} ms per request`);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.scriptletFilteringEngine = api;
|
||||
export default scriptletFilteringEngine;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
111
src/js/start.js
111
src/js/start.js
|
@ -23,7 +23,32 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import cacheStorage from './cachestorage.js';
|
||||
import contextMenu from './contextmenu.js';
|
||||
import io from './assets.js';
|
||||
import lz4Codec from './lz4.js';
|
||||
import staticExtFilteringEngine from './static-ext-filtering.js';
|
||||
import staticFilteringReverseLookup from './reverselookup.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
import { ubolog } from './console.js';
|
||||
import { webRequest } from './traffic.js';
|
||||
|
||||
import {
|
||||
permanentFirewall,
|
||||
sessionFirewall,
|
||||
} from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
permanentSwitches,
|
||||
sessionSwitches,
|
||||
} from './hnswitches.js';
|
||||
|
||||
import {
|
||||
permanentURLFiltering,
|
||||
sessionURLFiltering,
|
||||
} from './url-net-filtering.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -32,21 +57,19 @@ import µBlock from './background.js';
|
|||
(async ( ) => {
|
||||
// >>>>> start of private scope
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.app.onShutdown = function() {
|
||||
µb.staticFilteringReverseLookup.shutdown();
|
||||
µb.assets.updateStop();
|
||||
µb.staticNetFilteringEngine.reset();
|
||||
µb.staticExtFilteringEngine.reset();
|
||||
µb.sessionFirewall.reset();
|
||||
µb.permanentFirewall.reset();
|
||||
µb.sessionURLFiltering.reset();
|
||||
µb.permanentURLFiltering.reset();
|
||||
µb.sessionSwitches.reset();
|
||||
µb.permanentSwitches.reset();
|
||||
staticFilteringReverseLookup.shutdown();
|
||||
io.updateStop();
|
||||
staticNetFilteringEngine.reset();
|
||||
staticExtFilteringEngine.reset();
|
||||
sessionFirewall.reset();
|
||||
permanentFirewall.reset();
|
||||
sessionURLFiltering.reset();
|
||||
permanentURLFiltering.reset();
|
||||
sessionSwitches.reset();
|
||||
permanentSwitches.reset();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -116,7 +139,7 @@ const onVersionReady = function(lastVersion) {
|
|||
|
||||
// Since built-in resources may have changed since last version, we
|
||||
// force a reload of all resources.
|
||||
µb.redirectEngine.invalidateResourcesSelfie();
|
||||
redirectEngine.invalidateResourcesSelfie();
|
||||
|
||||
// https://github.com/LiCybora/NanoDefenderFirefox/issues/196
|
||||
// Toggle on the blocking of CSP reports by default for Firefox.
|
||||
|
@ -124,8 +147,8 @@ const onVersionReady = function(lastVersion) {
|
|||
lastVersionInt <= 1031003011 &&
|
||||
vAPI.webextFlavor.soup.has('firefox')
|
||||
) {
|
||||
µb.sessionSwitches.toggle('no-csp-reports', '*', 1);
|
||||
µb.permanentSwitches.toggle('no-csp-reports', '*', 1);
|
||||
sessionSwitches.toggle('no-csp-reports', '*', 1);
|
||||
permanentSwitches.toggle('no-csp-reports', '*', 1);
|
||||
µb.saveHostnameSwitches();
|
||||
}
|
||||
};
|
||||
|
@ -225,7 +248,7 @@ const onCacheSettingsReady = async function(fetched) {
|
|||
}
|
||||
if ( µb.selfieIsInvalid ) {
|
||||
µb.selfieManager.destroy();
|
||||
µb.cacheStorage.set(µb.systemSettings);
|
||||
cacheStorage.set(µb.systemSettings);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -243,12 +266,12 @@ const onFirstFetchReady = function(fetched, adminExtra) {
|
|||
fromFetch(µb.localSettings, fetched);
|
||||
fromFetch(µb.restoreBackupSettings, fetched);
|
||||
|
||||
µb.permanentFirewall.fromString(fetched.dynamicFilteringString);
|
||||
µb.sessionFirewall.assign(µb.permanentFirewall);
|
||||
µb.permanentURLFiltering.fromString(fetched.urlFilteringString);
|
||||
µb.sessionURLFiltering.assign(µb.permanentURLFiltering);
|
||||
µb.permanentSwitches.fromString(fetched.hostnameSwitchesString);
|
||||
µb.sessionSwitches.assign(µb.permanentSwitches);
|
||||
permanentFirewall.fromString(fetched.dynamicFilteringString);
|
||||
sessionFirewall.assign(permanentFirewall);
|
||||
permanentURLFiltering.fromString(fetched.urlFilteringString);
|
||||
sessionURLFiltering.assign(permanentURLFiltering);
|
||||
permanentSwitches.fromString(fetched.hostnameSwitchesString);
|
||||
sessionSwitches.assign(permanentSwitches);
|
||||
|
||||
onNetWhitelistReady(fetched.netWhitelist, adminExtra);
|
||||
onVersionReady(fetched.version);
|
||||
|
@ -307,10 +330,10 @@ const createDefaultProps = function() {
|
|||
try {
|
||||
// https://github.com/gorhill/uBlock/issues/531
|
||||
await µb.restoreAdminSettings();
|
||||
log.info(`Admin settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Admin settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
await µb.loadHiddenSettings();
|
||||
log.info(`Hidden settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Hidden settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
// Maybe override current network listener suspend state
|
||||
if ( µb.hiddenSettings.suspendTabsUntilReady === 'no' ) {
|
||||
|
@ -320,42 +343,42 @@ try {
|
|||
}
|
||||
|
||||
if ( µb.hiddenSettings.disableWebAssembly !== true ) {
|
||||
µb.staticNetFilteringEngine.enableWASM('/js').then(( ) => {
|
||||
log.info(`WASM modules ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
staticNetFilteringEngine.enableWASM('/js').then(( ) => {
|
||||
ubolog(`WASM modules ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
});
|
||||
}
|
||||
|
||||
const cacheBackend = await µb.cacheStorage.select(
|
||||
const cacheBackend = await cacheStorage.select(
|
||||
µb.hiddenSettings.cacheStorageAPI
|
||||
);
|
||||
log.info(`Backend storage for cache will be ${cacheBackend}`);
|
||||
ubolog(`Backend storage for cache will be ${cacheBackend}`);
|
||||
|
||||
const adminExtra = await vAPI.adminStorage.get('toAdd');
|
||||
log.info(`Extra admin settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Extra admin settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1365
|
||||
// Wait for onCacheSettingsReady() to be fully ready.
|
||||
const [ , , lastVersion ] = await Promise.all([
|
||||
µb.loadSelectedFilterLists().then(( ) => {
|
||||
log.info(`List selection ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`List selection ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
}),
|
||||
µb.cacheStorage.get(
|
||||
cacheStorage.get(
|
||||
{ compiledMagic: 0, selfieMagic: 0 }
|
||||
).then(fetched => {
|
||||
log.info(`Cache magic numbers ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Cache magic numbers ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
onCacheSettingsReady(fetched);
|
||||
}),
|
||||
vAPI.storage.get(createDefaultProps()).then(fetched => {
|
||||
log.info(`First fetch ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`First fetch ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
onFirstFetchReady(fetched, adminExtra);
|
||||
return fetched.version;
|
||||
}),
|
||||
µb.loadUserSettings().then(fetched => {
|
||||
log.info(`User settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`User settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
onUserSettingsReady(fetched);
|
||||
}),
|
||||
µb.loadPublicSuffixList().then(( ) => {
|
||||
log.info(`PSL ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`PSL ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -369,7 +392,7 @@ try {
|
|||
}
|
||||
|
||||
// Prime the filtering engines before first use.
|
||||
µb.staticNetFilteringEngine.prime();
|
||||
staticNetFilteringEngine.prime();
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/817#issuecomment-565730122
|
||||
// Still try to load filter lists regardless of whether a serious error
|
||||
|
@ -378,7 +401,7 @@ let selfieIsValid = false;
|
|||
try {
|
||||
selfieIsValid = await µb.selfieManager.load();
|
||||
if ( selfieIsValid === true ) {
|
||||
log.info(`Selfie ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Selfie ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
}
|
||||
} catch (ex) {
|
||||
console.trace(ex);
|
||||
|
@ -386,7 +409,7 @@ try {
|
|||
if ( selfieIsValid !== true ) {
|
||||
try {
|
||||
await µb.loadFilterLists();
|
||||
log.info(`Filter lists ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`Filter lists ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
} catch (ex) {
|
||||
console.trace(ex);
|
||||
}
|
||||
|
@ -399,21 +422,21 @@ if ( selfieIsValid !== true ) {
|
|||
µb.readyToFilter = true;
|
||||
|
||||
// Start network observers.
|
||||
µb.webRequest.start();
|
||||
webRequest.start();
|
||||
|
||||
// Ensure that the resources allocated for decompression purpose (likely
|
||||
// large buffers) are garbage-collectable immediately after launch.
|
||||
// Otherwise I have observed that it may take quite a while before the
|
||||
// garbage collection of these resources kicks in. Relinquishing as soon
|
||||
// as possible ensure minimal memory usage baseline.
|
||||
µb.lz4Codec.relinquish();
|
||||
lz4Codec.relinquish();
|
||||
|
||||
// Initialize internal state with maybe already existing tabs.
|
||||
initializeTabs();
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/184
|
||||
// Check for updates not too far in the future.
|
||||
µb.assets.addObserver(µb.assetObserver.bind(µb));
|
||||
io.addObserver(µb.assetObserver.bind(µb));
|
||||
µb.scheduleAssetUpdater(
|
||||
µb.userSettings.autoUpdate
|
||||
? µb.hiddenSettings.autoUpdateDelayAfterLaunch * 1000
|
||||
|
@ -422,7 +445,7 @@ initializeTabs();
|
|||
|
||||
// Force an update of the context menu according to the currently
|
||||
// active tab.
|
||||
µb.contextMenu.update();
|
||||
contextMenu.update();
|
||||
|
||||
// Maybe install non-default popup document, or automatically select
|
||||
// default UI according to platform.
|
||||
|
@ -455,7 +478,7 @@ browser.runtime.onUpdateAvailable.addListener(details => {
|
|||
}
|
||||
});
|
||||
|
||||
log.info(`All ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
ubolog(`All ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
// <<<<< end of private scope
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2017-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';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const StaticExtFilteringHostnameDB = class {
|
||||
constructor(nBits, selfie = undefined) {
|
||||
this.nBits = nBits;
|
||||
this.timer = undefined;
|
||||
this.strToIdMap = new Map();
|
||||
this.hostnameToSlotIdMap = new Map();
|
||||
// Array of integer pairs
|
||||
this.hostnameSlots = [];
|
||||
// Array of strings (selectors and pseudo-selectors)
|
||||
this.strSlots = [];
|
||||
this.size = 0;
|
||||
if ( selfie !== undefined ) {
|
||||
this.fromSelfie(selfie);
|
||||
}
|
||||
}
|
||||
|
||||
store(hn, bits, s) {
|
||||
this.size += 1;
|
||||
let iStr = this.strToIdMap.get(s);
|
||||
if ( iStr === undefined ) {
|
||||
iStr = this.strSlots.length;
|
||||
this.strSlots.push(s);
|
||||
this.strToIdMap.set(s, iStr);
|
||||
if ( this.timer === undefined ) {
|
||||
this.collectGarbage(true);
|
||||
}
|
||||
}
|
||||
const strId = iStr << this.nBits | bits;
|
||||
let iHn = this.hostnameToSlotIdMap.get(hn);
|
||||
if ( iHn === undefined ) {
|
||||
this.hostnameToSlotIdMap.set(hn, this.hostnameSlots.length);
|
||||
this.hostnameSlots.push(strId, 0);
|
||||
return;
|
||||
}
|
||||
// Add as last item.
|
||||
while ( this.hostnameSlots[iHn+1] !== 0 ) {
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
}
|
||||
this.hostnameSlots[iHn+1] = this.hostnameSlots.length;
|
||||
this.hostnameSlots.push(strId, 0);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.hostnameToSlotIdMap.clear();
|
||||
this.hostnameSlots.length = 0;
|
||||
this.strSlots.length = 0;
|
||||
this.strToIdMap.clear();
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
collectGarbage(later = false) {
|
||||
if ( later === false ) {
|
||||
if ( this.timer !== undefined ) {
|
||||
self.cancelIdleCallback(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
this.strToIdMap.clear();
|
||||
return;
|
||||
}
|
||||
if ( this.timer !== undefined ) { return; }
|
||||
this.timer = self.requestIdleCallback(
|
||||
( ) => {
|
||||
this.timer = undefined;
|
||||
this.strToIdMap.clear();
|
||||
},
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
}
|
||||
|
||||
// modifiers = 1: return only specific items
|
||||
// modifiers = 2: return only generic items
|
||||
//
|
||||
retrieve(hostname, out, modifiers = 0) {
|
||||
if ( modifiers === 2 ) {
|
||||
hostname = '';
|
||||
}
|
||||
const mask = out.length - 1; // out.length must be power of two
|
||||
for (;;) {
|
||||
let iHn = this.hostnameToSlotIdMap.get(hostname);
|
||||
if ( iHn !== undefined ) {
|
||||
do {
|
||||
const strId = this.hostnameSlots[iHn+0];
|
||||
out[strId & mask].add(
|
||||
this.strSlots[strId >>> this.nBits]
|
||||
);
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
} while ( iHn !== 0 );
|
||||
}
|
||||
if ( hostname === '' ) { break; }
|
||||
const pos = hostname.indexOf('.');
|
||||
if ( pos === -1 ) {
|
||||
if ( modifiers === 1 ) { break; }
|
||||
hostname = '';
|
||||
} else {
|
||||
hostname = hostname.slice(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasStr(hostname, exceptionBit, value) {
|
||||
let found = false;
|
||||
for (;;) {
|
||||
let iHn = this.hostnameToSlotIdMap.get(hostname);
|
||||
if ( iHn !== undefined ) {
|
||||
do {
|
||||
const strId = this.hostnameSlots[iHn+0];
|
||||
const str = this.strSlots[strId >>> this.nBits];
|
||||
if ( (strId & exceptionBit) !== 0 ) {
|
||||
if ( str === value || str === '' ) { return false; }
|
||||
}
|
||||
if ( str === value ) { found = true; }
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
} while ( iHn !== 0 );
|
||||
}
|
||||
if ( hostname === '' ) { break; }
|
||||
const pos = hostname.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
hostname = hostname.slice(pos + 1);
|
||||
} else if ( hostname !== '*' ) {
|
||||
hostname = '*';
|
||||
} else {
|
||||
hostname = '';
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
toSelfie() {
|
||||
return {
|
||||
hostnameToSlotIdMap: Array.from(this.hostnameToSlotIdMap),
|
||||
hostnameSlots: this.hostnameSlots,
|
||||
strSlots: this.strSlots,
|
||||
size: this.size
|
||||
};
|
||||
}
|
||||
|
||||
fromSelfie(selfie) {
|
||||
if ( selfie === undefined ) { return; }
|
||||
this.hostnameToSlotIdMap = new Map(selfie.hostnameToSlotIdMap);
|
||||
this.hostnameSlots = selfie.hostnameSlots;
|
||||
this.strSlots = selfie.strSlots;
|
||||
this.size = selfie.size;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const StaticExtFilteringSessionDB = class {
|
||||
constructor() {
|
||||
this.db = new Map();
|
||||
}
|
||||
compile(s) {
|
||||
return s;
|
||||
}
|
||||
add(bits, s) {
|
||||
const bucket = this.db.get(bits);
|
||||
if ( bucket === undefined ) {
|
||||
this.db.set(bits, new Set([ s ]));
|
||||
} else {
|
||||
bucket.add(s);
|
||||
}
|
||||
}
|
||||
remove(bits, s) {
|
||||
const bucket = this.db.get(bits);
|
||||
if ( bucket === undefined ) { return; }
|
||||
bucket.delete(s);
|
||||
if ( bucket.size !== 0 ) { return; }
|
||||
this.db.delete(bits);
|
||||
}
|
||||
retrieve(out) {
|
||||
const mask = out.length - 1;
|
||||
for ( const [ bits, bucket ] of this.db ) {
|
||||
const i = bits & mask;
|
||||
if ( out[i] instanceof Object === false ) { continue; }
|
||||
for ( const s of bucket ) {
|
||||
out[i].add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
has(bits, s) {
|
||||
const selectors = this.db.get(bits);
|
||||
return selectors !== undefined && selectors.has(s);
|
||||
}
|
||||
clear() {
|
||||
this.db.clear();
|
||||
}
|
||||
get isNotEmpty() {
|
||||
return this.db.size !== 0;
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export {
|
||||
StaticExtFilteringHostnameDB,
|
||||
StaticExtFilteringSessionDB,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
|
@ -23,7 +23,12 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
||||
import htmlFilteringEngine from './html-filtering.js';
|
||||
import httpheaderFilteringEngine from './httpheader-filtering.js';
|
||||
import io from './assets.js';
|
||||
import logger from './logger.js';
|
||||
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
@ -52,244 +57,49 @@ import µBlock from './background.js';
|
|||
|
||||
**/
|
||||
|
||||
const µb = µBlock;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public API
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const api = {
|
||||
const staticExtFilteringEngine = {
|
||||
get acceptedCount() {
|
||||
return µb.cosmeticFilteringEngine.acceptedCount +
|
||||
µb.scriptletFilteringEngine.acceptedCount +
|
||||
µb.httpheaderFilteringEngine.acceptedCount +
|
||||
µb.htmlFilteringEngine.acceptedCount;
|
||||
return cosmeticFilteringEngine.acceptedCount +
|
||||
scriptletFilteringEngine.acceptedCount +
|
||||
httpheaderFilteringEngine.acceptedCount +
|
||||
htmlFilteringEngine.acceptedCount;
|
||||
},
|
||||
get discardedCount() {
|
||||
return µb.cosmeticFilteringEngine.discardedCount +
|
||||
µb.scriptletFilteringEngine.discardedCount +
|
||||
µb.httpheaderFilteringEngine.discardedCount +
|
||||
µb.htmlFilteringEngine.discardedCount;
|
||||
return cosmeticFilteringEngine.discardedCount +
|
||||
scriptletFilteringEngine.discardedCount +
|
||||
httpheaderFilteringEngine.discardedCount +
|
||||
htmlFilteringEngine.discardedCount;
|
||||
},
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public classes
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
api.HostnameBasedDB = class {
|
||||
constructor(nBits, selfie = undefined) {
|
||||
this.nBits = nBits;
|
||||
this.timer = undefined;
|
||||
this.strToIdMap = new Map();
|
||||
this.hostnameToSlotIdMap = new Map();
|
||||
// Array of integer pairs
|
||||
this.hostnameSlots = [];
|
||||
// Array of strings (selectors and pseudo-selectors)
|
||||
this.strSlots = [];
|
||||
this.size = 0;
|
||||
if ( selfie !== undefined ) {
|
||||
this.fromSelfie(selfie);
|
||||
}
|
||||
}
|
||||
|
||||
store(hn, bits, s) {
|
||||
this.size += 1;
|
||||
let iStr = this.strToIdMap.get(s);
|
||||
if ( iStr === undefined ) {
|
||||
iStr = this.strSlots.length;
|
||||
this.strSlots.push(s);
|
||||
this.strToIdMap.set(s, iStr);
|
||||
if ( this.timer === undefined ) {
|
||||
this.collectGarbage(true);
|
||||
}
|
||||
}
|
||||
const strId = iStr << this.nBits | bits;
|
||||
let iHn = this.hostnameToSlotIdMap.get(hn);
|
||||
if ( iHn === undefined ) {
|
||||
this.hostnameToSlotIdMap.set(hn, this.hostnameSlots.length);
|
||||
this.hostnameSlots.push(strId, 0);
|
||||
return;
|
||||
}
|
||||
// Add as last item.
|
||||
while ( this.hostnameSlots[iHn+1] !== 0 ) {
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
}
|
||||
this.hostnameSlots[iHn+1] = this.hostnameSlots.length;
|
||||
this.hostnameSlots.push(strId, 0);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.hostnameToSlotIdMap.clear();
|
||||
this.hostnameSlots.length = 0;
|
||||
this.strSlots.length = 0;
|
||||
this.strToIdMap.clear();
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
collectGarbage(later = false) {
|
||||
if ( later === false ) {
|
||||
if ( this.timer !== undefined ) {
|
||||
self.cancelIdleCallback(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
this.strToIdMap.clear();
|
||||
return;
|
||||
}
|
||||
if ( this.timer !== undefined ) { return; }
|
||||
this.timer = self.requestIdleCallback(
|
||||
( ) => {
|
||||
this.timer = undefined;
|
||||
this.strToIdMap.clear();
|
||||
},
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
}
|
||||
|
||||
// modifiers = 1: return only specific items
|
||||
// modifiers = 2: return only generic items
|
||||
//
|
||||
retrieve(hostname, out, modifiers = 0) {
|
||||
if ( modifiers === 2 ) {
|
||||
hostname = '';
|
||||
}
|
||||
const mask = out.length - 1; // out.length must be power of two
|
||||
for (;;) {
|
||||
let iHn = this.hostnameToSlotIdMap.get(hostname);
|
||||
if ( iHn !== undefined ) {
|
||||
do {
|
||||
const strId = this.hostnameSlots[iHn+0];
|
||||
out[strId & mask].add(
|
||||
this.strSlots[strId >>> this.nBits]
|
||||
);
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
} while ( iHn !== 0 );
|
||||
}
|
||||
if ( hostname === '' ) { break; }
|
||||
const pos = hostname.indexOf('.');
|
||||
if ( pos === -1 ) {
|
||||
if ( modifiers === 1 ) { break; }
|
||||
hostname = '';
|
||||
} else {
|
||||
hostname = hostname.slice(pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasStr(hostname, exceptionBit, value) {
|
||||
let found = false;
|
||||
for (;;) {
|
||||
let iHn = this.hostnameToSlotIdMap.get(hostname);
|
||||
if ( iHn !== undefined ) {
|
||||
do {
|
||||
const strId = this.hostnameSlots[iHn+0];
|
||||
const str = this.strSlots[strId >>> this.nBits];
|
||||
if ( (strId & exceptionBit) !== 0 ) {
|
||||
if ( str === value || str === '' ) { return false; }
|
||||
}
|
||||
if ( str === value ) { found = true; }
|
||||
iHn = this.hostnameSlots[iHn+1];
|
||||
} while ( iHn !== 0 );
|
||||
}
|
||||
if ( hostname === '' ) { break; }
|
||||
const pos = hostname.indexOf('.');
|
||||
if ( pos !== -1 ) {
|
||||
hostname = hostname.slice(pos + 1);
|
||||
} else if ( hostname !== '*' ) {
|
||||
hostname = '*';
|
||||
} else {
|
||||
hostname = '';
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
toSelfie() {
|
||||
return {
|
||||
hostnameToSlotIdMap: Array.from(this.hostnameToSlotIdMap),
|
||||
hostnameSlots: this.hostnameSlots,
|
||||
strSlots: this.strSlots,
|
||||
size: this.size
|
||||
};
|
||||
}
|
||||
|
||||
fromSelfie(selfie) {
|
||||
if ( selfie === undefined ) { return; }
|
||||
this.hostnameToSlotIdMap = new Map(selfie.hostnameToSlotIdMap);
|
||||
this.hostnameSlots = selfie.hostnameSlots;
|
||||
this.strSlots = selfie.strSlots;
|
||||
this.size = selfie.size;
|
||||
}
|
||||
};
|
||||
|
||||
api.SessionDB = class {
|
||||
constructor() {
|
||||
this.db = new Map();
|
||||
}
|
||||
compile(s) {
|
||||
return s;
|
||||
}
|
||||
add(bits, s) {
|
||||
const bucket = this.db.get(bits);
|
||||
if ( bucket === undefined ) {
|
||||
this.db.set(bits, new Set([ s ]));
|
||||
} else {
|
||||
bucket.add(s);
|
||||
}
|
||||
}
|
||||
remove(bits, s) {
|
||||
const bucket = this.db.get(bits);
|
||||
if ( bucket === undefined ) { return; }
|
||||
bucket.delete(s);
|
||||
if ( bucket.size !== 0 ) { return; }
|
||||
this.db.delete(bits);
|
||||
}
|
||||
retrieve(out) {
|
||||
const mask = out.length - 1;
|
||||
for ( const [ bits, bucket ] of this.db ) {
|
||||
const i = bits & mask;
|
||||
if ( out[i] instanceof Object === false ) { continue; }
|
||||
for ( const s of bucket ) {
|
||||
out[i].add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
has(bits, s) {
|
||||
const selectors = this.db.get(bits);
|
||||
return selectors !== undefined && selectors.has(s);
|
||||
}
|
||||
clear() {
|
||||
this.db.clear();
|
||||
}
|
||||
get isNotEmpty() {
|
||||
return this.db.size !== 0;
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public methods
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
api.reset = function() {
|
||||
µb.cosmeticFilteringEngine.reset();
|
||||
µb.scriptletFilteringEngine.reset();
|
||||
µb.httpheaderFilteringEngine.reset();
|
||||
µb.htmlFilteringEngine.reset();
|
||||
staticExtFilteringEngine.reset = function() {
|
||||
cosmeticFilteringEngine.reset();
|
||||
scriptletFilteringEngine.reset();
|
||||
httpheaderFilteringEngine.reset();
|
||||
htmlFilteringEngine.reset();
|
||||
};
|
||||
|
||||
api.freeze = function() {
|
||||
µb.cosmeticFilteringEngine.freeze();
|
||||
µb.scriptletFilteringEngine.freeze();
|
||||
µb.httpheaderFilteringEngine.freeze();
|
||||
µb.htmlFilteringEngine.freeze();
|
||||
staticExtFilteringEngine.freeze = function() {
|
||||
cosmeticFilteringEngine.freeze();
|
||||
scriptletFilteringEngine.freeze();
|
||||
httpheaderFilteringEngine.freeze();
|
||||
htmlFilteringEngine.freeze();
|
||||
};
|
||||
|
||||
api.compile = function(parser, writer) {
|
||||
staticExtFilteringEngine.compile = function(parser, writer) {
|
||||
if ( parser.category !== parser.CATStaticExtFilter ) { return false; }
|
||||
|
||||
if ( (parser.flavorBits & parser.BITFlavorUnsupported) !== 0 ) {
|
||||
const who = writer.properties.get('name') || '?';
|
||||
µb.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: `Invalid extended filter in ${who}: ${parser.raw}`
|
||||
|
@ -299,13 +109,13 @@ api.compile = function(parser, writer) {
|
|||
|
||||
// Scriptlet injection
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtScriptlet) !== 0 ) {
|
||||
µb.scriptletFilteringEngine.compile(parser, writer);
|
||||
scriptletFilteringEngine.compile(parser, writer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Response header filtering
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtResponseHeader) !== 0 ) {
|
||||
µb.httpheaderFilteringEngine.compile(parser, writer);
|
||||
httpheaderFilteringEngine.compile(parser, writer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -313,67 +123,65 @@ api.compile = function(parser, writer) {
|
|||
// TODO: evaluate converting Adguard's `$$` syntax into uBO's HTML
|
||||
// filtering syntax.
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtHTML) !== 0 ) {
|
||||
µb.htmlFilteringEngine.compile(parser, writer);
|
||||
htmlFilteringEngine.compile(parser, writer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cosmetic filtering
|
||||
µb.cosmeticFilteringEngine.compile(parser, writer);
|
||||
cosmeticFilteringEngine.compile(parser, writer);
|
||||
return true;
|
||||
};
|
||||
|
||||
api.compileTemporary = function(parser) {
|
||||
staticExtFilteringEngine.compileTemporary = function(parser) {
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtScriptlet) !== 0 ) {
|
||||
return µb.scriptletFilteringEngine.compileTemporary(parser);
|
||||
return scriptletFilteringEngine.compileTemporary(parser);
|
||||
}
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtResponseHeader) !== 0 ) {
|
||||
return µb.httpheaderFilteringEngine.compileTemporary(parser);
|
||||
return httpheaderFilteringEngine.compileTemporary(parser);
|
||||
}
|
||||
if ( (parser.flavorBits & parser.BITFlavorExtHTML) !== 0 ) {
|
||||
return µb.htmlFilteringEngine.compileTemporary(parser);
|
||||
return htmlFilteringEngine.compileTemporary(parser);
|
||||
}
|
||||
return µb.cosmeticFilteringEngine.compileTemporary(parser);
|
||||
return cosmeticFilteringEngine.compileTemporary(parser);
|
||||
};
|
||||
|
||||
api.fromCompiledContent = function(reader, options) {
|
||||
µb.cosmeticFilteringEngine.fromCompiledContent(reader, options);
|
||||
µb.scriptletFilteringEngine.fromCompiledContent(reader, options);
|
||||
µb.httpheaderFilteringEngine.fromCompiledContent(reader, options);
|
||||
µb.htmlFilteringEngine.fromCompiledContent(reader, options);
|
||||
staticExtFilteringEngine.fromCompiledContent = function(reader, options) {
|
||||
cosmeticFilteringEngine.fromCompiledContent(reader, options);
|
||||
scriptletFilteringEngine.fromCompiledContent(reader, options);
|
||||
httpheaderFilteringEngine.fromCompiledContent(reader, options);
|
||||
htmlFilteringEngine.fromCompiledContent(reader, options);
|
||||
};
|
||||
|
||||
api.toSelfie = function(path) {
|
||||
return µBlock.assets.put(
|
||||
staticExtFilteringEngine.toSelfie = function(path) {
|
||||
return io.put(
|
||||
`${path}/main`,
|
||||
JSON.stringify({
|
||||
cosmetic: µb.cosmeticFilteringEngine.toSelfie(),
|
||||
scriptlets: µb.scriptletFilteringEngine.toSelfie(),
|
||||
httpHeaders: µb.httpheaderFilteringEngine.toSelfie(),
|
||||
html: µb.htmlFilteringEngine.toSelfie(),
|
||||
cosmetic: cosmeticFilteringEngine.toSelfie(),
|
||||
scriptlets: scriptletFilteringEngine.toSelfie(),
|
||||
httpHeaders: httpheaderFilteringEngine.toSelfie(),
|
||||
html: htmlFilteringEngine.toSelfie(),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
api.fromSelfie = function(path) {
|
||||
return µBlock.assets.get(`${path}/main`).then(details => {
|
||||
staticExtFilteringEngine.fromSelfie = function(path) {
|
||||
return io.get(`${path}/main`).then(details => {
|
||||
let selfie;
|
||||
try {
|
||||
selfie = JSON.parse(details.content);
|
||||
} catch (ex) {
|
||||
}
|
||||
if ( selfie instanceof Object === false ) { return false; }
|
||||
µb.cosmeticFilteringEngine.fromSelfie(selfie.cosmetic);
|
||||
µb.scriptletFilteringEngine.fromSelfie(selfie.scriptlets);
|
||||
µb.httpheaderFilteringEngine.fromSelfie(selfie.httpHeaders);
|
||||
µb.htmlFilteringEngine.fromSelfie(selfie.html);
|
||||
cosmeticFilteringEngine.fromSelfie(selfie.cosmetic);
|
||||
scriptletFilteringEngine.fromSelfie(selfie.scriptlets);
|
||||
httpheaderFilteringEngine.fromSelfie(selfie.httpHeaders);
|
||||
htmlFilteringEngine.fromSelfie(selfie.html);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.staticExtFilteringEngine = api;
|
||||
export default staticExtFilteringEngine;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -3396,8 +3396,6 @@ FilterContainer.prototype.freeze = function() {
|
|||
const filterBucketId = FilterBucket.fid;
|
||||
const unserialize = CompiledListReader.unserialize;
|
||||
|
||||
const t0 = Date.now();
|
||||
|
||||
for ( const line of this.goodFilters ) {
|
||||
if ( this.badFilters.has(line) ) {
|
||||
this.discardedCount += 1;
|
||||
|
@ -3487,8 +3485,6 @@ FilterContainer.prototype.freeze = function() {
|
|||
this.optimize();
|
||||
}, { timeout: 5000 });
|
||||
}
|
||||
|
||||
console.info(`staticNetFilteringEngine.freeze() took ${Date.now()-t0} ms`);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -3499,8 +3495,6 @@ FilterContainer.prototype.optimize = function() {
|
|||
this.optimizeTimerId = undefined;
|
||||
}
|
||||
|
||||
const t0 = Date.now();
|
||||
|
||||
for ( let bits = 0, n = this.categories.length; bits < n; bits++ ) {
|
||||
const bucket = this.categories[bits];
|
||||
if ( bucket === undefined ) { continue; }
|
||||
|
@ -3523,8 +3517,6 @@ FilterContainer.prototype.optimize = function() {
|
|||
for ( let i = filterUnitWritePtr, n = filterUnits.length; i < n; i++ ) {
|
||||
filterUnits[i] = null;
|
||||
}
|
||||
|
||||
console.info(`staticNetFilteringEngine.optimize() took ${Date.now()-t0} ms`);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -4477,9 +4469,7 @@ FilterContainer.prototype.benchmark = async function(requests, options = {}) {
|
|||
return text;
|
||||
}
|
||||
|
||||
const print = log.print;
|
||||
|
||||
print(`Benchmarking staticNetFilteringEngine.matchRequest()...`);
|
||||
console.info(`Benchmarking staticNetFilteringEngine.matchRequest()...`);
|
||||
|
||||
const fctxt = new FilteringContext();
|
||||
|
||||
|
@ -4489,12 +4479,12 @@ FilterContainer.prototype.benchmark = async function(requests, options = {}) {
|
|||
fctxt.setDocOriginFromURL(request.frameUrl);
|
||||
fctxt.setType(request.cpt);
|
||||
const r = this.matchRequest(fctxt);
|
||||
print(`Result=${r}:`);
|
||||
print(`\ttype=${fctxt.type}`);
|
||||
print(`\turl=${fctxt.url}`);
|
||||
print(`\tdocOrigin=${fctxt.getDocOrigin()}`);
|
||||
console.info(`Result=${r}:`);
|
||||
console.info(`\ttype=${fctxt.type}`);
|
||||
console.info(`\turl=${fctxt.url}`);
|
||||
console.info(`\tdocOrigin=${fctxt.getDocOrigin()}`);
|
||||
if ( r !== 0 ) {
|
||||
console.log(this.toLogData());
|
||||
console.info(this.toLogData());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -4524,11 +4514,11 @@ FilterContainer.prototype.benchmark = async function(requests, options = {}) {
|
|||
matchCount += 1;
|
||||
if ( recorded !== undefined ) { recorded.push(r); }
|
||||
if ( expected !== undefined && r !== expected[i] ) {
|
||||
print(`Mismatch with reference results at ${i}:`);
|
||||
print(`\tExpected ${expected[i]}, got ${r}:`);
|
||||
print(`\ttype=${fctxt.type}`);
|
||||
print(`\turl=${fctxt.url}`);
|
||||
print(`\tdocOrigin=${fctxt.getDocOrigin()}`);
|
||||
console.info(`Mismatch with reference results at ${i}:`);
|
||||
console.info(`\tExpected ${expected[i]}, got ${r}:`);
|
||||
console.info(`\ttype=${fctxt.type}`);
|
||||
console.info(`\turl=${fctxt.url}`);
|
||||
console.info(`\tdocOrigin=${fctxt.getDocOrigin()}`);
|
||||
}
|
||||
if ( r !== 1 ) {
|
||||
if ( this.hasQuery(fctxt) ) {
|
||||
|
@ -4564,7 +4554,7 @@ FilterContainer.prototype.benchmark = async function(requests, options = {}) {
|
|||
);
|
||||
}
|
||||
const s = output.join('\n');
|
||||
print(s);
|
||||
console.info(s);
|
||||
return s;
|
||||
};
|
||||
|
||||
|
@ -4576,9 +4566,9 @@ FilterContainer.prototype.test = async function(docURL, type, url) {
|
|||
fctxt.setType(type);
|
||||
fctxt.setURL(url);
|
||||
const r = this.matchRequest(fctxt);
|
||||
console.log(`${r}`);
|
||||
console.info(`${r}`);
|
||||
if ( r !== 0 ) {
|
||||
console.log(this.toLogData());
|
||||
console.info(this.toLogData());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4643,7 +4633,7 @@ FilterContainer.prototype.bucketHistogram = function() {
|
|||
results.sort((a, b) => {
|
||||
return b.size - a.size;
|
||||
});
|
||||
console.log(results);
|
||||
console.info(results);
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
|
@ -4733,7 +4723,7 @@ FilterContainer.prototype.filterClassHistogram = function() {
|
|||
const results = Array.from(filterClassDetails.values()).sort((a, b) => {
|
||||
return b.count - a.count;
|
||||
});
|
||||
console.log(results);
|
||||
console.info(results);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -4772,14 +4762,12 @@ FilterContainer.prototype.tokenHistograms = async function(requests) {
|
|||
hitTokenMap.delete(token);
|
||||
}
|
||||
const tophits = Array.from(hitTokenMap).sort(customSort).slice(0, 100);
|
||||
console.log('Misses:', JSON.stringify(topmisses));
|
||||
console.log('Hits:', JSON.stringify(tophits));
|
||||
console.info('Misses:', JSON.stringify(topmisses));
|
||||
console.info('Hits:', JSON.stringify(tophits));
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const staticNetFilteringEngine = new FilterContainer();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export { staticNetFilteringEngine };
|
||||
export default staticNetFilteringEngine;
|
||||
|
|
|
@ -26,12 +26,24 @@
|
|||
import '../lib/publicsuffixlist/publicsuffixlist.js';
|
||||
import '../lib/punycode.js';
|
||||
|
||||
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
||||
import globals from './globals.js';
|
||||
import io from './assets.js';
|
||||
import logger from './logger.js';
|
||||
import lz4Codec from './lz4.js';
|
||||
import staticExtFilteringEngine from './static-ext-filtering.js';
|
||||
import staticFilteringReverseLookup from './reverselookup.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { hostnameFromURI } from './uri-utils.js';
|
||||
import { sparseBase64 } from './base64-custom.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import { permanentFirewall } from './dynamic-net-filtering.js';
|
||||
import { permanentSwitches } from './hnswitches.js';
|
||||
import { permanentURLFiltering } from './url-net-filtering.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
import { sparseBase64 } from './base64-custom.js';
|
||||
import { StaticFilteringParser } from './static-filtering-parser.js';
|
||||
import µBlock from './background.js';
|
||||
import { ubolog, ubologSet } from './console.js';
|
||||
|
||||
import {
|
||||
CompiledListReader,
|
||||
|
@ -40,7 +52,7 @@ import {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.getBytesInUse = async function() {
|
||||
µb.getBytesInUse = async function() {
|
||||
const promises = [];
|
||||
let bytesInUse;
|
||||
|
||||
|
@ -71,17 +83,16 @@ import {
|
|||
if ( results.length > 1 && results[1] instanceof Object ) {
|
||||
processCount(results[1].usage);
|
||||
}
|
||||
µBlock.storageUsed = bytesInUse;
|
||||
µb.storageUsed = bytesInUse;
|
||||
return bytesInUse;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.saveLocalSettings = (( ) => {
|
||||
µb.saveLocalSettings = (( ) => {
|
||||
const saveAfter = 4 * 60 * 1000;
|
||||
|
||||
const onTimeout = ( ) => {
|
||||
const µb = µBlock;
|
||||
if ( µb.localSettingsLastModified > µb.localSettingsLastSaved ) {
|
||||
µb.saveLocalSettings();
|
||||
}
|
||||
|
@ -98,7 +109,7 @@ import {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadUserSettings = async function() {
|
||||
µb.loadUserSettings = async function() {
|
||||
const usDefault = this.userSettingsDefault;
|
||||
|
||||
const results = await Promise.all([
|
||||
|
@ -126,7 +137,7 @@ import {
|
|||
return usUser;
|
||||
};
|
||||
|
||||
µBlock.saveUserSettings = function() {
|
||||
µb.saveUserSettings = function() {
|
||||
const toSave = this.getModifiedSettings(
|
||||
this.userSettings,
|
||||
this.userSettingsDefault
|
||||
|
@ -154,7 +165,7 @@ import {
|
|||
|
||||
// Admin hidden settings have precedence over user hidden settings.
|
||||
|
||||
µBlock.loadHiddenSettings = async function() {
|
||||
µb.loadHiddenSettings = async function() {
|
||||
const hsDefault = this.hiddenSettingsDefault;
|
||||
const hsAdmin = this.hiddenSettingsAdmin;
|
||||
const hsUser = this.hiddenSettings;
|
||||
|
@ -186,7 +197,7 @@ import {
|
|||
hsDefault[name] = hsAdmin[name] = hsUser[name] = value;
|
||||
}
|
||||
}
|
||||
µBlock.noDashboard = disableDashboard === true;
|
||||
µb.noDashboard = disableDashboard === true;
|
||||
if ( Array.isArray(disabledPopupPanelParts) ) {
|
||||
const partNameToBit = new Map([
|
||||
[ 'globalStats', 0b00010 ],
|
||||
|
@ -230,7 +241,7 @@ import {
|
|||
// This way the new default values in the future will properly apply for
|
||||
// those which were not modified by the user.
|
||||
|
||||
µBlock.saveHiddenSettings = function() {
|
||||
µb.saveHiddenSettings = function() {
|
||||
vAPI.storage.set({
|
||||
hiddenSettings: this.getModifiedSettings(
|
||||
this.hiddenSettings,
|
||||
|
@ -240,8 +251,8 @@ import {
|
|||
};
|
||||
|
||||
self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||
const µbhs = µBlock.hiddenSettings;
|
||||
self.log.verbosity = µbhs.consoleLogLevel;
|
||||
const µbhs = µb.hiddenSettings;
|
||||
ubologSet(µbhs.consoleLogLevel === 'info');
|
||||
vAPI.net.setOptions({
|
||||
cnameIgnoreList: µbhs.cnameIgnoreList,
|
||||
cnameIgnore1stParty: µbhs.cnameIgnore1stParty,
|
||||
|
@ -255,7 +266,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.hiddenSettingsFromString = function(raw) {
|
||||
µb.hiddenSettingsFromString = function(raw) {
|
||||
const out = Object.assign({}, this.hiddenSettingsDefault);
|
||||
const lineIter = new LineIterator(raw);
|
||||
while ( lineIter.eot() === false ) {
|
||||
|
@ -273,7 +284,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
return out;
|
||||
};
|
||||
|
||||
µBlock.hiddenSettingValueFromString = function(name, value) {
|
||||
µb.hiddenSettingValueFromString = function(name, value) {
|
||||
if ( typeof name !== 'string' || typeof value !== 'string' ) { return; }
|
||||
const hsDefault = this.hiddenSettingsDefault;
|
||||
if ( hsDefault.hasOwnProperty(name) === false ) { return; }
|
||||
|
@ -305,7 +316,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
return r;
|
||||
};
|
||||
|
||||
µBlock.stringFromHiddenSettings = function() {
|
||||
µb.stringFromHiddenSettings = function() {
|
||||
const out = [];
|
||||
for ( const key of Object.keys(this.hiddenSettings).sort() ) {
|
||||
out.push(key + ' ' + this.hiddenSettings[key]);
|
||||
|
@ -315,31 +326,31 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.savePermanentFirewallRules = function() {
|
||||
µb.savePermanentFirewallRules = function() {
|
||||
vAPI.storage.set({
|
||||
dynamicFilteringString: this.permanentFirewall.toString()
|
||||
dynamicFilteringString: permanentFirewall.toString()
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.savePermanentURLFilteringRules = function() {
|
||||
µb.savePermanentURLFilteringRules = function() {
|
||||
vAPI.storage.set({
|
||||
urlFilteringString: this.permanentURLFiltering.toString()
|
||||
urlFilteringString: permanentURLFiltering.toString()
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.saveHostnameSwitches = function() {
|
||||
µb.saveHostnameSwitches = function() {
|
||||
vAPI.storage.set({
|
||||
hostnameSwitchesString: this.permanentSwitches.toString()
|
||||
hostnameSwitchesString: permanentSwitches.toString()
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.saveWhitelist = function() {
|
||||
µb.saveWhitelist = function() {
|
||||
vAPI.storage.set({
|
||||
netWhitelist: this.arrayFromWhitelist(this.netWhitelist)
|
||||
});
|
||||
|
@ -348,7 +359,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadSelectedFilterLists = async function() {
|
||||
µb.loadSelectedFilterLists = async function() {
|
||||
const bin = await vAPI.storage.get('selectedFilterLists');
|
||||
if ( bin instanceof Object && Array.isArray(bin.selectedFilterLists) ) {
|
||||
this.selectedFilterLists = bin.selectedFilterLists;
|
||||
|
@ -357,11 +368,11 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
// https://github.com/gorhill/uBlock/issues/747
|
||||
// Select default filter lists if first-time launch.
|
||||
const lists = await this.assets.metadata();
|
||||
const lists = await io.metadata();
|
||||
this.saveSelectedFilterLists(this.autoSelectRegionalFilterLists(lists));
|
||||
};
|
||||
|
||||
µBlock.saveSelectedFilterLists = function(newKeys, append = false) {
|
||||
µb.saveSelectedFilterLists = function(newKeys, append = false) {
|
||||
const oldKeys = this.selectedFilterLists.slice();
|
||||
if ( append ) {
|
||||
newKeys = newKeys.concat(oldKeys);
|
||||
|
@ -380,7 +391,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.applyFilterListSelection = function(details) {
|
||||
µb.applyFilterListSelection = function(details) {
|
||||
let selectedListKeySet = new Set(this.selectedFilterLists);
|
||||
let importedLists = this.userSettings.importedLists.slice();
|
||||
|
||||
|
@ -458,7 +469,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.listKeysFromCustomFilterLists = function(raw) {
|
||||
µb.listKeysFromCustomFilterLists = function(raw) {
|
||||
const urls = typeof raw === 'string'
|
||||
? raw.trim().split(/[\n\r]+/)
|
||||
: raw;
|
||||
|
@ -476,20 +487,20 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.saveUserFilters = function(content) {
|
||||
µb.saveUserFilters = function(content) {
|
||||
// https://github.com/gorhill/uBlock/issues/1022
|
||||
// Be sure to end with an empty line.
|
||||
content = content.trim();
|
||||
if ( content !== '' ) { content += '\n'; }
|
||||
this.removeCompiledFilterList(this.userFiltersPath);
|
||||
return this.assets.put(this.userFiltersPath, content);
|
||||
return io.put(this.userFiltersPath, content);
|
||||
};
|
||||
|
||||
µBlock.loadUserFilters = function() {
|
||||
return this.assets.get(this.userFiltersPath);
|
||||
µb.loadUserFilters = function() {
|
||||
return io.get(this.userFiltersPath);
|
||||
};
|
||||
|
||||
µBlock.appendUserFilters = async function(filters, options) {
|
||||
µb.appendUserFilters = async function(filters, options) {
|
||||
filters = filters.trim();
|
||||
if ( filters.length === 0 ) { return; }
|
||||
|
||||
|
@ -542,8 +553,8 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
const compiledFilters = this.compileFilters(filters, {
|
||||
assetKey: this.userFiltersPath
|
||||
});
|
||||
const snfe = this.staticNetFilteringEngine;
|
||||
const cfe = this.cosmeticFilteringEngine;
|
||||
const snfe = staticNetFilteringEngine;
|
||||
const cfe = cosmeticFilteringEngine;
|
||||
const acceptedCount = snfe.acceptedCount + cfe.acceptedCount;
|
||||
const discardedCount = snfe.discardedCount + cfe.discardedCount;
|
||||
this.applyCompiledFilters(compiledFilters, true);
|
||||
|
@ -557,9 +568,9 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
entry.entryCount += deltaEntryCount;
|
||||
entry.entryUsedCount += deltaEntryUsedCount;
|
||||
vAPI.storage.set({ 'availableFilterLists': this.availableFilterLists });
|
||||
this.staticNetFilteringEngine.freeze();
|
||||
this.redirectEngine.freeze();
|
||||
this.staticExtFilteringEngine.freeze();
|
||||
staticNetFilteringEngine.freeze();
|
||||
redirectEngine.freeze();
|
||||
staticExtFilteringEngine.freeze();
|
||||
this.selfieManager.destroy();
|
||||
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/cj7g7m/
|
||||
|
@ -571,18 +582,18 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
vAPI.messaging.broadcast({ what: 'userFiltersUpdated' });
|
||||
};
|
||||
|
||||
µBlock.createUserFilters = function(details) {
|
||||
µb.createUserFilters = function(details) {
|
||||
this.appendUserFilters(details.filters, details);
|
||||
// https://github.com/gorhill/uBlock/issues/1786
|
||||
if ( details.docURL === undefined ) { return; }
|
||||
this.cosmeticFilteringEngine.removeFromSelectorCache(
|
||||
cosmeticFilteringEngine.removeFromSelectorCache(
|
||||
hostnameFromURI(details.docURL)
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.autoSelectRegionalFilterLists = function(lists) {
|
||||
µb.autoSelectRegionalFilterLists = function(lists) {
|
||||
const selectedListKeys = [ this.userFiltersPath ];
|
||||
for ( const key in lists ) {
|
||||
if ( lists.hasOwnProperty(key) === false ) { continue; }
|
||||
|
@ -601,7 +612,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.getAvailableLists = async function() {
|
||||
µb.getAvailableLists = async function() {
|
||||
let oldAvailableLists = {},
|
||||
newAvailableLists = {};
|
||||
|
||||
|
@ -625,7 +636,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
title: '',
|
||||
};
|
||||
newAvailableLists[listKey] = entry;
|
||||
this.assets.registerAssetSource(listKey, entry);
|
||||
io.registerAssetSource(listKey, entry);
|
||||
}
|
||||
|
||||
// Convert a no longer existing stock list into an imported list.
|
||||
|
@ -645,7 +656,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
title: oldEntry.title || ''
|
||||
};
|
||||
newAvailableLists[listURL] = newEntry;
|
||||
this.assets.registerAssetSource(listURL, newEntry);
|
||||
io.registerAssetSource(listURL, newEntry);
|
||||
importedListKeys.push(listURL);
|
||||
this.userSettings.importedLists.push(listURL.trim());
|
||||
this.saveUserSettings();
|
||||
|
@ -654,8 +665,8 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
const promises = [
|
||||
vAPI.storage.get('availableFilterLists'),
|
||||
this.assets.metadata(),
|
||||
this.badLists.size === 0 ? this.assets.get('ublock-badlists') : false,
|
||||
io.metadata(),
|
||||
this.badLists.size === 0 ? io.get('ublock-badlists') : false,
|
||||
];
|
||||
|
||||
// Load previously saved available lists -- these contains data
|
||||
|
@ -731,7 +742,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
if ( newEntry.submitter !== 'user' ) { continue; }
|
||||
if ( importedListKeys.indexOf(assetKey) !== -1 ) { continue; }
|
||||
delete newAvailableLists[assetKey];
|
||||
this.assets.unregisterAssetSource(assetKey);
|
||||
io.unregisterAssetSource(assetKey);
|
||||
this.removeFilterList(assetKey);
|
||||
}
|
||||
|
||||
|
@ -740,17 +751,17 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadFilterLists = (( ) => {
|
||||
µb.loadFilterLists = (( ) => {
|
||||
const loadedListKeys = [];
|
||||
let loadingPromise;
|
||||
let t0 = 0;
|
||||
|
||||
const onDone = function() {
|
||||
log.info(`loadFilterLists() took ${Date.now()-t0} ms`);
|
||||
ubolog(`loadFilterLists() took ${Date.now()-t0} ms`);
|
||||
|
||||
this.staticNetFilteringEngine.freeze();
|
||||
this.staticExtFilteringEngine.freeze();
|
||||
this.redirectEngine.freeze();
|
||||
staticNetFilteringEngine.freeze();
|
||||
staticExtFilteringEngine.freeze();
|
||||
redirectEngine.freeze();
|
||||
vAPI.net.unsuspend();
|
||||
|
||||
vAPI.storage.set({ 'availableFilterLists': this.availableFilterLists });
|
||||
|
@ -763,15 +774,15 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
});
|
||||
|
||||
this.selfieManager.destroy();
|
||||
this.lz4Codec.relinquish();
|
||||
lz4Codec.relinquish();
|
||||
this.compiledFormatChanged = false;
|
||||
|
||||
loadingPromise = undefined;
|
||||
};
|
||||
|
||||
const applyCompiledFilters = function(assetKey, compiled) {
|
||||
const snfe = this.staticNetFilteringEngine;
|
||||
const sxfe = this.staticExtFilteringEngine;
|
||||
const snfe = staticNetFilteringEngine;
|
||||
const sxfe = staticExtFilteringEngine;
|
||||
let acceptedCount = snfe.acceptedCount + sxfe.acceptedCount,
|
||||
discardedCount = snfe.discardedCount + sxfe.discardedCount;
|
||||
this.applyCompiledFilters(compiled, assetKey === this.userFiltersPath);
|
||||
|
@ -789,15 +800,15 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
this.availableFilterLists = lists;
|
||||
|
||||
vAPI.net.suspend();
|
||||
this.redirectEngine.reset();
|
||||
this.staticExtFilteringEngine.reset();
|
||||
this.staticNetFilteringEngine.reset();
|
||||
redirectEngine.reset();
|
||||
staticExtFilteringEngine.reset();
|
||||
staticNetFilteringEngine.reset();
|
||||
this.selfieManager.destroy();
|
||||
this.staticFilteringReverseLookup.resetLists();
|
||||
staticFilteringReverseLookup.resetLists();
|
||||
|
||||
// We need to build a complete list of assets to pull first: this is
|
||||
// because it *may* happens that some load operations are synchronous:
|
||||
// This happens for assets which do not exist, ot assets with no
|
||||
// This happens for assets which do not exist, or assets with no
|
||||
// content.
|
||||
const toLoad = [];
|
||||
for ( const assetKey in lists ) {
|
||||
|
@ -837,7 +848,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.getCompiledFilterList = async function(assetKey) {
|
||||
µb.getCompiledFilterList = async function(assetKey) {
|
||||
const compiledPath = 'compiled/' + assetKey;
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1365
|
||||
|
@ -847,7 +858,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
this.compiledFormatChanged === false &&
|
||||
this.badLists.has(assetKey) === false
|
||||
) {
|
||||
const compiledDetails = await this.assets.get(compiledPath);
|
||||
const compiledDetails = await io.get(compiledPath);
|
||||
if (
|
||||
parseInt(compiledDetails.content, 10) ===
|
||||
this.systemSettings.compiledMagic
|
||||
|
@ -862,7 +873,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
return { assetKey, content: '' };
|
||||
}
|
||||
|
||||
const rawDetails = await this.assets.get(assetKey, { silent: true });
|
||||
const rawDetails = await io.get(assetKey, { silent: true });
|
||||
// Compiling an empty string results in an empty string.
|
||||
if ( rawDetails.content === '' ) {
|
||||
rawDetails.assetKey = assetKey;
|
||||
|
@ -878,7 +889,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
const compiledContent =
|
||||
this.compileFilters(rawDetails.content, { assetKey });
|
||||
this.assets.put(compiledPath, compiledContent);
|
||||
io.put(compiledPath, compiledContent);
|
||||
|
||||
return { assetKey, content: compiledContent };
|
||||
};
|
||||
|
@ -892,7 +903,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// the whole raw filter list to be held in memory just because we cut out
|
||||
// the title as a substring.
|
||||
|
||||
µBlock.extractFilterListMetadata = function(assetKey, raw) {
|
||||
µb.extractFilterListMetadata = function(assetKey, raw) {
|
||||
const listEntry = this.availableFilterLists[assetKey];
|
||||
if ( listEntry === undefined ) { return; }
|
||||
// Metadata expected to be found at the top of content.
|
||||
|
@ -904,13 +915,13 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
const title = matches && matches[1].trim() || '';
|
||||
if ( title !== '' && title !== listEntry.title ) {
|
||||
listEntry.title = this.orphanizeString(title);
|
||||
this.assets.registerAssetSource(assetKey, { title });
|
||||
io.registerAssetSource(assetKey, { title });
|
||||
}
|
||||
matches = head.match(/(?:^|\n)(?:!|# )[\t ]*Homepage[\t ]*:[\t ]*(https?:\/\/\S+)\s/i);
|
||||
const supportURL = matches && matches[1] || '';
|
||||
if ( supportURL !== '' && supportURL !== listEntry.supportURL ) {
|
||||
listEntry.supportURL = this.orphanizeString(supportURL);
|
||||
this.assets.registerAssetSource(assetKey, { supportURL });
|
||||
io.registerAssetSource(assetKey, { supportURL });
|
||||
}
|
||||
}
|
||||
// Extract update frequency information
|
||||
|
@ -924,7 +935,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
updateAfter = Math.max(updateAfter, 1);
|
||||
if ( updateAfter !== listEntry.updateAfter ) {
|
||||
listEntry.updateAfter = updateAfter;
|
||||
this.assets.registerAssetSource(assetKey, { updateAfter });
|
||||
io.registerAssetSource(assetKey, { updateAfter });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -932,18 +943,18 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.removeCompiledFilterList = function(assetKey) {
|
||||
this.assets.remove('compiled/' + assetKey);
|
||||
µb.removeCompiledFilterList = function(assetKey) {
|
||||
io.remove('compiled/' + assetKey);
|
||||
};
|
||||
|
||||
µBlock.removeFilterList = function(assetKey) {
|
||||
µb.removeFilterList = function(assetKey) {
|
||||
this.removeCompiledFilterList(assetKey);
|
||||
this.assets.remove(assetKey);
|
||||
io.remove(assetKey);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.compileFilters = function(rawText, details = {}) {
|
||||
µb.compileFilters = function(rawText, details = {}) {
|
||||
const writer = new CompiledListWriter();
|
||||
|
||||
// Populate the writer with information potentially useful to the
|
||||
|
@ -957,8 +968,6 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// Useful references:
|
||||
// https://adblockplus.org/en/filter-cheatsheet
|
||||
// https://adblockplus.org/en/filters
|
||||
const staticNetFilteringEngine = this.staticNetFilteringEngine;
|
||||
const staticExtFilteringEngine = this.staticExtFilteringEngine;
|
||||
const lineIter = new LineIterator(this.preparseDirectives.prune(rawText));
|
||||
const parser = new StaticFilteringParser({ expertMode });
|
||||
|
||||
|
@ -990,7 +999,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
}
|
||||
if ( staticNetFilteringEngine.compile(parser, writer) ) { continue; }
|
||||
if ( staticNetFilteringEngine.error !== undefined ) {
|
||||
this.logger.writeOne({
|
||||
logger.writeOne({
|
||||
realm: 'message',
|
||||
type: 'error',
|
||||
text: staticNetFilteringEngine.error
|
||||
|
@ -1013,11 +1022,11 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// Added `firstparty` argument: to avoid discarding cosmetic filters when
|
||||
// applying 1st-party filters.
|
||||
|
||||
µBlock.applyCompiledFilters = function(rawText, firstparty) {
|
||||
µb.applyCompiledFilters = function(rawText, firstparty) {
|
||||
if ( rawText === '' ) { return; }
|
||||
const reader = new CompiledListReader(rawText);
|
||||
this.staticNetFilteringEngine.fromCompiled(reader);
|
||||
this.staticExtFilteringEngine.fromCompiledContent(reader, {
|
||||
staticNetFilteringEngine.fromCompiled(reader);
|
||||
staticExtFilteringEngine.fromCompiledContent(reader, {
|
||||
skipGenericCosmetic: this.userSettings.ignoreGenericCosmeticFilters,
|
||||
skipCosmetic: !firstparty && !this.userSettings.parseAllABPHideFilters
|
||||
});
|
||||
|
@ -1027,7 +1036,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
// https://github.com/AdguardTeam/AdguardBrowserExtension/issues/917
|
||||
|
||||
µBlock.preparseDirectives = {
|
||||
µb.preparseDirectives = {
|
||||
// This method returns an array of indices, corresponding to position in
|
||||
// the content string which should alternatively be parsed and discarded.
|
||||
split: function(content) {
|
||||
|
@ -1140,19 +1149,19 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadRedirectResources = async function() {
|
||||
µb.loadRedirectResources = async function() {
|
||||
try {
|
||||
const success = await this.redirectEngine.resourcesFromSelfie();
|
||||
const success = await redirectEngine.resourcesFromSelfie();
|
||||
if ( success === true ) { return true; }
|
||||
|
||||
const fetchPromises = [
|
||||
this.redirectEngine.loadBuiltinResources()
|
||||
redirectEngine.loadBuiltinResources()
|
||||
];
|
||||
|
||||
const userResourcesLocation = this.hiddenSettings.userResourcesLocation;
|
||||
if ( userResourcesLocation !== 'unset' ) {
|
||||
for ( const url of userResourcesLocation.split(/\s+/) ) {
|
||||
fetchPromises.push(this.assets.fetchText(url));
|
||||
fetchPromises.push(io.fetchText(url));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1172,10 +1181,10 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
content += '\n\n' + result.content;
|
||||
}
|
||||
|
||||
this.redirectEngine.resourcesFromString(content);
|
||||
this.redirectEngine.selfieFromResources();
|
||||
redirectEngine.resourcesFromString(content);
|
||||
redirectEngine.selfieFromResources();
|
||||
} catch(ex) {
|
||||
log.info(ex);
|
||||
ubolog(ex);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1183,31 +1192,31 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadPublicSuffixList = async function() {
|
||||
µb.loadPublicSuffixList = async function() {
|
||||
const psl = globals.publicSuffixList;
|
||||
if ( this.hiddenSettings.disableWebAssembly !== true ) {
|
||||
psl.enableWASM('/lib/publicsuffixlist');
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.assets.get(`compiled/${this.pslAssetKey}`);
|
||||
const result = await io.get(`compiled/${this.pslAssetKey}`);
|
||||
if ( psl.fromSelfie(result.content, sparseBase64) ) {
|
||||
return;
|
||||
}
|
||||
} catch (ex) {
|
||||
log.info(ex);
|
||||
ubolog(ex);
|
||||
}
|
||||
|
||||
const result = await this.assets.get(this.pslAssetKey);
|
||||
const result = await io.get(this.pslAssetKey);
|
||||
if ( result.content !== '' ) {
|
||||
this.compilePublicSuffixList(result.content);
|
||||
}
|
||||
};
|
||||
|
||||
µBlock.compilePublicSuffixList = function(content) {
|
||||
µb.compilePublicSuffixList = function(content) {
|
||||
const psl = globals.publicSuffixList;
|
||||
psl.parse(content, globals.punycode.toASCII);
|
||||
this.assets.put(`compiled/${this.pslAssetKey}`, psl.toSelfie(sparseBase64));
|
||||
io.put(`compiled/${this.pslAssetKey}`, psl.toSelfie(sparseBase64));
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1216,8 +1225,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// be generated if the user doesn't change his filter lists selection for
|
||||
// some set time.
|
||||
|
||||
µBlock.selfieManager = (( ) => {
|
||||
const µb = µBlock;
|
||||
µb.selfieManager = (( ) => {
|
||||
let createTimer;
|
||||
let destroyTimer;
|
||||
|
||||
|
@ -1227,28 +1235,27 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
const create = async function() {
|
||||
await Promise.all([
|
||||
µb.assets.put(
|
||||
io.put(
|
||||
'selfie/main',
|
||||
JSON.stringify({
|
||||
magic: µb.systemSettings.selfieMagic,
|
||||
availableFilterLists: µb.availableFilterLists,
|
||||
})
|
||||
),
|
||||
µb.redirectEngine.toSelfie('selfie/redirectEngine'),
|
||||
µb.staticExtFilteringEngine.toSelfie(
|
||||
redirectEngine.toSelfie('selfie/redirectEngine'),
|
||||
staticExtFilteringEngine.toSelfie(
|
||||
'selfie/staticExtFilteringEngine'
|
||||
),
|
||||
µb.staticNetFilteringEngine.toSelfie(
|
||||
µb.assets,
|
||||
staticNetFilteringEngine.toSelfie(io,
|
||||
'selfie/staticNetFilteringEngine'
|
||||
),
|
||||
]);
|
||||
µb.lz4Codec.relinquish();
|
||||
lz4Codec.relinquish();
|
||||
µb.selfieIsInvalid = false;
|
||||
};
|
||||
|
||||
const loadMain = async function() {
|
||||
const details = await µb.assets.get('selfie/main');
|
||||
const details = await io.get('selfie/main');
|
||||
if (
|
||||
details instanceof Object === false ||
|
||||
typeof details.content !== 'string' ||
|
||||
|
@ -1278,12 +1285,11 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
try {
|
||||
const results = await Promise.all([
|
||||
loadMain(),
|
||||
µb.redirectEngine.fromSelfie('selfie/redirectEngine'),
|
||||
µb.staticExtFilteringEngine.fromSelfie(
|
||||
redirectEngine.fromSelfie('selfie/redirectEngine'),
|
||||
staticExtFilteringEngine.fromSelfie(
|
||||
'selfie/staticExtFilteringEngine'
|
||||
),
|
||||
µb.staticNetFilteringEngine.fromSelfie(
|
||||
µb.assets,
|
||||
staticNetFilteringEngine.fromSelfie(io,
|
||||
'selfie/staticNetFilteringEngine'
|
||||
),
|
||||
]);
|
||||
|
@ -1292,14 +1298,14 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
}
|
||||
}
|
||||
catch (reason) {
|
||||
log.info(reason);
|
||||
ubolog(reason);
|
||||
}
|
||||
destroy();
|
||||
return false;
|
||||
};
|
||||
|
||||
const destroy = function() {
|
||||
µb.assets.remove(/^selfie\//);
|
||||
io.remove(/^selfie\//);
|
||||
µb.selfieIsInvalid = true;
|
||||
createTimer = vAPI.setTimeout(( ) => {
|
||||
createTimer = undefined;
|
||||
|
@ -1335,7 +1341,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// necessarily present, i.e. administrators may removed entries which
|
||||
// values are left to the user's choice.
|
||||
|
||||
µBlock.restoreAdminSettings = async function() {
|
||||
µb.restoreAdminSettings = async function() {
|
||||
let toOverwrite = {};
|
||||
let data;
|
||||
try {
|
||||
|
@ -1368,7 +1374,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
typeof data.assetsBootstrapLocation === 'string' &&
|
||||
data.assetsBootstrapLocation !== ''
|
||||
) {
|
||||
µBlock.assetsBootstrapLocation = data.assetsBootstrapLocation;
|
||||
µb.assetsBootstrapLocation = data.assetsBootstrapLocation;
|
||||
}
|
||||
|
||||
if ( typeof data.userSettings === 'object' ) {
|
||||
|
@ -1409,7 +1415,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
Array.isArray(toOverwrite.trustedSiteDirectives) &&
|
||||
toOverwrite.trustedSiteDirectives.length !== 0
|
||||
) {
|
||||
µBlock.netWhitelistDefault = toOverwrite.trustedSiteDirectives.slice();
|
||||
µb.netWhitelistDefault = toOverwrite.trustedSiteDirectives.slice();
|
||||
bin.netWhitelist = toOverwrite.trustedSiteDirectives.slice();
|
||||
binNotEmpty = true;
|
||||
} else if ( Array.isArray(data.whitelist) ) {
|
||||
|
@ -1457,7 +1463,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// https://github.com/gorhill/uBlock/issues/3210
|
||||
// Support ability to auto-enable a filter list based on user agent.
|
||||
|
||||
µBlock.listMatchesEnvironment = function(details) {
|
||||
µb.listMatchesEnvironment = function(details) {
|
||||
// Matches language?
|
||||
if ( typeof details.lang === 'string' ) {
|
||||
let re = this.listMatchesEnvironment.reLang;
|
||||
|
@ -1480,7 +1486,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.scheduleAssetUpdater = (( ) => {
|
||||
µb.scheduleAssetUpdater = (( ) => {
|
||||
let timer, next = 0;
|
||||
|
||||
return function(updateDelay) {
|
||||
|
@ -1502,7 +1508,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
timer = vAPI.setTimeout(( ) => {
|
||||
timer = undefined;
|
||||
next = 0;
|
||||
this.assets.updateStart({
|
||||
io.updateStart({
|
||||
delay: this.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 ||
|
||||
120000,
|
||||
auto: true,
|
||||
|
@ -1513,7 +1519,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.assetObserver = function(topic, details) {
|
||||
µb.assetObserver = function(topic, details) {
|
||||
// Do not update filter list if not in use.
|
||||
// Also, ignore really bad lists, i.e. those which should not even be
|
||||
// fetched from a remote server.
|
||||
|
@ -1544,7 +1550,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
details.content
|
||||
);
|
||||
if ( this.badLists.has(details.assetKey) === false ) {
|
||||
this.assets.put(
|
||||
io.put(
|
||||
'compiled/' + details.assetKey,
|
||||
this.compileFilters(details.content, {
|
||||
assetKey: details.assetKey
|
||||
|
@ -1592,7 +1598,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
this.hiddenSettings.userResourcesLocation !== 'unset' ||
|
||||
vAPI.webextFlavor.soup.has('devbuild')
|
||||
) {
|
||||
this.redirectEngine.invalidateResourcesSelfie();
|
||||
redirectEngine.invalidateResourcesSelfie();
|
||||
}
|
||||
this.loadFilterLists();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import contextMenu from './contextmenu.js';
|
||||
import logger from './logger.js';
|
||||
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { PageStore } from './pagestore.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
import { sessionSwitches } from './hnswitches.js';
|
||||
import { sessionURLFiltering } from './url-net-filtering.js';
|
||||
|
||||
import {
|
||||
domainFromHostname,
|
||||
hostnameFromURI,
|
||||
|
@ -30,8 +40,6 @@ import {
|
|||
originFromURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
@ -44,7 +52,7 @@ import µBlock from './background.js';
|
|||
// hostname. This way, for a specific scheme you can create scope with
|
||||
// rules which will apply only to that scheme.
|
||||
|
||||
µBlock.normalizeTabURL = (( ) => {
|
||||
µb.normalizeTabURL = (( ) => {
|
||||
const tabURLNormalizer = new URL('about:blank');
|
||||
|
||||
return (tabId, tabURL) => {
|
||||
|
@ -93,9 +101,7 @@ import µBlock from './background.js';
|
|||
// c: close opener
|
||||
// d: close target
|
||||
|
||||
µBlock.onPopupUpdated = (( ) => {
|
||||
const µb = µBlock;
|
||||
|
||||
const onPopupUpdated = (( ) => {
|
||||
// https://github.com/gorhill/uBlock/commit/1d448b85b2931412508aa01bf899e0b6f0033626#commitcomment-14944764
|
||||
// See if two URLs are different, disregarding scheme -- because the
|
||||
// scheme can be unilaterally changed by the browser.
|
||||
|
@ -162,13 +168,13 @@ import µBlock from './background.js';
|
|||
// popunders.
|
||||
if (
|
||||
popupType === 'popup' &&
|
||||
µb.sessionSwitches.evaluateZ(
|
||||
sessionSwitches.evaluateZ(
|
||||
'no-popups',
|
||||
fctxt.getTabHostname()
|
||||
)
|
||||
) {
|
||||
fctxt.filter = {
|
||||
raw: 'no-popups: ' + µb.sessionSwitches.z + ' true',
|
||||
raw: 'no-popups: ' + sessionSwitches.z + ' true',
|
||||
result: 1,
|
||||
source: 'switch'
|
||||
};
|
||||
|
@ -178,16 +184,16 @@ import µBlock from './background.js';
|
|||
// https://github.com/gorhill/uBlock/issues/581
|
||||
// Take into account popup-specific rules in dynamic URL
|
||||
// filtering, OR generic allow rules.
|
||||
let result = µb.sessionURLFiltering.evaluateZ(
|
||||
let result = sessionURLFiltering.evaluateZ(
|
||||
fctxt.getTabHostname(),
|
||||
targetURL,
|
||||
popupType
|
||||
);
|
||||
if (
|
||||
result === 1 && µb.sessionURLFiltering.type === popupType ||
|
||||
result === 1 && sessionURLFiltering.type === popupType ||
|
||||
result === 2
|
||||
) {
|
||||
fctxt.filter = µb.sessionURLFiltering.toLogData();
|
||||
fctxt.filter = sessionURLFiltering.toLogData();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -195,21 +201,21 @@ import µBlock from './background.js';
|
|||
// Take into account `allow` rules in dynamic filtering: `block`
|
||||
// rules are ignored, as block rules are not meant to block
|
||||
// specific types like `popup` (just like with static filters).
|
||||
result = µb.sessionFirewall.evaluateCellZY(
|
||||
result = sessionFirewall.evaluateCellZY(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.getHostname(),
|
||||
popupType
|
||||
);
|
||||
if ( result === 2 ) {
|
||||
fctxt.filter = µb.sessionFirewall.toLogData();
|
||||
fctxt.filter = sessionFirewall.toLogData();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
fctxt.type = popupType;
|
||||
const result = µb.staticNetFilteringEngine.matchRequest(fctxt, 0b0001);
|
||||
const result = staticNetFilteringEngine.matchRequest(fctxt, 0b0001);
|
||||
if ( result !== 0 ) {
|
||||
fctxt.filter = µb.staticNetFilteringEngine.toLogData();
|
||||
fctxt.filter = staticNetFilteringEngine.toLogData();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -225,11 +231,11 @@ import µBlock from './background.js';
|
|||
if (
|
||||
fctxt.filter === undefined ||
|
||||
fctxt.filter !== 'static' ||
|
||||
fctxt.filter.token === µb.staticNetFilteringEngine.noTokenHash
|
||||
fctxt.filter.token === staticNetFilteringEngine.noTokenHash
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
if ( fctxt.filter.token === µb.staticNetFilteringEngine.dotTokenHash ) {
|
||||
if ( fctxt.filter.token === staticNetFilteringEngine.dotTokenHash ) {
|
||||
return result;
|
||||
}
|
||||
const re = new RegExp(fctxt.filter.regex, 'i');
|
||||
|
@ -357,7 +363,7 @@ import µBlock from './background.js';
|
|||
|
||||
// Log only for when there was a hit against an actual filter (allow or block).
|
||||
// https://github.com/gorhill/uBlock/issues/2776
|
||||
if ( µb.logger.enabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').setType(popupType);
|
||||
if ( popupType === 'popup' ) {
|
||||
fctxt.setURL(targetURL)
|
||||
|
@ -463,8 +469,7 @@ housekeep itself.
|
|||
|
||||
*/
|
||||
|
||||
µBlock.tabContextManager = (( ) => {
|
||||
const µb = µBlock;
|
||||
µb.tabContextManager = (( ) => {
|
||||
const tabContexts = new Map();
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1001
|
||||
|
@ -524,7 +529,7 @@ housekeep itself.
|
|||
if ( targetTabId === candidate.opener.tabId ) {
|
||||
candidate.opener.popunder = true;
|
||||
}
|
||||
const result = await µb.onPopupUpdated(tabId, candidate.opener);
|
||||
const result = onPopupUpdated(tabId, candidate.opener);
|
||||
if ( result === true ) {
|
||||
candidate.destroy();
|
||||
} else {
|
||||
|
@ -864,20 +869,20 @@ vAPI.Tabs = class extends vAPI.Tabs {
|
|||
super.onActivated(details);
|
||||
if ( vAPI.isBehindTheSceneTabId(details.tabId) ) { return; }
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/680
|
||||
µBlock.updateToolbarIcon(details.tabId);
|
||||
µBlock.contextMenu.update(details.tabId);
|
||||
µb.updateToolbarIcon(details.tabId);
|
||||
contextMenu.update(details.tabId);
|
||||
}
|
||||
|
||||
onClosed(tabId) {
|
||||
super.onClosed(tabId);
|
||||
if ( vAPI.isBehindTheSceneTabId(tabId) ) { return; }
|
||||
µBlock.unbindTabFromPageStore(tabId);
|
||||
µBlock.contextMenu.update();
|
||||
µb.unbindTabFromPageStore(tabId);
|
||||
contextMenu.update();
|
||||
}
|
||||
|
||||
onCreated(details) {
|
||||
super.onCreated(details);
|
||||
µBlock.tabContextManager.onTabCreated(details);
|
||||
µb.tabContextManager.onTabCreated(details);
|
||||
}
|
||||
|
||||
// When the DOM content of root frame is loaded, this means the tab
|
||||
|
@ -895,7 +900,6 @@ vAPI.Tabs = class extends vAPI.Tabs {
|
|||
// is not available at this point.
|
||||
onNavigation(details) {
|
||||
super.onNavigation(details);
|
||||
const µb = µBlock;
|
||||
const { frameId, tabId, url } = details;
|
||||
if ( frameId === 0 ) {
|
||||
µb.tabContextManager.commit(tabId, url);
|
||||
|
@ -912,7 +916,7 @@ vAPI.Tabs = class extends vAPI.Tabs {
|
|||
isNetworkURI(url) &&
|
||||
pageStore.getNetFilteringSwitch()
|
||||
) {
|
||||
µb.scriptletFilteringEngine.injectNow(details);
|
||||
scriptletFilteringEngine.injectNow(details);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -924,8 +928,8 @@ vAPI.Tabs = class extends vAPI.Tabs {
|
|||
super.onUpdated(tabId, changeInfo, tab);
|
||||
if ( !tab.url || tab.url === '' ) { return; }
|
||||
if ( !changeInfo.url ) { return; }
|
||||
µBlock.tabContextManager.commit(tabId, changeInfo.url);
|
||||
µBlock.bindTabToPageStore(tabId, 'tabUpdated', tab);
|
||||
µb.tabContextManager.commit(tabId, changeInfo.url);
|
||||
µb.bindTabToPageStore(tabId, 'tabUpdated', tab);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -936,7 +940,7 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
// Create an entry for the tab if it doesn't exist.
|
||||
|
||||
µBlock.bindTabToPageStore = function(tabId, context, details = undefined) {
|
||||
µb.bindTabToPageStore = function(tabId, context, details = undefined) {
|
||||
this.updateToolbarIcon(tabId, 0b111);
|
||||
|
||||
// Do not create a page store for URLs which are of no interests
|
||||
|
@ -950,7 +954,7 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
// Tab is not bound
|
||||
if ( pageStore === undefined ) {
|
||||
pageStore = this.PageStore.factory(tabId, details);
|
||||
pageStore = PageStore.factory(tabId, details);
|
||||
this.pageStores.set(tabId, pageStore);
|
||||
this.pageStoresToken = Date.now();
|
||||
return pageStore;
|
||||
|
@ -981,7 +985,7 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.unbindTabFromPageStore = function(tabId) {
|
||||
µb.unbindTabFromPageStore = function(tabId) {
|
||||
const pageStore = this.pageStores.get(tabId);
|
||||
if ( pageStore === undefined ) { return; }
|
||||
pageStore.dispose();
|
||||
|
@ -991,11 +995,11 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.pageStoreFromTabId = function(tabId) {
|
||||
µb.pageStoreFromTabId = function(tabId) {
|
||||
return this.pageStores.get(tabId) || null;
|
||||
};
|
||||
|
||||
µBlock.mustPageStoreFromTabId = function(tabId) {
|
||||
µb.mustPageStoreFromTabId = function(tabId) {
|
||||
return this.pageStores.get(tabId) || this.pageStores.get(vAPI.noTabId);
|
||||
};
|
||||
|
||||
|
@ -1008,19 +1012,19 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
// the document context (if present) of the network request.
|
||||
|
||||
{
|
||||
const NoPageStore = class extends µBlock.PageStore {
|
||||
const NoPageStore = class extends PageStore {
|
||||
getNetFilteringSwitch(fctxt) {
|
||||
if ( fctxt ) {
|
||||
const docOrigin = fctxt.getDocOrigin();
|
||||
if ( docOrigin ) {
|
||||
return µBlock.getNetFilteringSwitch(docOrigin);
|
||||
return µb.getNetFilteringSwitch(docOrigin);
|
||||
}
|
||||
}
|
||||
return super.getNetFilteringSwitch();
|
||||
}
|
||||
};
|
||||
const pageStore = new NoPageStore(vAPI.noTabId);
|
||||
µBlock.pageStores.set(pageStore.tabId, pageStore);
|
||||
µb.pageStores.set(pageStore.tabId, pageStore);
|
||||
pageStore.title = vAPI.i18n('logBehindTheScene');
|
||||
}
|
||||
|
||||
|
@ -1028,8 +1032,7 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
|
||||
// Update visual of extension icon.
|
||||
|
||||
µBlock.updateToolbarIcon = (( ) => {
|
||||
const µb = µBlock;
|
||||
µb.updateToolbarIcon = (( ) => {
|
||||
const tabIdToDetails = new Map();
|
||||
|
||||
const computeBadgeColor = (bits) => {
|
||||
|
@ -1118,11 +1121,11 @@ vAPI.tabs = new vAPI.Tabs();
|
|||
const checkTab = async tabId => {
|
||||
const tab = await vAPI.tabs.get(tabId);
|
||||
if ( tab instanceof Object && tab.discarded !== true ) { return; }
|
||||
µBlock.unbindTabFromPageStore(tabId);
|
||||
µb.unbindTabFromPageStore(tabId);
|
||||
};
|
||||
|
||||
const pageStoreJanitor = function() {
|
||||
const tabIds = Array.from(µBlock.pageStores.keys()).sort();
|
||||
const tabIds = Array.from(µb.pageStores.keys()).sort();
|
||||
if ( pageStoreJanitorSampleAt >= tabIds.length ) {
|
||||
pageStoreJanitorSampleAt = 0;
|
||||
}
|
||||
|
|
|
@ -23,17 +23,17 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µBlock from './background.js';
|
||||
import µb from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.textEncode = (function() {
|
||||
const textEncode = (( ) => {
|
||||
|
||||
if ( µBlock.canFilterResponseData !== true ) { return; }
|
||||
if ( µb.canFilterResponseData !== true ) { return; }
|
||||
|
||||
// charset aliases extracted from:
|
||||
// https://github.com/inexorabletash/text-encoding/blob/b4e5bc26e26e51f56e3daa9f13138c79f49d3c34/lib/encoding.js#L342
|
||||
var normalizedCharset = new Map([
|
||||
const normalizedCharset = new Map([
|
||||
[ 'utf8', 'utf-8' ],
|
||||
[ 'unicode-1-1-utf-8', 'utf-8' ],
|
||||
[ 'utf-8', 'utf-8' ],
|
||||
|
@ -66,7 +66,7 @@ import µBlock from './background.js';
|
|||
]);
|
||||
|
||||
// http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1250.TXT
|
||||
var cp1250_range0 = new Uint8Array([
|
||||
const cp1250_range0 = new Uint8Array([
|
||||
/* 0x0100 */ 0x00, 0x00, 0xC3, 0xE3, 0xA5, 0xB9, 0xC6, 0xE6,
|
||||
/* 0x0108 */ 0x00, 0x00, 0x00, 0x00, 0xC8, 0xE8, 0xCF, 0xEF,
|
||||
/* 0x0110 */ 0xD0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -86,7 +86,7 @@ import µBlock from './background.js';
|
|||
]);
|
||||
|
||||
// http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT
|
||||
var cp1251_range0 = new Uint8Array([
|
||||
const cp1251_range0 = new Uint8Array([
|
||||
/* 0x0400 */ 0x00, 0xA8, 0x80, 0x81, 0xAA, 0xBD, 0xB2, 0xAF,
|
||||
/* 0x0408 */ 0xA3, 0x8A, 0x8C, 0x8E, 0x8D, 0x00, 0xA1, 0x8F,
|
||||
/* 0x0410 */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
|
||||
|
@ -109,7 +109,7 @@ import µBlock from './background.js';
|
|||
]);
|
||||
|
||||
// https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
|
||||
var cp1252_range0 = new Uint8Array([
|
||||
const cp1252_range0 = new Uint8Array([
|
||||
/* 0x0150 */ 0x00, 0x00, 0x8C, 0x9C, 0x00, 0x00, 0x00, 0x00,
|
||||
/* 0x0158 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* 0x0160 */ 0x8A, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -118,7 +118,7 @@ import µBlock from './background.js';
|
|||
/* 0x0178 */ 0x9F, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x9E, 0x00
|
||||
]);
|
||||
|
||||
var cp125x_range0 = new Uint8Array([
|
||||
const cp125x_range0 = new Uint8Array([
|
||||
/* 0x2010 */ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00,
|
||||
/* 0x2018 */ 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00,
|
||||
/* 0x2020 */ 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00,
|
||||
|
@ -127,9 +127,9 @@ import µBlock from './background.js';
|
|||
/* 0x2038 */ 0x00, 0x8B, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
]);
|
||||
|
||||
var encoders = {
|
||||
const encoders = {
|
||||
'windows-1250': function(buf) {
|
||||
var i = 0, n = buf.byteLength, o = 0, c;
|
||||
let i = 0, n = buf.byteLength, o = 0, c;
|
||||
while ( i < n ) {
|
||||
c = buf[i++];
|
||||
if ( c < 0x80 ) {
|
||||
|
@ -174,7 +174,7 @@ import µBlock from './background.js';
|
|||
return buf.slice(0, o);
|
||||
},
|
||||
'windows-1251': function(buf) {
|
||||
var i = 0, n = buf.byteLength, o = 0, c;
|
||||
let i = 0, n = buf.byteLength, o = 0, c;
|
||||
while ( i < n ) {
|
||||
c = buf[i++];
|
||||
if ( c < 0x80 ) {
|
||||
|
@ -211,7 +211,7 @@ import µBlock from './background.js';
|
|||
return buf.slice(0, o);
|
||||
},
|
||||
'windows-1252': function(buf) {
|
||||
var i = 0, n = buf.byteLength, o = 0, c;
|
||||
let i = 0, n = buf.byteLength, o = 0, c;
|
||||
while ( i < n ) {
|
||||
c = buf[i++];
|
||||
if ( c < 0x80 ) {
|
||||
|
@ -267,3 +267,9 @@ import µBlock from './background.js';
|
|||
}
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export default textEncode;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,13 +23,22 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import htmlFilteringEngine from './html-filtering.js';
|
||||
import httpheaderFilteringEngine from './httpheader-filtering.js';
|
||||
import logger from './logger.js';
|
||||
import scriptletFilteringEngine from './scriptlet-filtering.js';
|
||||
import staticNetFilteringEngine from './static-net-filtering.js';
|
||||
import textEncode from './text-encode.js';
|
||||
import µb from './background.js';
|
||||
import { sessionFirewall } from './dynamic-net-filtering.js';
|
||||
import { sessionSwitches } from './hnswitches.js';
|
||||
import { sessionURLFiltering } from './url-net-filtering.js';
|
||||
|
||||
import {
|
||||
entityFromDomain,
|
||||
isNetworkURI,
|
||||
} from './uri-utils.js';
|
||||
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Platform-specific behavior.
|
||||
|
@ -55,7 +64,7 @@ const supportsFloc = document.interestCohort instanceof Function;
|
|||
// Intercept and filter web requests.
|
||||
|
||||
const onBeforeRequest = function(details) {
|
||||
const fctxt = µBlock.filteringContext.fromWebrequestDetails(details);
|
||||
const fctxt = µb.filteringContext.fromWebrequestDetails(details);
|
||||
|
||||
// Special handling for root document.
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1001
|
||||
|
@ -72,7 +81,6 @@ const onBeforeRequest = function(details) {
|
|||
}
|
||||
|
||||
// Lookup the page store associated with this tab id.
|
||||
const µb = µBlock;
|
||||
let pageStore = µb.pageStoreFromTabId(tabId);
|
||||
if ( pageStore === null ) {
|
||||
const tabContext = µb.tabContextManager.mustLookup(tabId);
|
||||
|
@ -87,7 +95,7 @@ const onBeforeRequest = function(details) {
|
|||
|
||||
pageStore.journalAddRequest(fctxt, result);
|
||||
|
||||
if ( µb.logger.enabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
|
||||
|
@ -121,7 +129,6 @@ const onBeforeRequest = function(details) {
|
|||
/******************************************************************************/
|
||||
|
||||
const onBeforeRootFrameRequest = function(fctxt) {
|
||||
const µb = µBlock;
|
||||
const requestURL = fctxt.url;
|
||||
|
||||
// Special handling for root document.
|
||||
|
@ -129,7 +136,6 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
// This must be executed regardless of whether the request is
|
||||
// behind-the-scene
|
||||
const requestHostname = fctxt.getHostname();
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
let result = 0;
|
||||
let logData;
|
||||
|
||||
|
@ -137,7 +143,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
const trusted = µb.getNetFilteringSwitch(requestURL) === false;
|
||||
if ( trusted ) {
|
||||
result = 2;
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logData = { engine: 'u', result: 2, raw: 'whitelisted' };
|
||||
}
|
||||
}
|
||||
|
@ -145,14 +151,14 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
// Permanently unrestricted?
|
||||
if (
|
||||
result === 0 &&
|
||||
µb.sessionSwitches.evaluateZ('no-strict-blocking', requestHostname)
|
||||
sessionSwitches.evaluateZ('no-strict-blocking', requestHostname)
|
||||
) {
|
||||
result = 2;
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logData = {
|
||||
engine: 'u',
|
||||
result: 2,
|
||||
raw: `no-strict-blocking: ${µb.sessionSwitches.z} true`
|
||||
raw: `no-strict-blocking: ${sessionSwitches.z} true`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +166,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
// Temporarily whitelisted?
|
||||
if ( result === 0 && strictBlockBypasser.isBypassed(requestHostname) ) {
|
||||
result = 2;
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
logData = {
|
||||
engine: 'u',
|
||||
result: 2,
|
||||
|
@ -171,7 +177,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
|
||||
// Static filtering
|
||||
if ( result === 0 ) {
|
||||
({ result, logData } = shouldStrictBlock(fctxt, loggerEnabled));
|
||||
({ result, logData } = shouldStrictBlock(fctxt, logger.enabled));
|
||||
}
|
||||
|
||||
const pageStore = µb.bindTabToPageStore(fctxt.tabId, 'beforeRequest');
|
||||
|
@ -180,7 +186,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
pageStore.journalAddRequest(fctxt, result);
|
||||
}
|
||||
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setFilter(logData);
|
||||
}
|
||||
|
||||
|
@ -190,12 +196,12 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
result !== 1 &&
|
||||
trusted === false &&
|
||||
pageStore !== null &&
|
||||
µb.staticNetFilteringEngine.hasQuery(fctxt)
|
||||
staticNetFilteringEngine.hasQuery(fctxt)
|
||||
) {
|
||||
pageStore.redirectNonBlockedRequest(fctxt);
|
||||
}
|
||||
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
|
||||
|
@ -259,8 +265,7 @@ const onBeforeRootFrameRequest = function(fctxt) {
|
|||
// --------+--------+--------+--------+--------+--------+
|
||||
|
||||
const shouldStrictBlock = function(fctxt, loggerEnabled) {
|
||||
const µb = µBlock;
|
||||
const snfe = µb.staticNetFilteringEngine;
|
||||
const snfe = staticNetFilteringEngine;
|
||||
|
||||
// Explicit filtering: `document` option
|
||||
const rs = snfe.matchRequest(fctxt, 0b0011);
|
||||
|
@ -358,7 +363,6 @@ const validateStrictBlock = function(fctxt, logData) {
|
|||
// Intercept and filter behind-the-scene requests.
|
||||
|
||||
const onBeforeBehindTheSceneRequest = function(fctxt) {
|
||||
const µb = µBlock;
|
||||
const pageStore = µb.pageStoreFromTabId(fctxt.tabId);
|
||||
if ( pageStore === null ) { return; }
|
||||
|
||||
|
@ -403,7 +407,7 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
|
|||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1204
|
||||
onBeforeBehindTheSceneRequest.journalAddRequest(fctxt, result);
|
||||
|
||||
if ( µb.logger.enabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
|
||||
|
@ -440,7 +444,7 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
|
|||
|
||||
const gc = ( ) => {
|
||||
gcTimer = undefined;
|
||||
if ( pageStoresToken !== µBlock.pageStoresToken ) { return reset(); }
|
||||
if ( pageStoresToken !== µb.pageStoresToken ) { return reset(); }
|
||||
gcTimer = vAPI.setTimeout(gc, 30011);
|
||||
};
|
||||
|
||||
|
@ -448,15 +452,15 @@ const onBeforeBehindTheSceneRequest = function(fctxt) {
|
|||
const docHostname = fctxt.getDocHostname();
|
||||
if (
|
||||
docHostname !== hostname ||
|
||||
pageStoresToken !== µBlock.pageStoresToken
|
||||
pageStoresToken !== µb.pageStoresToken
|
||||
) {
|
||||
hostname = docHostname;
|
||||
pageStores = new Set();
|
||||
for ( const pageStore of µBlock.pageStores.values() ) {
|
||||
for ( const pageStore of µb.pageStores.values() ) {
|
||||
if ( pageStore.tabHostname !== docHostname ) { continue; }
|
||||
pageStores.add(pageStore);
|
||||
}
|
||||
pageStoresToken = µBlock.pageStoresToken;
|
||||
pageStoresToken = µb.pageStoresToken;
|
||||
if ( gcTimer !== undefined ) {
|
||||
clearTimeout(gcTimer);
|
||||
}
|
||||
|
@ -486,7 +490,6 @@ const onHeadersReceived = function(details) {
|
|||
return;
|
||||
}
|
||||
|
||||
const µb = µBlock;
|
||||
const fctxt = µb.filteringContext.fromWebrequestDetails(details);
|
||||
const isRootDoc = fctxt.itype === fctxt.MAIN_FRAME;
|
||||
|
||||
|
@ -511,7 +514,7 @@ const onHeadersReceived = function(details) {
|
|||
if ( isRootDoc === false && µb.hiddenSettings.filterOnHeaders === true ) {
|
||||
const result = pageStore.filterOnHeaders(fctxt, responseHeaders);
|
||||
if ( result !== 0 ) {
|
||||
if ( µb.logger.enabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
if ( result === 1 ) {
|
||||
|
@ -542,7 +545,7 @@ const onHeadersReceived = function(details) {
|
|||
µb.canFilterResponseData && filterDocument(fctxt, details) === true;
|
||||
|
||||
let modifiedHeaders = false;
|
||||
if ( µb.httpheaderFilteringEngine.apply(fctxt, responseHeaders) === true ) {
|
||||
if ( httpheaderFilteringEngine.apply(fctxt, responseHeaders) === true ) {
|
||||
modifiedHeaders = true;
|
||||
}
|
||||
if ( injectCSP(fctxt, pageStore, responseHeaders) === true ) {
|
||||
|
@ -622,7 +625,6 @@ const normalizeBehindTheSceneResponseHeaders = function(details) {
|
|||
**/
|
||||
|
||||
const filterDocument = (( ) => {
|
||||
const µb = µBlock;
|
||||
const filterers = new Map();
|
||||
let domParser, xmlSerializer,
|
||||
utf8TextDecoder, textDecoder, textEncoder;
|
||||
|
@ -749,7 +751,7 @@ const filterDocument = (( ) => {
|
|||
filterer.mime
|
||||
);
|
||||
charsetFound = charsetFromDoc(doc);
|
||||
charsetUsed = µb.textEncode.normalizeCharset(charsetFound);
|
||||
charsetUsed = textEncode.normalizeCharset(charsetFound);
|
||||
if ( charsetUsed === undefined ) {
|
||||
return streamClose(filterer);
|
||||
}
|
||||
|
@ -764,7 +766,7 @@ const filterDocument = (( ) => {
|
|||
// In case of no explicit charset found, try to find one again, but
|
||||
// this time with the whole document parsed.
|
||||
if ( charsetFound === undefined ) {
|
||||
charsetFound = µb.textEncode.normalizeCharset(charsetFromDoc(doc));
|
||||
charsetFound = textEncode.normalizeCharset(charsetFromDoc(doc));
|
||||
if ( charsetFound !== charsetUsed ) {
|
||||
if ( charsetFound === undefined ) {
|
||||
return streamClose(filterer);
|
||||
|
@ -779,7 +781,7 @@ const filterDocument = (( ) => {
|
|||
|
||||
let modified = false;
|
||||
if ( filterer.selectors !== undefined ) {
|
||||
if ( µb.htmlFilteringEngine.apply(doc, filterer) ) {
|
||||
if ( htmlFilteringEngine.apply(doc, filterer) ) {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
@ -799,7 +801,7 @@ const filterDocument = (( ) => {
|
|||
doc.documentElement.outerHTML
|
||||
);
|
||||
if ( charsetUsed !== 'utf-8' ) {
|
||||
encodedStream = µb.textEncode.encode(
|
||||
encodedStream = textEncode.encode(
|
||||
charsetUsed,
|
||||
encodedStream
|
||||
);
|
||||
|
@ -837,7 +839,7 @@ const filterDocument = (( ) => {
|
|||
charset: undefined
|
||||
};
|
||||
|
||||
request.selectors = µb.htmlFilteringEngine.retrieve(request);
|
||||
request.selectors = htmlFilteringEngine.retrieve(request);
|
||||
if ( request.selectors === undefined ) { return; }
|
||||
|
||||
const headers = extras.responseHeaders;
|
||||
|
@ -847,7 +849,7 @@ const filterDocument = (( ) => {
|
|||
if ( request.mime === undefined ) { return; }
|
||||
let charset = charsetFromContentType(contentType);
|
||||
if ( charset !== undefined ) {
|
||||
charset = µb.textEncode.normalizeCharset(charset);
|
||||
charset = textEncode.normalizeCharset(charset);
|
||||
if ( charset === undefined ) { return; }
|
||||
request.charset = charset;
|
||||
}
|
||||
|
@ -869,8 +871,6 @@ const filterDocument = (( ) => {
|
|||
/******************************************************************************/
|
||||
|
||||
const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
||||
const µb = µBlock;
|
||||
const loggerEnabled = µb.logger.enabled;
|
||||
const cspSubsets = [];
|
||||
const requestType = fctxt.type;
|
||||
|
||||
|
@ -881,8 +881,8 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
const builtinDirectives = [];
|
||||
|
||||
if ( pageStore.filterScripting(fctxt, true) === 1 ) {
|
||||
builtinDirectives.push(µBlock.cspNoScripting);
|
||||
if ( loggerEnabled ) {
|
||||
builtinDirectives.push(µb.cspNoScripting);
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').setType('scripting').toLogger();
|
||||
}
|
||||
}
|
||||
|
@ -896,9 +896,9 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
fctxt2.setDocOriginFromURL(fctxt.url);
|
||||
const result = pageStore.filterRequest(fctxt2);
|
||||
if ( result === 1 ) {
|
||||
builtinDirectives.push(µBlock.cspNoInlineScript);
|
||||
builtinDirectives.push(µb.cspNoInlineScript);
|
||||
}
|
||||
if ( result === 2 && loggerEnabled ) {
|
||||
if ( result === 2 && logger.enabled ) {
|
||||
fctxt2.setRealm('network').toLogger();
|
||||
}
|
||||
}
|
||||
|
@ -907,8 +907,8 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
// - Use a CSP to also forbid inline fonts if remote fonts are blocked.
|
||||
fctxt.type = 'inline-font';
|
||||
if ( pageStore.filterRequest(fctxt) === 1 ) {
|
||||
builtinDirectives.push(µBlock.cspNoInlineFont);
|
||||
if ( loggerEnabled ) {
|
||||
builtinDirectives.push(µb.cspNoInlineFont);
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
}
|
||||
|
@ -923,7 +923,7 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
|
||||
fctxt.type = requestType;
|
||||
const staticDirectives =
|
||||
µb.staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp');
|
||||
staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'csp');
|
||||
if ( staticDirectives !== undefined ) {
|
||||
for ( const directive of staticDirectives ) {
|
||||
if ( directive.result !== 1 ) { continue; }
|
||||
|
@ -934,16 +934,16 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
// URL filtering `allow` rules override static filtering.
|
||||
if (
|
||||
cspSubsets.length !== 0 &&
|
||||
µb.sessionURLFiltering.evaluateZ(
|
||||
sessionURLFiltering.evaluateZ(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.url,
|
||||
'csp'
|
||||
) === 2
|
||||
) {
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network')
|
||||
.setType('csp')
|
||||
.setFilter(µb.sessionURLFiltering.toLogData())
|
||||
.setFilter(sessionURLFiltering.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
return;
|
||||
|
@ -953,16 +953,16 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
if (
|
||||
cspSubsets.length !== 0 &&
|
||||
µb.userSettings.advancedUserEnabled &&
|
||||
µb.sessionFirewall.evaluateCellZY(
|
||||
sessionFirewall.evaluateCellZY(
|
||||
fctxt.getTabHostname(),
|
||||
fctxt.getTabHostname(),
|
||||
'*'
|
||||
) === 2
|
||||
) {
|
||||
if ( loggerEnabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network')
|
||||
.setType('csp')
|
||||
.setFilter(µb.sessionFirewall.toLogData())
|
||||
.setFilter(sessionFirewall.toLogData())
|
||||
.toLogger();
|
||||
}
|
||||
return;
|
||||
|
@ -972,7 +972,7 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
|
||||
// Static CSP policies will be applied.
|
||||
|
||||
if ( loggerEnabled && staticDirectives !== undefined ) {
|
||||
if ( logger.enabled && staticDirectives !== undefined ) {
|
||||
fctxt.setRealm('network')
|
||||
.pushFilters(staticDirectives.map(a => a.logData()))
|
||||
.toLogger();
|
||||
|
@ -1006,7 +1006,7 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
|
|||
|
||||
const foilFloc = function(fctxt, responseHeaders) {
|
||||
const hn = fctxt.getHostname();
|
||||
if ( µBlock.scriptletFilteringEngine.hasScriptlet(hn, 1, 'no-floc') === false ) {
|
||||
if ( scriptletFilteringEngine.hasScriptlet(hn, 1, 'no-floc') === false ) {
|
||||
return false;
|
||||
}
|
||||
responseHeaders.push({
|
||||
|
@ -1029,7 +1029,7 @@ const foilLargeMediaElement = function(details, fctxt, pageStore) {
|
|||
if ( details.fromCache === true ) { return; }
|
||||
|
||||
let size = 0;
|
||||
if ( µBlock.userSettings.largeMediaSize !== 0 ) {
|
||||
if ( µb.userSettings.largeMediaSize !== 0 ) {
|
||||
const headers = details.responseHeaders;
|
||||
const i = headerIndexFromName('content-length', headers);
|
||||
if ( i === -1 ) { return; }
|
||||
|
@ -1039,7 +1039,7 @@ const foilLargeMediaElement = function(details, fctxt, pageStore) {
|
|||
const result = pageStore.filterLargeMediaElement(fctxt, size);
|
||||
if ( result === 0 ) { return; }
|
||||
|
||||
if ( µBlock.logger.enabled ) {
|
||||
if ( logger.enabled ) {
|
||||
fctxt.setRealm('network').toLogger();
|
||||
}
|
||||
|
||||
|
@ -1083,14 +1083,14 @@ const strictBlockBypasser = {
|
|||
if ( typeof hostname !== 'string' || hostname === '' ) { return; }
|
||||
this.hostnameToDeadlineMap.set(
|
||||
hostname,
|
||||
Date.now() + µBlock.hiddenSettings.strictBlockingBypassDuration * 1000
|
||||
Date.now() + µb.hiddenSettings.strictBlockingBypassDuration * 1000
|
||||
);
|
||||
},
|
||||
|
||||
isBypassed: function(hostname) {
|
||||
if ( this.hostnameToDeadlineMap.size === 0 ) { return false; }
|
||||
let bypassDuration =
|
||||
µBlock.hiddenSettings.strictBlockingBypassDuration * 1000;
|
||||
µb.hiddenSettings.strictBlockingBypassDuration * 1000;
|
||||
if ( this.cleanupTimer === undefined ) {
|
||||
this.cleanupTimer = vAPI.setTimeout(
|
||||
( ) => {
|
||||
|
@ -1122,9 +1122,7 @@ const strictBlockBypasser = {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
|
||||
µBlock.webRequest = {
|
||||
const webRequest = {
|
||||
start: (( ) => {
|
||||
vAPI.net = new vAPI.Net();
|
||||
vAPI.net.suspend();
|
||||
|
@ -1147,3 +1145,7 @@ const strictBlockBypasser = {
|
|||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
export { webRequest };
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
109
src/js/ublock.js
109
src/js/ublock.js
|
@ -23,8 +23,26 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import contextMenu from './contextmenu.js';
|
||||
import cosmeticFilteringEngine from './cosmetic-filtering.js';
|
||||
import µb from './background.js';
|
||||
import { hostnameFromURI } from './uri-utils.js';
|
||||
import µBlock from './background.js';
|
||||
import { redirectEngine } from './redirect-engine.js';
|
||||
|
||||
import {
|
||||
permanentFirewall,
|
||||
sessionFirewall,
|
||||
} from './dynamic-net-filtering.js';
|
||||
|
||||
import {
|
||||
permanentSwitches,
|
||||
sessionSwitches,
|
||||
} from './hnswitches.js';
|
||||
|
||||
import {
|
||||
permanentURLFiltering,
|
||||
sessionURLFiltering,
|
||||
} from './url-net-filtering.js';
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
@ -90,7 +108,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.getNetFilteringSwitch = function(url) {
|
||||
µb.getNetFilteringSwitch = function(url) {
|
||||
const hostname = hostnameFromURI(url);
|
||||
let key = hostname;
|
||||
for (;;) {
|
||||
|
@ -109,7 +127,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.toggleNetFilteringSwitch = function(url, scope, newState) {
|
||||
µb.toggleNetFilteringSwitch = function(url, scope, newState) {
|
||||
const currentState = this.getNetFilteringSwitch(url);
|
||||
if ( newState === undefined ) {
|
||||
newState = !currentState;
|
||||
|
@ -179,7 +197,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.arrayFromWhitelist = function(whitelist) {
|
||||
µb.arrayFromWhitelist = function(whitelist) {
|
||||
const out = new Set();
|
||||
for ( const bucket of whitelist.values() ) {
|
||||
for ( const directive of bucket ) {
|
||||
|
@ -189,13 +207,13 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
return Array.from(out).sort((a, b) => a.localeCompare(b));
|
||||
};
|
||||
|
||||
µBlock.stringFromWhitelist = function(whitelist) {
|
||||
µb.stringFromWhitelist = function(whitelist) {
|
||||
return this.arrayFromWhitelist(whitelist).join('\n');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.whitelistFromArray = function(lines) {
|
||||
µb.whitelistFromArray = function(lines) {
|
||||
const whitelist = new Map();
|
||||
|
||||
// Comment bucket must always be ready to be used.
|
||||
|
@ -273,27 +291,27 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
return whitelist;
|
||||
};
|
||||
|
||||
µBlock.whitelistFromString = function(s) {
|
||||
µb.whitelistFromString = function(s) {
|
||||
return this.whitelistFromArray(s.split('\n'));
|
||||
};
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/3717
|
||||
µBlock.reWhitelistBadHostname = /[^a-z0-9.\-_\[\]:]/;
|
||||
µBlock.reWhitelistHostnameExtractor = /([a-z0-9.\-_\[\]]+)(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/;
|
||||
µb.reWhitelistBadHostname = /[^a-z0-9.\-_\[\]:]/;
|
||||
µb.reWhitelistHostnameExtractor = /([a-z0-9.\-_\[\]]+)(?::[\d*]+)?\/(?:[^\x00-\x20\/]|$)[^\x00-\x20]*$/;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.changeUserSettings = function(name, value) {
|
||||
µb.changeUserSettings = function(name, value) {
|
||||
let us = this.userSettings;
|
||||
|
||||
// Return all settings if none specified.
|
||||
if ( name === undefined ) {
|
||||
us = JSON.parse(JSON.stringify(us));
|
||||
us.noCosmeticFiltering = this.sessionSwitches.evaluate('no-cosmetic-filtering', '*') === 1;
|
||||
us.noLargeMedia = this.sessionSwitches.evaluate('no-large-media', '*') === 1;
|
||||
us.noRemoteFonts = this.sessionSwitches.evaluate('no-remote-fonts', '*') === 1;
|
||||
us.noScripting = this.sessionSwitches.evaluate('no-scripting', '*') === 1;
|
||||
us.noCSPReports = this.sessionSwitches.evaluate('no-csp-reports', '*') === 1;
|
||||
us.noCosmeticFiltering = sessionSwitches.evaluate('no-cosmetic-filtering', '*') === 1;
|
||||
us.noLargeMedia = sessionSwitches.evaluate('no-large-media', '*') === 1;
|
||||
us.noRemoteFonts = sessionSwitches.evaluate('no-remote-fonts', '*') === 1;
|
||||
us.noScripting = sessionSwitches.evaluate('no-scripting', '*') === 1;
|
||||
us.noCSPReports = sessionSwitches.evaluate('no-csp-reports', '*') === 1;
|
||||
return us;
|
||||
}
|
||||
|
||||
|
@ -338,11 +356,11 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
break;
|
||||
case 'collapseBlocked':
|
||||
if ( value === false ) {
|
||||
this.cosmeticFilteringEngine.removeFromSelectorCache('*', 'net');
|
||||
cosmeticFilteringEngine.removeFromSelectorCache('*', 'net');
|
||||
}
|
||||
break;
|
||||
case 'contextMenuEnabled':
|
||||
this.contextMenu.update(null);
|
||||
contextMenu.update(null);
|
||||
break;
|
||||
case 'hyperlinkAuditingDisabled':
|
||||
if ( this.privacySettingsSupported ) {
|
||||
|
@ -371,8 +389,8 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
}
|
||||
if ( switchName === undefined ) { break; }
|
||||
let switchState = value ? 1 : 0;
|
||||
this.sessionSwitches.toggle(switchName, '*', switchState);
|
||||
if ( this.permanentSwitches.toggle(switchName, '*', switchState) ) {
|
||||
sessionSwitches.toggle(switchName, '*', switchState);
|
||||
if ( permanentSwitches.toggle(switchName, '*', switchState) ) {
|
||||
this.saveHostnameSwitches();
|
||||
}
|
||||
break;
|
||||
|
@ -399,13 +417,13 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/8524cf/my_custom_scriptlets_doesnt_work_what_am_i_doing/
|
||||
|
||||
µBlock.changeHiddenSettings = function(hs) {
|
||||
µb.changeHiddenSettings = function(hs) {
|
||||
const mustReloadResources =
|
||||
hs.userResourcesLocation !== this.hiddenSettings.userResourcesLocation;
|
||||
this.hiddenSettings = hs;
|
||||
this.saveHiddenSettings();
|
||||
if ( mustReloadResources ) {
|
||||
this.redirectEngine.invalidateResourcesSelfie();
|
||||
redirectEngine.invalidateResourcesSelfie();
|
||||
this.loadRedirectResources();
|
||||
}
|
||||
this.fireDOMEvent('hiddenSettingsChanged');
|
||||
|
@ -413,7 +431,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.elementPickerExec = async function(
|
||||
µb.elementPickerExec = async function(
|
||||
tabId,
|
||||
frameId,
|
||||
targetElement,
|
||||
|
@ -451,18 +469,18 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
// Always set own rules, trying to be fancy to avoid setting seemingly
|
||||
// (but not really) redundant rules led to this issue.
|
||||
|
||||
µBlock.toggleFirewallRule = function(details) {
|
||||
µb.toggleFirewallRule = function(details) {
|
||||
let { srcHostname, desHostname, requestType, action } = details;
|
||||
|
||||
if ( action !== 0 ) {
|
||||
this.sessionFirewall.setCell(
|
||||
sessionFirewall.setCell(
|
||||
srcHostname,
|
||||
desHostname,
|
||||
requestType,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
this.sessionFirewall.unsetCell(
|
||||
sessionFirewall.unsetCell(
|
||||
srcHostname,
|
||||
desHostname,
|
||||
requestType
|
||||
|
@ -472,14 +490,14 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
// https://github.com/chrisaljoudi/uBlock/issues/731#issuecomment-73937469
|
||||
if ( details.persist ) {
|
||||
if ( action !== 0 ) {
|
||||
this.permanentFirewall.setCell(
|
||||
permanentFirewall.setCell(
|
||||
srcHostname,
|
||||
desHostname,
|
||||
requestType,
|
||||
action
|
||||
);
|
||||
} else {
|
||||
this.permanentFirewall.unsetCell(
|
||||
permanentFirewall.unsetCell(
|
||||
srcHostname,
|
||||
desHostname,
|
||||
requestType,
|
||||
|
@ -506,7 +524,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
}
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/420
|
||||
this.cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
|
||||
cosmeticFilteringEngine.removeFromSelectorCache(srcHostname, 'net');
|
||||
|
||||
if ( details.tabId === undefined ) { return; }
|
||||
|
||||
|
@ -525,8 +543,8 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.toggleURLFilteringRule = function(details) {
|
||||
let changed = this.sessionURLFiltering.setRule(
|
||||
µb.toggleURLFilteringRule = function(details) {
|
||||
let changed = sessionURLFiltering.setRule(
|
||||
details.context,
|
||||
details.url,
|
||||
details.type,
|
||||
|
@ -534,11 +552,11 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
);
|
||||
if ( changed === false ) { return; }
|
||||
|
||||
this.cosmeticFilteringEngine.removeFromSelectorCache(details.context, 'net');
|
||||
cosmeticFilteringEngine.removeFromSelectorCache(details.context, 'net');
|
||||
|
||||
if ( details.persist !== true ) { return; }
|
||||
|
||||
changed = this.permanentURLFiltering.setRule(
|
||||
changed = permanentURLFiltering.setRule(
|
||||
details.context,
|
||||
details.url,
|
||||
details.type,
|
||||
|
@ -552,8 +570,8 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.toggleHostnameSwitch = function(details) {
|
||||
let changed = this.sessionSwitches.toggleZ(
|
||||
µb.toggleHostnameSwitch = function(details) {
|
||||
let changed = sessionSwitches.toggleZ(
|
||||
details.name,
|
||||
details.hostname,
|
||||
!!details.deep,
|
||||
|
@ -582,7 +600,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
if ( details.persist !== true ) { return; }
|
||||
|
||||
changed = this.permanentSwitches.toggleZ(
|
||||
changed = permanentSwitches.toggleZ(
|
||||
details.name,
|
||||
details.hostname,
|
||||
!!details.deep,
|
||||
|
@ -595,29 +613,28 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.blockingModeFromHostname = function(hn) {
|
||||
µb.blockingModeFromHostname = function(hn) {
|
||||
let bits = 0;
|
||||
if ( this.sessionSwitches.evaluateZ('no-scripting', hn) ) {
|
||||
if ( sessionSwitches.evaluateZ('no-scripting', hn) ) {
|
||||
bits |= 0b00000010;
|
||||
}
|
||||
if ( this.userSettings.advancedUserEnabled ) {
|
||||
const fw = this.sessionFirewall;
|
||||
if ( fw.evaluateCellZY(hn, '*', '3p') === 1 ) {
|
||||
if ( sessionFirewall.evaluateCellZY(hn, '*', '3p') === 1 ) {
|
||||
bits |= 0b00000100;
|
||||
}
|
||||
if ( fw.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
|
||||
if ( sessionFirewall.evaluateCellZY(hn, '*', '3p-script') === 1 ) {
|
||||
bits |= 0b00001000;
|
||||
}
|
||||
if ( fw.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
|
||||
if ( sessionFirewall.evaluateCellZY(hn, '*', '3p-frame') === 1 ) {
|
||||
bits |= 0b00010000;
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
};
|
||||
|
||||
µBlock.parseBlockingProfiles = (( ) => {
|
||||
µb.parseBlockingProfiles = (( ) => {
|
||||
const parse = function() {
|
||||
const s = µBlock.hiddenSettings.blockingProfiles;
|
||||
const s = µb.hiddenSettings.blockingProfiles;
|
||||
const profiles = [];
|
||||
s.split(/\s+/).forEach(s => {
|
||||
let pos = s.indexOf('/');
|
||||
|
@ -629,8 +646,8 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
const color = s.slice(pos + 1);
|
||||
profiles.push({ bits, color: color !== '' ? color : '#666' });
|
||||
});
|
||||
µBlock.liveBlockingProfiles = profiles;
|
||||
µBlock.blockingProfileColorCache.clear();
|
||||
µb.liveBlockingProfiles = profiles;
|
||||
µb.blockingProfileColorCache.clear();
|
||||
};
|
||||
|
||||
parse();
|
||||
|
@ -642,7 +659,7 @@ const matchBucket = function(url, hostname, bucket, start) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.scriptlets = (function() {
|
||||
µb.scriptlets = (function() {
|
||||
const pendingEntries = new Map();
|
||||
|
||||
const Entry = class {
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import µb from './background.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import µBlock from './background.js';
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
@ -200,7 +200,7 @@ URLNetFiltering.prototype.evaluateZ = function(context, target, type) {
|
|||
if ( this.rules.size === 0 ) {
|
||||
return 0;
|
||||
}
|
||||
µBlock.decomposeHostname(context, this.decomposedSource);
|
||||
µb.decomposeHostname(context, this.decomposedSource);
|
||||
for ( let shn of this.decomposedSource ) {
|
||||
this.context = shn;
|
||||
let entries = this.rules.get(shn + ' ' + type);
|
||||
|
@ -370,11 +370,9 @@ URLNetFiltering.prototype.removeFromRuleParts = function(parts) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
// Export
|
||||
const sessionURLFiltering = new URLNetFiltering();
|
||||
const permanentURLFiltering = new URLNetFiltering();
|
||||
|
||||
µBlock.URLNetFiltering = URLNetFiltering;
|
||||
|
||||
µBlock.sessionURLFiltering = new URLNetFiltering();
|
||||
µBlock.permanentURLFiltering = new URLNetFiltering();
|
||||
export { permanentURLFiltering, sessionURLFiltering };
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -23,12 +23,13 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
import io from './assets.js';
|
||||
import µb from './background.js';
|
||||
import { LineIterator } from './text-iterators.js';
|
||||
import µBlock from './background.js';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.formatCount = function(count) {
|
||||
µb.formatCount = function(count) {
|
||||
if ( typeof count !== 'number' ) {
|
||||
return '';
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ import µBlock from './background.js';
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.dateNowToSensibleString = function() {
|
||||
µb.dateNowToSensibleString = function() {
|
||||
const now = new Date(Date.now() - (new Date()).getTimezoneOffset() * 60000);
|
||||
return now.toISOString().replace(/\.\d+Z$/, '')
|
||||
.replace(/:/g, '.')
|
||||
|
@ -62,7 +63,7 @@ import µBlock from './background.js';
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.openNewTab = function(details) {
|
||||
µb.openNewTab = function(details) {
|
||||
if ( details.url.startsWith('logger-ui.html') ) {
|
||||
if ( details.shiftKey ) {
|
||||
this.changeUserSettings(
|
||||
|
@ -92,7 +93,7 @@ import µBlock from './background.js';
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.MRUCache = class {
|
||||
µb.MRUCache = class {
|
||||
constructor(size) {
|
||||
this.size = size;
|
||||
this.array = [];
|
||||
|
@ -136,13 +137,13 @@ import µBlock from './background.js';
|
|||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
|
||||
µBlock.escapeRegex = function(s) {
|
||||
µb.escapeRegex = function(s) {
|
||||
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.decomposeHostname = (( ) => {
|
||||
µb.decomposeHostname = (( ) => {
|
||||
// For performance purpose, as simple tests as possible
|
||||
const reHostnameVeryCoarse = /[g-z_-]/;
|
||||
const reIPv4VeryCoarse = /\.\d+$/;
|
||||
|
@ -196,7 +197,7 @@ import µBlock from './background.js';
|
|||
|
||||
// TODO: evaluate using TextEncoder/TextDecoder
|
||||
|
||||
µBlock.orphanizeString = function(s) {
|
||||
µb.orphanizeString = function(s) {
|
||||
return JSON.parse(JSON.stringify(s));
|
||||
};
|
||||
|
||||
|
@ -217,10 +218,6 @@ import µBlock from './background.js';
|
|||
// From uBO's dev console, launch the benchmark:
|
||||
// µBlock.staticNetFilteringEngine.benchmark();
|
||||
//
|
||||
// The advanced setting `consoleLogLevel` must be set to `info` to see the
|
||||
// results in uBO's dev console, see:
|
||||
// https://github.com/gorhill/uBlock/wiki/Advanced-settings#consoleloglevel
|
||||
//
|
||||
// The usual browser dev tools can be used to obtain useful profiling
|
||||
// data, i.e. start the profiler, call the benchmark method from the
|
||||
// console, then stop the profiler when it completes.
|
||||
|
@ -232,7 +229,7 @@ import µBlock from './background.js';
|
|||
// Rename ./tmp/requests.json.gz to something else if you no longer want
|
||||
// ./assets/requests.json in the build.
|
||||
|
||||
µBlock.loadBenchmarkDataset = (( ) => {
|
||||
µb.loadBenchmarkDataset = (( ) => {
|
||||
let datasetPromise;
|
||||
let ttlTimer;
|
||||
|
||||
|
@ -251,13 +248,13 @@ import µBlock from './background.js';
|
|||
return datasetPromise;
|
||||
}
|
||||
|
||||
const datasetURL = µBlock.hiddenSettings.benchmarkDatasetURL;
|
||||
const datasetURL = µb.hiddenSettings.benchmarkDatasetURL;
|
||||
if ( datasetURL === 'unset' ) {
|
||||
console.info(`No benchmark dataset available.`);
|
||||
return Promise.resolve();
|
||||
}
|
||||
console.info(`Loading benchmark dataset...`);
|
||||
datasetPromise = µBlock.assets.fetchText(datasetURL).then(details => {
|
||||
datasetPromise = io.fetchText(datasetURL).then(details => {
|
||||
console.info(`Parsing benchmark dataset...`);
|
||||
const requests = [];
|
||||
const lineIter = new LineIterator(details.content);
|
||||
|
@ -288,7 +285,7 @@ import µBlock from './background.js';
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.fireDOMEvent = function(name) {
|
||||
µb.fireDOMEvent = function(name) {
|
||||
if (
|
||||
window instanceof Object &&
|
||||
window.dispatchEvent instanceof Function &&
|
||||
|
@ -302,7 +299,7 @@ import µBlock from './background.js';
|
|||
|
||||
// TODO: properly compare arrays
|
||||
|
||||
µBlock.getModifiedSettings = function(edit, orig = {}) {
|
||||
µb.getModifiedSettings = function(edit, orig = {}) {
|
||||
const out = {};
|
||||
for ( const prop in edit ) {
|
||||
if ( orig.hasOwnProperty(prop) && edit[prop] !== orig[prop] ) {
|
||||
|
@ -312,7 +309,7 @@ import µBlock from './background.js';
|
|||
return out;
|
||||
};
|
||||
|
||||
µBlock.settingValueFromString = function(orig, name, s) {
|
||||
µb.settingValueFromString = function(orig, name, s) {
|
||||
if ( typeof name !== 'string' || typeof s !== 'string' ) { return; }
|
||||
if ( orig.hasOwnProperty(name) === false ) { return; }
|
||||
let r;
|
||||
|
|
Loading…
Reference in New Issue