Byparr/extentions/uBOL-home/js/background.js
2024-07-24 13:57:40 +00:00

381 lines
12 KiB
JavaScript

/*******************************************************************************
uBlock Origin Lite - a comprehensive, MV3-compliant content blocker
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
*/
/******************************************************************************/
import {
adminRead,
browser,
dnr,
localRead, localWrite,
runtime,
sessionRead, sessionWrite,
} from './ext.js';
import {
broadcastMessage,
ubolLog,
} from './utils.js';
import {
defaultRulesetsFromLanguage,
enableRulesets,
getEnabledRulesetsDetails,
getRulesetDetails,
updateDynamicRules,
} from './ruleset-manager.js';
import {
getDefaultFilteringMode,
getFilteringMode,
getTrustedSites,
setDefaultFilteringMode,
setFilteringMode,
setTrustedSites,
syncWithBrowserPermissions,
} from './mode-manager.js';
import {
registerInjectables,
} from './scripting-manager.js';
/******************************************************************************/
const rulesetConfig = {
version: '',
enabledRulesets: ['default'],
autoReload: true,
showBlockedCount: true,
};
const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, '');
const canShowBlockedCount = typeof dnr.setExtensionActionOptions === 'function';
let firstRun = false;
let wakeupRun = false;
/******************************************************************************/
function getCurrentVersion() {
return runtime.getManifest().version;
}
async function loadRulesetConfig() {
let data = sessionRead('rulesetConfig');
if (data) {
rulesetConfig.version = data.version;
rulesetConfig.enabledRulesets = data.enabledRulesets;
rulesetConfig.autoReload = typeof data.autoReload === 'boolean'
? data.autoReload
: true;
rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean'
? data.showBlockedCount
: true;
wakeupRun = true;
return;
}
data = localRead('rulesetConfig');
if (data) {
rulesetConfig.version = data.version;
rulesetConfig.enabledRulesets = data.enabledRulesets;
rulesetConfig.autoReload = typeof data.autoReload === 'boolean'
? data.autoReload
: true;
rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean'
? data.showBlockedCount
: true;
sessionWrite('rulesetConfig', rulesetConfig);
return;
}
rulesetConfig.enabledRulesets = defaultRulesetsFromLanguage();
sessionWrite('rulesetConfig', rulesetConfig);
localWrite('rulesetConfig', rulesetConfig);
firstRun = true;
}
async function saveRulesetConfig() {
sessionWrite('rulesetConfig', rulesetConfig);
return localWrite('rulesetConfig', rulesetConfig);
}
/******************************************************************************/
async function hasGreatPowers(origin) {
if (/^https?:\/\//.test(origin) === false) { return false; }
return browser.permissions.contains({
origins: [`${origin}/*`],
});
}
function hasOmnipotence() {
return browser.permissions.contains({
origins: ['<all_urls>'],
});
}
async function onPermissionsRemoved() {
const beforeMode = getDefaultFilteringMode();
const modified = syncWithBrowserPermissions();
if (modified === false) { return false; }
const afterMode = getDefaultFilteringMode();
if (beforeMode > 1 && afterMode <= 1) {
updateDynamicRules();
}
registerInjectables();
return true;
}
/******************************************************************************/
function onMessage(request, sender, callback) {
// Does not require trusted origin.
switch (request.what) {
case 'insertCSS': {
const tabId = sender?.tab?.id ?? false;
const frameId = sender?.frameId ?? false;
if (tabId === false || frameId === false) { return; }
browser.scripting.insertCSS({
css: request.css,
origin: 'USER',
target: { tabId, frameIds: [frameId] },
}).catch(reason => {
console.log(reason);
});
return false;
}
default:
break;
}
// Does require trusted origin.
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/MessageSender
// Firefox API does not set `sender.origin`
if (sender.origin !== undefined && sender.origin !== UBOL_ORIGIN) { return; }
switch (request.what) {
case 'applyRulesets': {
enableRulesets(request.enabledRulesets).then(() => {
rulesetConfig.enabledRulesets = request.enabledRulesets;
return saveRulesetConfig();
}).then(() => {
registerInjectables();
callback();
broadcastMessage({ enabledRulesets: rulesetConfig.enabledRulesets });
});
return true;
}
case 'getOptionsPageData': {
Promise.all([
getDefaultFilteringMode(),
getTrustedSites(),
getRulesetDetails(),
dnr.getEnabledRulesets(),
]).then(results => {
const [
defaultFilteringMode,
trustedSites,
rulesetDetails,
enabledRulesets,
] = results;
callback({
defaultFilteringMode,
trustedSites: Array.from(trustedSites),
enabledRulesets,
maxNumberOfEnabledRulesets: dnr.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS,
rulesetDetails: Array.from(rulesetDetails.values()),
autoReload: rulesetConfig.autoReload,
showBlockedCount: rulesetConfig.showBlockedCount,
canShowBlockedCount,
firstRun,
});
firstRun = false;
});
return true;
}
case 'setAutoReload':
rulesetConfig.autoReload = request.state && true || false;
saveRulesetConfig().then(() => {
callback();
broadcastMessage({ autoReload: rulesetConfig.autoReload });
});
return true;
case 'setShowBlockedCount':
rulesetConfig.showBlockedCount = request.state && true || false;
if (canShowBlockedCount) {
dnr.setExtensionActionOptions({
displayActionCountAsBadgeText: rulesetConfig.showBlockedCount,
});
}
saveRulesetConfig().then(() => {
callback();
broadcastMessage({ showBlockedCount: rulesetConfig.showBlockedCount });
});
return true;
case 'popupPanelData': {
Promise.all([
getFilteringMode(request.hostname),
hasOmnipotence(),
hasGreatPowers(request.origin),
getEnabledRulesetsDetails(),
]).then(results => {
callback({
level: results[0],
autoReload: rulesetConfig.autoReload,
hasOmnipotence: results[1],
hasGreatPowers: results[2],
rulesetDetails: results[3],
});
});
return true;
}
case 'getFilteringMode': {
getFilteringMode(request.hostname).then(actualLevel => {
callback(actualLevel);
});
return true;
}
case 'setFilteringMode': {
getFilteringMode(request.hostname).then(actualLevel => {
if (request.level === actualLevel) { return actualLevel; }
return setFilteringMode(request.hostname, request.level);
}).then(actualLevel => {
registerInjectables();
callback(actualLevel);
});
return true;
}
case 'setDefaultFilteringMode': {
getDefaultFilteringMode().then(beforeLevel =>
setDefaultFilteringMode(request.level).then(afterLevel =>
({ beforeLevel, afterLevel })
)
).then(({ beforeLevel, afterLevel }) => {
if (beforeLevel === 1 || afterLevel === 1) {
updateDynamicRules();
}
if (afterLevel !== beforeLevel) {
registerInjectables();
}
callback(afterLevel);
});
return true;
}
case 'setTrustedSites':
setTrustedSites(request.hostnames).then(() => {
registerInjectables();
return Promise.all([
getDefaultFilteringMode(),
getTrustedSites(),
]);
}).then(results => {
callback({
defaultFilteringMode: results[0],
trustedSites: Array.from(results[1]),
});
});
return true;
default:
break;
}
}
/******************************************************************************/
async function start() {
loadRulesetConfig();
if (wakeupRun === false) {
enableRulesets(rulesetConfig.enabledRulesets);
}
// We need to update the regex rules only when ruleset version changes.
if (wakeupRun === false) {
const currentVersion = getCurrentVersion();
if (currentVersion !== rulesetConfig.version) {
ubolLog(`Version change: ${rulesetConfig.version} => ${currentVersion}`);
updateDynamicRules().then(() => {
rulesetConfig.version = currentVersion;
saveRulesetConfig();
});
}
}
// Permissions may have been removed while the extension was disabled
const permissionsChanged = onPermissionsRemoved();
// Unsure whether the browser remembers correctly registered css/scripts
// after we quit the browser. For now uBOL will check unconditionally at
// launch time whether content css/scripts are properly registered.
if (wakeupRun === false || permissionsChanged) {
registerInjectables();
const enabledRulesets = dnr.getEnabledRulesets();
ubolLog(`Enabled rulesets: ${enabledRulesets}`);
dnr.getAvailableStaticRuleCount().then(count => {
ubolLog(`Available static rule count: ${count}`);
});
}
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest
// Firefox API does not support `dnr.setExtensionActionOptions`
if (wakeupRun === false && canShowBlockedCount) {
dnr.setExtensionActionOptions({
displayActionCountAsBadgeText: rulesetConfig.showBlockedCount,
});
}
runtime.onMessage.addListener(onMessage);
browser.permissions.onRemoved.addListener(
() => { onPermissionsRemoved(); }
);
if (firstRun) {
const disableFirstRunPage = adminRead('disableFirstRunPage');
if (disableFirstRunPage !== true) {
runtime.openOptionsPage();
}
}
}
try {
start();
} catch (reason) {
console.trace(reason);
}