mirror of
https://github.com/ThePhaseless/Byparr.git
synced 2025-03-16 02:00:21 +08:00
381 lines
12 KiB
JavaScript
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);
|
||
|
}
|