mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
[mv3] Add badge reflecting number of injectable content on current site
Additonally, general code review.
This commit is contained in:
parent
c0bce368a7
commit
e1b54514cc
@ -185,11 +185,12 @@ body.mobile.no-tooltips .toolRibbon .tool {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
#toggleGreatPowers .badge {
|
#toggleGreatPowers .badge {
|
||||||
|
bottom: 4px;
|
||||||
font-size: var(--font-size-xsmall);
|
font-size: var(--font-size-xsmall);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
right: 4px;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 2px;
|
right: 4px;
|
||||||
}
|
}
|
||||||
body:not(.hasGreatPowers) [data-i18n-title="popupGrantGreatPowers"],
|
body:not(.hasGreatPowers) [data-i18n-title="popupGrantGreatPowers"],
|
||||||
body.hasGreatPowers [data-i18n-title="popupRevokeGreatPowers"] {
|
body.hasGreatPowers [data-i18n-title="popupRevokeGreatPowers"] {
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
|
|
||||||
import { browser, dnr, i18n, runtime } from './ext.js';
|
import { browser, dnr, i18n, runtime } from './ext.js';
|
||||||
import { fetchJSON } from './fetch.js';
|
import { fetchJSON } from './fetch.js';
|
||||||
import { registerInjectable } from './scripting-manager.js';
|
import { getInjectableCount, registerInjectable } from './scripting-manager.js';
|
||||||
|
import { parsedURLromOrigin } from './utils.js';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -229,7 +230,9 @@ async function updateRegexRules() {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
async function matchesTrustedSiteDirective(details) {
|
async function matchesTrustedSiteDirective(details) {
|
||||||
const url = new URL(details.origin);
|
const url = parsedURLromOrigin(details.origin);
|
||||||
|
if ( url === undefined ) { return false; }
|
||||||
|
|
||||||
const dynamicRuleMap = await getDynamicRules();
|
const dynamicRuleMap = await getDynamicRules();
|
||||||
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
||||||
if ( rule === undefined ) { return false; }
|
if ( rule === undefined ) { return false; }
|
||||||
@ -241,11 +244,14 @@ async function matchesTrustedSiteDirective(details) {
|
|||||||
if ( pos === -1 ) { break; }
|
if ( pos === -1 ) { break; }
|
||||||
hostname = hostname.slice(pos+1);
|
hostname = hostname.slice(pos+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addTrustedSiteDirective(details) {
|
async function addTrustedSiteDirective(details) {
|
||||||
const url = new URL(details.origin);
|
const url = parsedURLromOrigin(details.origin);
|
||||||
|
if ( url === undefined ) { return false; }
|
||||||
|
|
||||||
const dynamicRuleMap = await getDynamicRules();
|
const dynamicRuleMap = await getDynamicRules();
|
||||||
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
||||||
if ( rule !== undefined ) {
|
if ( rule !== undefined ) {
|
||||||
@ -254,6 +260,7 @@ async function addTrustedSiteDirective(details) {
|
|||||||
rule.condition.requestDomains = [];
|
rule.condition.requestDomains = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( rule === undefined ) {
|
if ( rule === undefined ) {
|
||||||
rule = {
|
rule = {
|
||||||
id: TRUSTED_DIRECTIVE_BASE_RULE_ID,
|
id: TRUSTED_DIRECTIVE_BASE_RULE_ID,
|
||||||
@ -270,15 +277,19 @@ async function addTrustedSiteDirective(details) {
|
|||||||
} else if ( rule.condition.requestDomains.includes(url.hostname) === false ) {
|
} else if ( rule.condition.requestDomains.includes(url.hostname) === false ) {
|
||||||
rule.condition.requestDomains.push(url.hostname);
|
rule.condition.requestDomains.push(url.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
await dnr.updateDynamicRules({
|
await dnr.updateDynamicRules({
|
||||||
addRules: [ rule ],
|
addRules: [ rule ],
|
||||||
removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ],
|
removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ],
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeTrustedSiteDirective(details) {
|
async function removeTrustedSiteDirective(details) {
|
||||||
const url = new URL(details.origin);
|
const url = parsedURLromOrigin(details.origin);
|
||||||
|
if ( url === undefined ) { return false; }
|
||||||
|
|
||||||
const dynamicRuleMap = await getDynamicRules();
|
const dynamicRuleMap = await getDynamicRules();
|
||||||
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
let rule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
||||||
if ( rule === undefined ) { return false; }
|
if ( rule === undefined ) { return false; }
|
||||||
@ -286,6 +297,7 @@ async function removeTrustedSiteDirective(details) {
|
|||||||
if ( Array.isArray(rule.condition.requestDomains) === false ) {
|
if ( Array.isArray(rule.condition.requestDomains) === false ) {
|
||||||
rule.condition.requestDomains = [];
|
rule.condition.requestDomains = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const domainSet = new Set(rule.condition.requestDomains);
|
const domainSet = new Set(rule.condition.requestDomains);
|
||||||
const beforeCount = domainSet.size;
|
const beforeCount = domainSet.size;
|
||||||
let hostname = url.hostname;
|
let hostname = url.hostname;
|
||||||
@ -295,7 +307,9 @@ async function removeTrustedSiteDirective(details) {
|
|||||||
if ( pos === -1 ) { break; }
|
if ( pos === -1 ) { break; }
|
||||||
hostname = hostname.slice(pos+1);
|
hostname = hostname.slice(pos+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( domainSet.size === beforeCount ) { return false; }
|
if ( domainSet.size === beforeCount ) { return false; }
|
||||||
|
|
||||||
if ( domainSet.size === 0 ) {
|
if ( domainSet.size === 0 ) {
|
||||||
dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID);
|
||||||
await dnr.updateDynamicRules({
|
await dnr.updateDynamicRules({
|
||||||
@ -303,11 +317,14 @@ async function removeTrustedSiteDirective(details) {
|
|||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.condition.requestDomains = Array.from(domainSet);
|
rule.condition.requestDomains = Array.from(domainSet);
|
||||||
|
|
||||||
await dnr.updateDynamicRules({
|
await dnr.updateDynamicRules({
|
||||||
addRules: [ rule ],
|
addRules: [ rule ],
|
||||||
removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ],
|
removeRuleIds: [ TRUSTED_DIRECTIVE_BASE_RULE_ID ],
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,11 +467,13 @@ function onMessage(request, sender, callback) {
|
|||||||
matchesTrustedSiteDirective(request),
|
matchesTrustedSiteDirective(request),
|
||||||
hasGreatPowers(request.origin),
|
hasGreatPowers(request.origin),
|
||||||
getEnabledRulesetsStats(),
|
getEnabledRulesetsStats(),
|
||||||
|
getInjectableCount(request.origin),
|
||||||
]).then(results => {
|
]).then(results => {
|
||||||
callback({
|
callback({
|
||||||
isTrusted: results[0],
|
isTrusted: results[0],
|
||||||
hasGreatPowers: results[1],
|
hasGreatPowers: results[1],
|
||||||
rulesetDetails: results[2],
|
rulesetDetails: results[2],
|
||||||
|
injectableCount: results[3],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@ -493,13 +512,15 @@ async function start() {
|
|||||||
// We need to update the regex rules only when ruleset version changes.
|
// We need to update the regex rules only when ruleset version changes.
|
||||||
const currentVersion = getCurrentVersion();
|
const currentVersion = getCurrentVersion();
|
||||||
if ( currentVersion !== rulesetConfig.version ) {
|
if ( currentVersion !== rulesetConfig.version ) {
|
||||||
await updateRegexRules();
|
|
||||||
console.log(`Version change: ${rulesetConfig.version} => ${currentVersion}`);
|
console.log(`Version change: ${rulesetConfig.version} => ${currentVersion}`);
|
||||||
|
await Promise.all([
|
||||||
|
updateRegexRules(),
|
||||||
|
registerInjectable(),
|
||||||
|
]);
|
||||||
rulesetConfig.version = currentVersion;
|
rulesetConfig.version = currentVersion;
|
||||||
|
saveRulesetConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
saveRulesetConfig();
|
|
||||||
|
|
||||||
const enabledRulesets = await dnr.getEnabledRulesets();
|
const enabledRulesets = await dnr.getEnabledRulesets();
|
||||||
console.log(`Enabled rulesets: ${enabledRulesets}`);
|
console.log(`Enabled rulesets: ${enabledRulesets}`);
|
||||||
|
|
||||||
|
@ -219,6 +219,10 @@ async function init() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
dom.text(qs$('#hostname'), tabHostname);
|
dom.text(qs$('#hostname'), tabHostname);
|
||||||
|
dom.text(
|
||||||
|
qs$('#toggleGreatPowers .badge'),
|
||||||
|
popupPanelData.injectableCount || ''
|
||||||
|
);
|
||||||
|
|
||||||
const parent = qs$('#rulesetStats');
|
const parent = qs$('#rulesetStats');
|
||||||
for ( const details of popupPanelData.rulesetDetails || [] ) {
|
for ( const details of popupPanelData.rulesetDetails || [] ) {
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
import { browser, dnr } from './ext.js';
|
import { browser, dnr } from './ext.js';
|
||||||
import { fetchJSON } from './fetch.js';
|
import { fetchJSON } from './fetch.js';
|
||||||
|
import { parsedURLromOrigin } from './utils.js';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -89,21 +90,21 @@ const toRegisterable = (fname, entry) => {
|
|||||||
id: fname,
|
id: fname,
|
||||||
allFrames: true,
|
allFrames: true,
|
||||||
};
|
};
|
||||||
if ( entry.matches ) {
|
if ( entry.y ) {
|
||||||
directive.matches = matchesFromHostnames(entry.y);
|
directive.matches = matchesFromHostnames(entry.y);
|
||||||
} else {
|
} else {
|
||||||
directive.matches = [ '*://*/*' ];
|
directive.matches = [ '*://*/*' ];
|
||||||
}
|
}
|
||||||
if ( entry.excludeMatches ) {
|
if ( entry.n ) {
|
||||||
directive.excludeMatches = matchesFromHostnames(entry.n);
|
directive.excludeMatches = matchesFromHostnames(entry.n);
|
||||||
}
|
}
|
||||||
if ( entry.type === CSS_TYPE ) {
|
if ( entry.type === CSS_TYPE ) {
|
||||||
directive.css = [
|
directive.css = [
|
||||||
`/content-css/${entry.id}/${fname.slice(0,1)}/${fname.slice(1,8)}.css`
|
`/content-css/${fname.slice(0,1)}/${fname.slice(1,2)}/${fname.slice(2,8)}.css`
|
||||||
];
|
];
|
||||||
} else if ( entry.type === JS_TYPE ) {
|
} else if ( entry.type === JS_TYPE ) {
|
||||||
directive.js = [
|
directive.js = [
|
||||||
`/content-js/${entry.id}/${fname.slice(0,1)}/${fname.slice(1,8)}.js`
|
`/content-js/${fname.slice(0,1)}/${fname.slice(1,8)}.js`
|
||||||
];
|
];
|
||||||
directive.runAt = 'document_start';
|
directive.runAt = 'document_start';
|
||||||
directive.world = 'MAIN';
|
directive.world = 'MAIN';
|
||||||
@ -115,15 +116,12 @@ const toRegisterable = (fname, entry) => {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const shouldRegister = (origins, matches) => {
|
const shouldRegister = (origins, matches) => {
|
||||||
|
if ( Array.isArray(matches) === false ) { return true; }
|
||||||
for ( const origin of origins ) {
|
for ( const origin of origins ) {
|
||||||
if ( origin === '*' || Array.isArray(matches) === false ) {
|
if ( origin === '*' ) { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
let hn = origin;
|
let hn = origin;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ( matches.includes(hn) ) {
|
if ( matches.includes(hn) ) { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( hn === '*' ) { break; }
|
if ( hn === '*' ) { break; }
|
||||||
const pos = hn.indexOf('.');
|
const pos = hn.indexOf('.');
|
||||||
hn = pos !== -1
|
hn = pos !== -1
|
||||||
@ -136,7 +134,9 @@ const shouldRegister = (origins, matches) => {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
async function getInjectableCount(hostname) {
|
async function getInjectableCount(origin) {
|
||||||
|
const url = parsedURLromOrigin(origin);
|
||||||
|
if ( url === undefined ) { return 0; }
|
||||||
|
|
||||||
const [
|
const [
|
||||||
rulesetIds,
|
rulesetIds,
|
||||||
@ -151,23 +151,22 @@ async function getInjectableCount(hostname) {
|
|||||||
let total = 0;
|
let total = 0;
|
||||||
|
|
||||||
for ( const rulesetId of rulesetIds ) {
|
for ( const rulesetId of rulesetIds ) {
|
||||||
|
|
||||||
if ( cssDetails.has(rulesetId) ) {
|
if ( cssDetails.has(rulesetId) ) {
|
||||||
for ( const entry of cssDetails ) {
|
const entries = cssDetails.get(rulesetId);
|
||||||
if ( shouldRegister([ hostname ], entry[1].y) === true ) {
|
for ( const entry of entries ) {
|
||||||
|
if ( shouldRegister([ url.hostname ], entry[1].y) ) {
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( scriptletDetails.has(rulesetId) ) {
|
if ( scriptletDetails.has(rulesetId) ) {
|
||||||
for ( const entry of cssDetails ) {
|
const entries = cssDetails.get(rulesetId);
|
||||||
if ( shouldRegister([ hostname ], entry[1].y) === true ) {
|
for ( const entry of entries ) {
|
||||||
|
if ( shouldRegister([ url.hostname ], entry[1].y) ) {
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
@ -199,23 +198,47 @@ async function registerInjectable() {
|
|||||||
origins.add('*');
|
origins.add('*');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mergeEntries = (a, b) => {
|
||||||
|
if ( b.y !== undefined ) {
|
||||||
|
if ( a.y === undefined ) {
|
||||||
|
a.y = new Set(b.y);
|
||||||
|
} else {
|
||||||
|
b.y.forEach(v => a.y.add(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( b.n !== undefined ) {
|
||||||
|
if ( a.n === undefined ) {
|
||||||
|
a.n = new Set(b.n);
|
||||||
|
} else {
|
||||||
|
b.n.forEach(v => a.n.add(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
const toRegister = new Map();
|
const toRegister = new Map();
|
||||||
|
|
||||||
for ( const rulesetId of rulesetIds ) {
|
for ( const rulesetId of rulesetIds ) {
|
||||||
if ( cssDetails.has(rulesetId) ) {
|
if ( cssDetails.has(rulesetId) ) {
|
||||||
for ( const [ fname, entry ] of cssDetails.get(rulesetId) ) {
|
for ( const [ fname, entry ] of cssDetails.get(rulesetId) ) {
|
||||||
entry.id = rulesetId;
|
if ( shouldRegister(origins, entry.y) === false ) { continue; }
|
||||||
entry.type = CSS_TYPE;
|
let existing = toRegister.get(fname);
|
||||||
if ( shouldRegister(origins, entry.y) !== true ) { continue; }
|
if ( existing === undefined ) {
|
||||||
toRegister.set(fname, entry);
|
existing = { type: CSS_TYPE };
|
||||||
|
toRegister.set(fname, existing);
|
||||||
|
}
|
||||||
|
mergeEntries(existing, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( scriptletDetails.has(rulesetId) ) {
|
if ( scriptletDetails.has(rulesetId) ) {
|
||||||
for ( const [ fname, entry ] of scriptletDetails.get(rulesetId) ) {
|
for ( const [ fname, entry ] of scriptletDetails.get(rulesetId) ) {
|
||||||
entry.id = rulesetId;
|
if ( shouldRegister(origins, entry.y) === false ) { continue; }
|
||||||
entry.type = JS_TYPE;
|
let existing = toRegister.get(fname);
|
||||||
if ( shouldRegister(origins, entry.y) !== true ) { continue; }
|
if ( existing === undefined ) {
|
||||||
toRegister.set(fname, entry);
|
existing = { type: JS_TYPE };
|
||||||
|
toRegister.set(fname, existing);
|
||||||
|
}
|
||||||
|
mergeEntries(existing, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
platform/mv3/extension/js/utils.js
Normal file
37
platform/mv3/extension/js/utils.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
uBlock Origin - a browser extension to block requests.
|
||||||
|
Copyright (C) 2022-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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jshint esversion:11 */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
function parsedURLromOrigin(origin) {
|
||||||
|
try {
|
||||||
|
return new URL(origin);
|
||||||
|
} catch(ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
export { parsedURLromOrigin };
|
@ -305,6 +305,8 @@ function optimizeExtendedFilters(filters) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const globalCSSFileSet = new Set();
|
||||||
|
|
||||||
const style = [
|
const style = [
|
||||||
' display:none!important;',
|
' display:none!important;',
|
||||||
' position:absolute!important;',
|
' position:absolute!important;',
|
||||||
@ -320,15 +322,34 @@ function processCosmeticFilters(assetDetails, mapin) {
|
|||||||
for ( const entry of optimized ) {
|
for ( const entry of optimized ) {
|
||||||
const selectors = entry.payload.join(',\n');
|
const selectors = entry.payload.join(',\n');
|
||||||
const fname = createHash('sha256').update(selectors).digest('hex').slice(0,8);
|
const fname = createHash('sha256').update(selectors).digest('hex').slice(0,8);
|
||||||
const fpath = `${assetDetails.id}/${fname.slice(0,1)}/${fname.slice(1,8)}`;
|
if ( globalCSSFileSet.has(fname) === false ) {
|
||||||
writeFile(
|
globalCSSFileSet.add(fname);
|
||||||
`${cssDir}/${fpath}.css`,
|
const fpath = `${fname.slice(0,1)}/${fname.slice(1,2)}/${fname.slice(2,8)}`;
|
||||||
`${selectors} {\n${style}\n}\n`
|
writeFile(
|
||||||
);
|
`${cssDir}/${fpath}.css`,
|
||||||
cssEntries.set(fname, {
|
`${selectors} {\n${style}\n}\n`
|
||||||
y: entry.matches,
|
);
|
||||||
n: entry.excludeMatches,
|
}
|
||||||
});
|
const existing = cssEntries.get(fname);
|
||||||
|
if ( existing === undefined ) {
|
||||||
|
cssEntries.set(fname, {
|
||||||
|
y: entry.matches,
|
||||||
|
n: entry.excludeMatches,
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( entry.matches ) {
|
||||||
|
for ( const hn of entry.matches ) {
|
||||||
|
if ( existing.y.includes(hn) ) { continue; }
|
||||||
|
existing.y.push(hn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( entry.excludeMatches ) {
|
||||||
|
for ( const hn of entry.excludeMatches ) {
|
||||||
|
if ( existing.n.includes(hn) ) { continue; }
|
||||||
|
existing.n.push(hn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`CSS entries: ${cssEntries.size}`);
|
log(`CSS entries: ${cssEntries.size}`);
|
||||||
@ -342,11 +363,58 @@ function processCosmeticFilters(assetDetails, mapin) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Load all available scriptlets into a key-val map, where the key is the
|
||||||
|
// scriptlet token, and val is the whole content of the file.
|
||||||
|
|
||||||
|
const scriptletDealiasingMap = new Map();
|
||||||
|
let scriptletsMapPromise;
|
||||||
|
|
||||||
|
function loadAllScriptlets() {
|
||||||
|
if ( scriptletsMapPromise !== undefined ) {
|
||||||
|
return scriptletsMapPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptletsMapPromise = fs.readdir('./scriptlets').then(files => {
|
||||||
|
const reScriptletNameOrAlias = /^\/\/\/\s+(?:name|alias)\s+(\S+)/gm;
|
||||||
|
const readPromises = [];
|
||||||
|
for ( const file of files ) {
|
||||||
|
readPromises.push(
|
||||||
|
fs.readFile(`./scriptlets/${file}`, { encoding: 'utf8' })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Promise.all(readPromises).then(results => {
|
||||||
|
const originalScriptletMap = new Map();
|
||||||
|
for ( const text of results ) {
|
||||||
|
const aliasSet = new Set();
|
||||||
|
for (;;) {
|
||||||
|
const match = reScriptletNameOrAlias.exec(text);
|
||||||
|
if ( match === null ) { break; }
|
||||||
|
aliasSet.add(match[1]);
|
||||||
|
}
|
||||||
|
if ( aliasSet.size === 0 ) { continue; }
|
||||||
|
const aliases = Array.from(aliasSet);
|
||||||
|
originalScriptletMap.set(aliases[0], text);
|
||||||
|
for ( let i = 0; i < aliases.length; i++ ) {
|
||||||
|
scriptletDealiasingMap.set(aliases[i], aliases[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return originalScriptletMap;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return scriptletsMapPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
const globalPatchedScriptletsSet = new Set();
|
||||||
|
|
||||||
async function processScriptletFilters(assetDetails, mapin) {
|
async function processScriptletFilters(assetDetails, mapin) {
|
||||||
if ( mapin === undefined ) { return 0; }
|
if ( mapin === undefined ) { return 0; }
|
||||||
|
|
||||||
const originalScriptletMap = new Map();
|
// Load all available scriptlets into a key-val map, where the key is the
|
||||||
const dealiasingMap = new Map();
|
// scriptlet token, and val is the whole content of the file.
|
||||||
|
const originalScriptletMap = await loadAllScriptlets();
|
||||||
|
|
||||||
const parseArguments = (raw) => {
|
const parseArguments = (raw) => {
|
||||||
const out = [];
|
const out = [];
|
||||||
@ -376,7 +444,7 @@ async function processScriptletFilters(assetDetails, mapin) {
|
|||||||
let pos = filter.indexOf(',');
|
let pos = filter.indexOf(',');
|
||||||
if ( pos === -1 ) { pos = end; }
|
if ( pos === -1 ) { pos = end; }
|
||||||
const parts = filter.trim().split(',').map(s => s.trim());
|
const parts = filter.trim().split(',').map(s => s.trim());
|
||||||
const token = dealiasingMap.get(parts[0]) || '';
|
const token = scriptletDealiasingMap.get(parts[0]) || '';
|
||||||
if ( token !== '' && originalScriptletMap.has(token) ) {
|
if ( token !== '' && originalScriptletMap.has(token) ) {
|
||||||
return {
|
return {
|
||||||
token,
|
token,
|
||||||
@ -387,83 +455,45 @@ async function processScriptletFilters(assetDetails, mapin) {
|
|||||||
|
|
||||||
const patchScriptlet = (filter) => {
|
const patchScriptlet = (filter) => {
|
||||||
return originalScriptletMap.get(filter.token).replace(
|
return originalScriptletMap.get(filter.token).replace(
|
||||||
/^self\.\$args\$$/m,
|
/^(\}\)\(\.\.\.)self\.\$args\$(\);)$/m,
|
||||||
`...${JSON.stringify(filter.args, null, 4)}`
|
`$1${JSON.stringify(filter.args, null, 4)}$2`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load all available scriptlets into a key-val map, where the key is the
|
// Generate distinct scriptlet files according to patched scriptlets
|
||||||
// scriptlet token, and val is the whole content of the file.
|
const scriptletEntries = new Map();
|
||||||
const files = await fs.readdir('./scriptlets');
|
|
||||||
const reScriptletNameOrAlias = /^\/\/\/\s+(?:name|alias)\s+(\S+)/gm;
|
|
||||||
for ( const file of files ) {
|
|
||||||
const text = await fs.readFile(
|
|
||||||
`./scriptlets/${file}`,
|
|
||||||
{ encoding: 'utf8' }
|
|
||||||
);
|
|
||||||
const aliasSet = new Set();
|
|
||||||
for (;;) {
|
|
||||||
const match = reScriptletNameOrAlias.exec(text);
|
|
||||||
if ( match === null ) { break; }
|
|
||||||
aliasSet.add(match[1]);
|
|
||||||
}
|
|
||||||
if ( aliasSet.size === 0 ) { continue; }
|
|
||||||
const aliases = Array.from(aliasSet);
|
|
||||||
originalScriptletMap.set(aliases[0], text);
|
|
||||||
for ( let i = 0; i < aliases.length; i++ ) {
|
|
||||||
dealiasingMap.set(aliases[i], aliases[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge entries after dealiasing and expanding arguments
|
for ( const [ rawFilter, entry ] of mapin ) {
|
||||||
const normalizedMap = new Map();
|
|
||||||
for ( const [ rawFilter, toAdd ] of mapin ) {
|
|
||||||
const normalized = parseFilter(rawFilter);
|
const normalized = parseFilter(rawFilter);
|
||||||
if ( normalized === undefined ) { continue; }
|
if ( normalized === undefined ) { continue; }
|
||||||
const key = JSON.stringify(normalized);
|
const json = JSON.stringify(normalized);
|
||||||
const toMerge = normalizedMap.get(key);
|
const fname = createHash('sha256').update(json).digest('hex').slice(0,8);
|
||||||
if ( toMerge === undefined ) {
|
if ( globalPatchedScriptletsSet.has(fname) === false ) {
|
||||||
normalizedMap.set(key, toAdd);
|
globalPatchedScriptletsSet.add(fname);
|
||||||
|
const scriptlet = patchScriptlet(normalized);
|
||||||
|
const fpath = `${fname.slice(0,1)}/${fname.slice(1,8)}`;
|
||||||
|
writeFile(`${scriptletDir}/${fpath}.js`, scriptlet);
|
||||||
|
}
|
||||||
|
const existing = scriptletEntries.get(fname);
|
||||||
|
if ( existing === undefined ) {
|
||||||
|
scriptletEntries.set(fname, {
|
||||||
|
y: entry.matches,
|
||||||
|
n: entry.excludeMatches,
|
||||||
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const matches = new Set(toMerge.matches || []);
|
if ( entry.matches ) {
|
||||||
const excludeMatches = new Set(toMerge.excludeMatches || []);
|
for ( const hn of entry.matches ) {
|
||||||
if ( toAdd.matches && toAdd.matches.size !== 0 ) {
|
if ( existing.y.includes(hn) ) { continue; }
|
||||||
toAdd.matches.forEach(hn => {
|
existing.y.push(hn);
|
||||||
matches.add(hn);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if ( toAdd.excludeMatches && toAdd.excludeMatches.size !== 0 ) {
|
if ( entry.excludeMatches ) {
|
||||||
toAdd.excludeMatches.forEach(hn => {
|
for ( const hn of entry.excludeMatches ) {
|
||||||
excludeMatches.add(hn);
|
if ( existing.n.includes(hn) ) { continue; }
|
||||||
});
|
existing.n.push(hn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( matches.size !== 0 ) {
|
|
||||||
toMerge.matches = matches.has('*')
|
|
||||||
? [ '*' ]
|
|
||||||
: Array.from(matches);
|
|
||||||
}
|
|
||||||
if ( excludeMatches.size !== 0 ) {
|
|
||||||
toMerge.excludeMatches = excludeMatches.has('*')
|
|
||||||
? [ '*' ]
|
|
||||||
: Array.from(excludeMatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine injected resources for same matches/excludeMatches instances
|
|
||||||
//const optimized = optimizeExtendedFilters(normalizedMap);
|
|
||||||
|
|
||||||
// Generate distinct scriptlets according to patched scriptlets
|
|
||||||
const scriptletEntries = new Map();
|
|
||||||
for ( const [ json, entry ] of normalizedMap ) {
|
|
||||||
const fname = createHash('sha256').update(json).digest('hex').slice(0,8);
|
|
||||||
const scriptlet = patchScriptlet(JSON.parse(json));
|
|
||||||
const fpath = `${assetDetails.id}/${fname.slice(0,1)}/${fname.slice(1,8)}`;
|
|
||||||
writeFile(`${scriptletDir}/${fpath}.js`, scriptlet);
|
|
||||||
scriptletEntries.set(fname, {
|
|
||||||
y: entry.matches,
|
|
||||||
n: entry.excludeMatches,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log(`Scriptlet entries: ${scriptletEntries.size}`);
|
log(`Scriptlet entries: ${scriptletEntries.size}`);
|
||||||
|
@ -137,9 +137,7 @@ try {
|
|||||||
return oe.apply(this, arguments);
|
return oe.apply(this, arguments);
|
||||||
}
|
}
|
||||||
}.bind();
|
}.bind();
|
||||||
})(
|
})(...self.$args$);
|
||||||
self.$args$
|
|
||||||
);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -113,9 +113,7 @@ try {
|
|||||||
return Reflect.apply(...arguments).then(o => pruner(o));
|
return Reflect.apply(...arguments).then(o => pruner(o));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})(
|
})(...self.$args$);
|
||||||
self.$args$
|
|
||||||
);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -155,9 +155,7 @@ try {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
trapChain(window, chain);
|
trapChain(window, chain);
|
||||||
})(
|
})(...self.$args$);
|
||||||
self.$args$
|
|
||||||
);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -4176,6 +4176,7 @@ FilterContainer.prototype.dnrFromCompiled = function(op, context, ...args) {
|
|||||||
};
|
};
|
||||||
mergeRules(rulesetMap, 'resourceTypes');
|
mergeRules(rulesetMap, 'resourceTypes');
|
||||||
mergeRules(rulesetMap, 'initiatorDomains');
|
mergeRules(rulesetMap, 'initiatorDomains');
|
||||||
|
mergeRules(rulesetMap, 'requestDomains');
|
||||||
mergeRules(rulesetMap, 'removeParams');
|
mergeRules(rulesetMap, 'removeParams');
|
||||||
|
|
||||||
// Patch case-sensitiveness
|
// Patch case-sensitiveness
|
||||||
|
Loading…
Reference in New Issue
Block a user