1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-04 16:47:15 +02:00

[mv3] Add ability to grant/revoke permissions on all sites

This commit is contained in:
Raymond Hill 2022-09-27 19:51:38 -04:00
parent d4b7169421
commit f652cc9855
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
10 changed files with 225 additions and 148 deletions

View File

@ -16,8 +16,13 @@
<div class="body"> <div class="body">
<div id="actions"> <div id="actions">
<p id="listsOfBlockedHostsPrompt"> <p>
<label id="omnipotenceWidget"><span class="input checkbox"><input type="checkbox"><svg viewBox="0 0 24 24"><path d="M1.73,12.91 8.1,19.28 22.79,4.59"/></svg></span><span data-i18n="omnipotenceLabel">_</span></label>
<legend data-i18n="omnipotenceLegend">_</legend>
</p>
<hr>
<p><button id="buttonApply" class="preferred disabled iconified" type="button" data-i18n-title="genericApplyChanges"><span class="fa-icon">check</span><span data-i18n="genericApplyChanges">_</span><span class="hover"></span></button> <p><button id="buttonApply" class="preferred disabled iconified" type="button" data-i18n-title="genericApplyChanges"><span class="fa-icon">check</span><span data-i18n="genericApplyChanges">_</span><span class="hover"></span></button>
<p id="listsOfBlockedHostsPrompt">
</div> </div>
<div> <div>

View File

@ -115,6 +115,14 @@
"message": "Block CSP reports", "message": "Block CSP reports",
"description": "background information: https://github.com/gorhill/uBlock/issues/3150" "description": "background information: https://github.com/gorhill/uBlock/issues/3150"
}, },
"omnipotenceLabel": {
"message": "Enable extended filtering on all websites",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"omnipotenceLegend": {
"message": "uBO Lite can apply extended filtering on a given website only after you explicitly grant the extension permissions to modify data on that website. This setting allows you to grant permissions for extended filtering to all websites at once.",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupDefault": { "3pGroupDefault": {
"message": "Default", "message": "Default",
"description": "Header for a ruleset section in 'Filter lists pane'" "description": "Header for a ruleset section in 'Filter lists pane'"

View File

@ -5,9 +5,14 @@
body { body {
margin-bottom: 6rem; margin-bottom: 6rem;
} }
legend {
color: var(--ink-3);
font-size: var(--font-size-smaller);
padding: var(--default-gap-xxsmall);
}
#actions { #actions {
background-color: var(--surface-1); background-color: var(--surface-1);
padding: 0.5em 0; padding: 1px 0;
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 10; z-index: 10;

View File

@ -1,5 +1,6 @@
body > div.body { body > div.body {
margin: 0 1em; margin: 0 1em;
max-width: min(600px, 100vw);
} }
h2, h3 { h2, h3 {
margin: 1em 0; margin: 1em 0;

View File

@ -186,6 +186,9 @@ body.mobile.no-tooltips .toolRibbon .tool {
#toggleGreatPowers { #toggleGreatPowers {
position: relative; position: relative;
} }
body.hasOmnipotence #toggleGreatPowers {
pointer-events: none;
}
#toggleGreatPowers .badge { #toggleGreatPowers .badge {
bottom: 4px; bottom: 4px;
font-size: var(--font-size-xsmall); font-size: var(--font-size-xsmall);
@ -202,7 +205,7 @@ body:not(.hasGreatPowers) [data-i18n-title="popupRevokeGreatPowers"],
body.hasGreatPowers [data-i18n-title="popupGrantGreatPowers"] { body.hasGreatPowers [data-i18n-title="popupGrantGreatPowers"] {
display: none; display: none;
} }
body [data-i18n-title="popupRevokeGreatPowers"] { body:not(.hasOmnipotence) [data-i18n-title="popupRevokeGreatPowers"] {
fill: var(--popup-power-ink); fill: var(--popup-power-ink);
} }

View File

@ -23,7 +23,7 @@
/******************************************************************************/ /******************************************************************************/
import { sendMessage } from './ext.js'; import { browser, sendMessage } from './ext.js';
import { i18n$ } from './i18n.js'; import { i18n$ } from './i18n.js';
import { dom, qs$, qsa$ } from './dom.js'; import { dom, qs$, qsa$ } from './dom.js';
import { simpleStorage } from './storage.js'; import { simpleStorage } from './storage.js';
@ -42,7 +42,7 @@ const renderNumber = function(value) {
/******************************************************************************/ /******************************************************************************/
const renderFilterLists = function(soft) { function renderFilterLists(soft) {
const { enabledRulesets, rulesetDetails } = cachedRulesetData; const { enabledRulesets, rulesetDetails } = cachedRulesetData;
const listGroupTemplate = qs$('#templates .groupEntry'); const listGroupTemplate = qs$('#templates .groupEntry');
const listEntryTemplate = qs$('#templates .listEntry'); const listEntryTemplate = qs$('#templates .listEntry');
@ -186,11 +186,13 @@ const renderFilterLists = function(soft) {
} }
renderWidgets(); renderWidgets();
}; }
/******************************************************************************/ /******************************************************************************/
const renderWidgets = function() { const renderWidgets = function() {
qs$('#omnipotenceWidget input').checked = cachedRulesetData.hasOmnipotence;
dom.cl.toggle( dom.cl.toggle(
qs$('#buttonApply'), qs$('#buttonApply'),
'disabled', 'disabled',
@ -217,7 +219,30 @@ const renderWidgets = function() {
/******************************************************************************/ /******************************************************************************/
const hashFromCurrentFromSettings = function() { async function onOmnipotenceChanged(ev) {
const input = ev.target;
const newState = input.checked;
const oldState = await browser.permissions.contains({
origins: [ '<all_urls>' ]
});
if ( newState === oldState ) { return; }
if ( newState ) {
browser.permissions.request({ origins: [ '<all_urls>' ] });
} else {
browser.permissions.remove({ origins: [ '<all_urls>' ] });
}
}
dom.on(
qs$('#omnipotenceWidget input'),
'change',
ev => { onOmnipotenceChanged(ev); }
);
/******************************************************************************/
function hashFromCurrentFromSettings() {
const hash = []; const hash = [];
const listHash = []; const listHash = [];
for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) {
@ -227,7 +252,7 @@ const hashFromCurrentFromSettings = function() {
} }
hash.push(listHash.sort().join()); hash.push(listHash.sort().join());
return hash.join(); return hash.join();
}; }
self.hasUnsavedData = function() { self.hasUnsavedData = function() {
return hashFromCurrentFromSettings() !== filteringSettingsHash; return hashFromCurrentFromSettings() !== filteringSettingsHash;
@ -251,7 +276,7 @@ dom.on(
/******************************************************************************/ /******************************************************************************/
const applyEnabledRulesets = async function() { async function applyEnabledRulesets() {
const enabledRulesets = []; const enabledRulesets = [];
for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) { for ( const liEntry of qsa$('#lists .listEntry[data-listkey]') ) {
if ( qs$('input[type="checkbox"]:checked', liEntry) === null ) { continue; } if ( qs$('input[type="checkbox"]:checked', liEntry) === null ) { continue; }
@ -264,13 +289,13 @@ const applyEnabledRulesets = async function() {
}); });
filteringSettingsHash = hashFromCurrentFromSettings(); filteringSettingsHash = hashFromCurrentFromSettings();
}; }
const buttonApplyHandler = async function() { async function buttonApplyHandler() {
dom.cl.remove(qs$('#buttonApply'), 'enabled'); dom.cl.remove(qs$('#buttonApply'), 'enabled');
await applyEnabledRulesets(); await applyEnabledRulesets();
renderWidgets(); renderWidgets();
}; }
dom.on( dom.on(
qs$('#buttonApply'), qs$('#buttonApply'),
@ -282,13 +307,13 @@ dom.on(
// Collapsing of unused lists. // Collapsing of unused lists.
const mustHideUnusedLists = function(which) { function mustHideUnusedLists(which) {
const hideAll = hideUnusedSet.has('*'); const hideAll = hideUnusedSet.has('*');
if ( which === '*' ) { return hideAll; } if ( which === '*' ) { return hideAll; }
return hideUnusedSet.has(which) !== hideAll; return hideUnusedSet.has(which) !== hideAll;
}; }
const toggleHideUnusedLists = function(which) { function toggleHideUnusedLists(which) {
const doesHideAll = hideUnusedSet.has('*'); const doesHideAll = hideUnusedSet.has('*');
let groupSelector; let groupSelector;
let mustHide; let mustHide;
@ -325,7 +350,7 @@ const toggleHideUnusedLists = function(which) {
'hideUnusedFilterLists', 'hideUnusedFilterLists',
Array.from(hideUnusedSet) Array.from(hideUnusedSet)
); );
}; }
dom.on( dom.on(
qs$('#lists'), qs$('#lists'),

View File

@ -43,7 +43,7 @@ import {
import { import {
getInjectableCount, getInjectableCount,
registerInjectable, registerInjectables,
} from './scripting-manager.js'; } from './scripting-manager.js';
import { import {
@ -113,26 +113,24 @@ async function saveRulesetConfig() {
/******************************************************************************/ /******************************************************************************/
async function hasGreatPowers(origin) { function hasGreatPowers(origin) {
return browser.permissions.contains({ return browser.permissions.contains({
origins: [ `${origin}/*` ], origins: [ `${origin}/*` ],
}); });
} }
function grantGreatPowers(hostname) { function hasOmnipotence() {
return browser.permissions.request({ return browser.permissions.contains({
origins: [ `*://${hostname}/*` ], origins: [ '<all_urls>' ],
}); });
} }
function revokeGreatPowers(hostname) { function onPermissionsAdded(permissions) {
return browser.permissions.remove({ registerInjectables(permissions.origins);
origins: [ `*://${hostname}/*` ],
});
} }
function onPermissionsChanged() { function onPermissionsRemoved(permissions) {
registerInjectable(); registerInjectables(permissions.origins);
} }
/******************************************************************************/ /******************************************************************************/
@ -145,7 +143,7 @@ function onMessage(request, sender, callback) {
rulesetConfig.enabledRulesets = request.enabledRulesets; rulesetConfig.enabledRulesets = request.enabledRulesets;
return Promise.all([ return Promise.all([
saveRulesetConfig(), saveRulesetConfig(),
registerInjectable(), registerInjectables(),
]); ]);
}).then(( ) => { }).then(( ) => {
callback(); callback();
@ -157,50 +155,40 @@ function onMessage(request, sender, callback) {
Promise.all([ Promise.all([
getRulesetDetails(), getRulesetDetails(),
dnr.getEnabledRulesets(), dnr.getEnabledRulesets(),
hasOmnipotence(),
]).then(results => { ]).then(results => {
const [ rulesetDetails, enabledRulesets ] = results; const [ rulesetDetails, enabledRulesets, hasOmnipotence ] = results;
callback({ callback({
enabledRulesets, enabledRulesets,
rulesetDetails: Array.from(rulesetDetails.values()), rulesetDetails: Array.from(rulesetDetails.values()),
hasOmnipotence,
}); });
}); });
return true; return true;
} }
case 'grantGreatPowers':
grantGreatPowers(request.hostname).then(granted => {
console.info(`Granted uBOL great powers on ${request.hostname}: ${granted}`);
callback(granted);
});
return true;
case 'popupPanelData': { case 'popupPanelData': {
Promise.all([ Promise.all([
matchesTrustedSiteDirective(request), matchesTrustedSiteDirective(request),
hasOmnipotence(),
hasGreatPowers(request.origin), hasGreatPowers(request.origin),
getEnabledRulesetsStats(), getEnabledRulesetsStats(),
getInjectableCount(request.origin), getInjectableCount(request.origin),
]).then(results => { ]).then(results => {
callback({ callback({
isTrusted: results[0], isTrusted: results[0],
hasGreatPowers: results[1], hasOmnipotence: results[1],
rulesetDetails: results[2], hasGreatPowers: results[2],
injectableCount: results[3], rulesetDetails: results[3],
injectableCount: results[4],
}); });
}); });
return true; return true;
} }
case 'revokeGreatPowers':
revokeGreatPowers(request.hostname).then(removed => {
console.info(`Revoked great powers from uBOL on ${request.hostname}: ${removed}`);
callback(removed);
});
return true;
case 'toggleTrustedSiteDirective': { case 'toggleTrustedSiteDirective': {
toggleTrustedSiteDirective(request).then(response => { toggleTrustedSiteDirective(request).then(response => {
registerInjectable().then(( ) => { registerInjectables().then(( ) => {
callback(response); callback(response);
}); });
}); });
@ -232,7 +220,7 @@ async function start() {
// Unsure whether the browser remembers correctly registered css/scripts // Unsure whether the browser remembers correctly registered css/scripts
// after we quit the browser. For now uBOL will check unconditionally at // after we quit the browser. For now uBOL will check unconditionally at
// launch time whether content css/scripts are properly registered. // launch time whether content css/scripts are properly registered.
registerInjectable(); registerInjectables();
const enabledRulesets = await dnr.getEnabledRulesets(); const enabledRulesets = await dnr.getEnabledRulesets();
console.log(`Enabled rulesets: ${enabledRulesets}`); console.log(`Enabled rulesets: ${enabledRulesets}`);
@ -249,6 +237,6 @@ async function start() {
runtime.onMessage.addListener(onMessage); runtime.onMessage.addListener(onMessage);
browser.permissions.onAdded.addListener(onPermissionsChanged); browser.permissions.onAdded.addListener(onPermissionsAdded);
browser.permissions.onRemoved.addListener(onPermissionsChanged); browser.permissions.onRemoved.addListener(onPermissionsRemoved);
})(); })();

View File

@ -157,9 +157,10 @@ dom.on(qs$('#lessButton'), 'click', ( ) => {
/******************************************************************************/ /******************************************************************************/
async function grantGreatPowers() { async function grantGreatPowers() {
const granted = await sendMessage({ if ( tabHostname === '' ) { return; }
what: 'grantGreatPowers', const targetHostname = tabHostname.replace(/^www\./, '');
hostname: tabHostname, const granted = await browser.permissions.request({
origins: [ `*://*.${targetHostname}/*` ],
}); });
if ( granted !== true ) { return; } if ( granted !== true ) { return; }
dom.cl.add(dom.body, 'hasGreatPowers'); dom.cl.add(dom.body, 'hasGreatPowers');
@ -167,9 +168,10 @@ async function grantGreatPowers() {
} }
async function revokeGreatPowers() { async function revokeGreatPowers() {
const removed = await sendMessage({ if ( tabHostname === '' ) { return; }
what: 'revokeGreatPowers', const targetHostname = tabHostname.replace(/^www\./, '');
hostname: tabHostname, const removed = await browser.permissions.remove({
origins: [ `*://*.${targetHostname}/*` ],
}); });
if ( removed !== true ) { return; } if ( removed !== true ) { return; }
dom.cl.remove(dom.body, 'hasGreatPowers'); dom.cl.remove(dom.body, 'hasGreatPowers');
@ -212,6 +214,12 @@ async function init() {
popupPanelData.isTrusted === true popupPanelData.isTrusted === true
); );
dom.cl.toggle(
dom.body,
'hasOmnipotence',
popupPanelData.hasOmnipotence === true
);
dom.cl.toggle( dom.cl.toggle(
dom.body, dom.body,
'hasGreatPowers', 'hasGreatPowers',

View File

@ -29,12 +29,7 @@ import { browser, dnr } from './ext.js';
import { fetchJSON } from './fetch.js'; import { fetchJSON } from './fetch.js';
import { getAllTrustedSiteDirectives } from './trusted-sites.js'; import { getAllTrustedSiteDirectives } from './trusted-sites.js';
import { import * as ut from './utils.js';
parsedURLromOrigin,
toBroaderHostname,
fidFromFileName,
fnameFromFileId,
} from './utils.js';
/******************************************************************************/ /******************************************************************************/
@ -57,28 +52,6 @@ function getScriptingDetails() {
/******************************************************************************/ /******************************************************************************/
const matchesFromHostnames = hostnames => {
const out = [];
for ( const hn of hostnames ) {
if ( hn === '*' ) {
out.push('*://*/*');
} else {
out.push(`*://*.${hn}/*`);
}
}
return out;
};
const hostnamesFromMatches = origins => {
const out = [];
for ( const origin of origins ) {
const match = /^\*:\/\/([^\/]+)\/\*/.exec(origin);
if ( match === null ) { continue; }
out.push(match[1]);
}
return out;
};
const arrayEq = (a, b) => { const arrayEq = (a, b) => {
if ( a === undefined ) { return b === undefined; } if ( a === undefined ) { return b === undefined; }
if ( b === undefined ) { return false; } if ( b === undefined ) { return false; }
@ -96,20 +69,20 @@ const toRegisterable = (fname, entry) => {
id: fname, id: fname,
}; };
if ( entry.matches ) { if ( entry.matches ) {
directive.matches = matchesFromHostnames(entry.matches); directive.matches = ut.matchesFromHostnames(entry.matches);
} else { } else {
directive.matches = [ '*://*/*' ]; directive.matches = [ '<all_urls>' ];
} }
if ( entry.excludeMatches ) { if ( entry.excludeMatches ) {
directive.excludeMatches = matchesFromHostnames(entry.excludeMatches); directive.excludeMatches = ut.matchesFromHostnames(entry.excludeMatches);
} }
directive.js = [ `/rulesets/js/${fname.slice(0,2)}/${fname.slice(2)}.js` ]; directive.js = [ `/rulesets/js/${fname.slice(0,2)}/${fname.slice(2)}.js` ];
if ( (fidFromFileName(fname) & RUN_AT_BIT) !== 0 ) { if ( (ut.fidFromFileName(fname) & RUN_AT_BIT) !== 0 ) {
directive.runAt = 'document_end'; directive.runAt = 'document_end';
} else { } else {
directive.runAt = 'document_start'; directive.runAt = 'document_start';
} }
if ( (fidFromFileName(fname) & MAIN_WORLD_BIT) !== 0 ) { if ( (ut.fidFromFileName(fname) & MAIN_WORLD_BIT) !== 0 ) {
directive.world = 'MAIN'; directive.world = 'MAIN';
} }
return directive; return directive;
@ -122,22 +95,31 @@ const MAIN_WORLD_BIT = 0b01;
const shouldUpdate = (registered, candidate) => { const shouldUpdate = (registered, candidate) => {
const matches = candidate.matches && const matches = candidate.matches &&
matchesFromHostnames(candidate.matches); ut.matchesFromHostnames(candidate.matches);
if ( arrayEq(registered.matches, matches) === false ) { if ( arrayEq(registered.matches, matches) === false ) {
return true; return true;
} }
const excludeMatches = candidate.excludeMatches && const excludeMatches = candidate.excludeMatches &&
matchesFromHostnames(candidate.excludeMatches); ut.matchesFromHostnames(candidate.excludeMatches);
if ( arrayEq(registered.excludeMatches, excludeMatches) === false ) { if ( arrayEq(registered.excludeMatches, excludeMatches) === false ) {
return true; return true;
} }
return false; return false;
}; };
const isTrustedHostname = (trustedSites, hn) => {
if ( trustedSites.size === 0 ) { return false; }
while ( hn ) {
if ( trustedSites.has(hn) ) { return true; }
hn = ut.toBroaderHostname(hn);
}
return false;
};
/******************************************************************************/ /******************************************************************************/
async function getInjectableCount(origin) { async function getInjectableCount(origin) {
const url = parsedURLromOrigin(origin); const url = ut.parsedURLromOrigin(origin);
if ( url === undefined ) { return 0; } if ( url === undefined ) { return 0; }
const [ const [
@ -161,7 +143,7 @@ async function getInjectableCount(origin) {
} else if ( Array.isArray(fids) ) { } else if ( Array.isArray(fids) ) {
total += fids.length; total += fids.length;
} }
hn = toBroaderHostname(hn); hn = ut.toBroaderHostname(hn);
} }
} }
@ -170,49 +152,27 @@ async function getInjectableCount(origin) {
/******************************************************************************/ /******************************************************************************/
async function registerInjectable() { function registerSomeInjectables(args) {
const {
if ( browser.scripting === undefined ) { return false; } hostnamesSet,
const [
hostnames,
trustedSites, trustedSites,
rulesetIds, rulesetIds,
registered,
scriptingDetails, scriptingDetails,
] = await Promise.all([ } = args;
browser.permissions.getAll(),
getAllTrustedSiteDirectives(),
dnr.getEnabledRulesets(),
browser.scripting.getRegisteredContentScripts(),
getScriptingDetails(),
]).then(results => {
results[0] = new Set(hostnamesFromMatches(results[0].origins));
results[1] = new Set(results[1]);
return results;
});
const toRegister = new Map(); const toRegisterMap = new Map();
const isTrustedHostname = hn => {
while ( hn ) {
if ( trustedSites.has(hn) ) { return true; }
hn = toBroaderHostname(hn);
}
return false;
};
const checkMatches = (details, hn) => { const checkMatches = (details, hn) => {
let fids = details.matches?.get(hn); let fids = details.matches?.get(hn);
if ( fids === undefined ) { return; } if ( fids === undefined ) { return; }
if ( typeof fids === 'number' ) { fids = [ fids ]; } if ( typeof fids === 'number' ) { fids = [ fids ]; }
for ( const fid of fids ) { for ( const fid of fids ) {
const fname = fnameFromFileId(fid); const fname = ut.fnameFromFileId(fid);
const existing = toRegister.get(fname); const existing = toRegisterMap.get(fname);
if ( existing ) { if ( existing ) {
existing.matches.push(hn); existing.matches.push(hn);
} else { } else {
toRegister.set(fname, { matches: [ hn ] }); toRegisterMap.set(fname, { matches: [ hn ] });
} }
} }
}; };
@ -220,47 +180,91 @@ async function registerInjectable() {
for ( const rulesetId of rulesetIds ) { for ( const rulesetId of rulesetIds ) {
const details = scriptingDetails.get(rulesetId); const details = scriptingDetails.get(rulesetId);
if ( details === undefined ) { continue; } if ( details === undefined ) { continue; }
for ( let hn of hostnames ) { for ( let hn of hostnamesSet ) {
if ( isTrustedHostname(hn) ) { continue; } if ( isTrustedHostname(trustedSites, hn) ) { continue; }
while ( hn ) { while ( hn ) {
checkMatches(details, hn); checkMatches(details, hn);
hn = toBroaderHostname(hn); hn = ut.toBroaderHostname(hn);
} }
} }
} }
const checkExcludeMatches = (details, hn) => { return toRegisterMap;
let fids = details.excludeMatches?.get(hn); }
if ( fids === undefined ) { return; }
if ( typeof fids === 'number' ) { fids = [ fids ]; } function registerAllInjectables(args) {
for ( const fid of fids ) { const {
const fname = fnameFromFileId(fid); trustedSites,
const existing = toRegister.get(fname); rulesetIds,
if ( existing === undefined ) { continue; } scriptingDetails,
if ( existing.excludeMatches ) { } = args;
existing.excludeMatches.push(hn);
} else { const toRegisterMap = new Map();
toRegister.set(fname, { excludeMatches: [ hn ] });
}
}
};
for ( const rulesetId of rulesetIds ) { for ( const rulesetId of rulesetIds ) {
const details = scriptingDetails.get(rulesetId); const details = scriptingDetails.get(rulesetId);
if ( details === undefined ) { continue; } if ( details === undefined ) { continue; }
for ( let hn of hostnames.keys() ) { for ( let [ hn, fids ] of details.matches ) {
while ( hn ) { if ( isTrustedHostname(trustedSites, hn) ) { continue; }
checkExcludeMatches(details, hn); if ( typeof fids === 'number' ) { fids = [ fids ]; }
hn = toBroaderHostname(hn); for ( const fid of fids ) {
const fname = ut.fnameFromFileId(fid);
const existing = toRegisterMap.get(fname);
if ( existing ) {
existing.matches.push(hn);
} else {
toRegisterMap.set(fname, { matches: [ hn ] });
}
} }
} }
} }
return toRegisterMap;
}
/******************************************************************************/
async function registerInjectables(origins) {
void origins;
if ( browser.scripting === undefined ) { return false; }
const [
hostnamesSet,
trustedSites,
rulesetIds,
scriptingDetails,
registered,
] = await Promise.all([
browser.permissions.getAll(),
getAllTrustedSiteDirectives(),
dnr.getEnabledRulesets(),
getScriptingDetails(),
browser.scripting.getRegisteredContentScripts(),
]).then(results => {
results[0] = new Set(ut.hostnamesFromMatches(results[0].origins));
results[1] = new Set(results[1]);
return results;
});
const toRegisterMap = hostnamesSet.has('*')
? registerAllInjectables({
trustedSites,
rulesetIds,
scriptingDetails,
})
: registerSomeInjectables({
hostnamesSet,
trustedSites,
rulesetIds,
scriptingDetails,
});
const before = new Map(registered.map(entry => [ entry.id, entry ])); const before = new Map(registered.map(entry => [ entry.id, entry ]));
const toAdd = []; const toAdd = [];
const toUpdate = []; const toUpdate = [];
for ( const [ fname, entry ] of toRegister ) { for ( const [ fname, entry ] of toRegisterMap ) {
if ( before.has(fname) === false ) { if ( before.has(fname) === false ) {
toAdd.push(toRegisterable(fname, entry)); toAdd.push(toRegisterable(fname, entry));
continue; continue;
@ -272,7 +276,7 @@ async function registerInjectable() {
const toRemove = []; const toRemove = [];
for ( const fname of before.keys() ) { for ( const fname of before.keys() ) {
if ( toRegister.has(fname) ) { continue; } if ( toRegisterMap.has(fname) ) { continue; }
toRemove.push(fname); toRemove.push(fname);
} }
@ -298,5 +302,5 @@ async function registerInjectable() {
export { export {
getInjectableCount, getInjectableCount,
registerInjectable registerInjectables
}; };

View File

@ -42,6 +42,34 @@ const toBroaderHostname = hn => {
/******************************************************************************/ /******************************************************************************/
const matchesFromHostnames = hostnames => {
const out = [];
for ( const hn of hostnames ) {
if ( hn === '*' ) {
out.push('<all_urls>');
} else {
out.push(`*://*.${hn}/*`);
}
}
return out;
};
const hostnamesFromMatches = origins => {
const out = [];
for ( const origin of origins ) {
if ( origin === '<all_urls>' ) {
out.push('*');
continue;
}
const match = /^\*:\/\/(?:\*\.)?([^\/]+)\/\*/.exec(origin);
if ( match === null ) { continue; }
out.push(match[1]);
}
return out;
};
/******************************************************************************/
const fnameFromFileId = fid => const fnameFromFileId = fid =>
fid.toString(32).padStart(7, '0'); fid.toString(32).padStart(7, '0');
@ -53,6 +81,8 @@ const fidFromFileName = fname =>
export { export {
parsedURLromOrigin, parsedURLromOrigin,
toBroaderHostname, toBroaderHostname,
matchesFromHostnames,
hostnamesFromMatches,
fnameFromFileId, fnameFromFileId,
fidFromFileName, fidFromFileName,
}; };