mirror of
https://github.com/gorhill/uBlock.git
synced 2026-03-11 09:04:36 +00:00
commit
697e4ae7bb
84 changed files with 2033 additions and 1307 deletions
|
|
@ -4,7 +4,8 @@
|
|||
"eqeqeq": true,
|
||||
"esnext": true,
|
||||
"globals": {
|
||||
"chrome": false,
|
||||
"browser": false, // global variable in Firefox, Edge
|
||||
"chrome": false, // global variable in Chromium, Chrome, Opera
|
||||
"Components": false, // global variable in Firefox
|
||||
"safari": false,
|
||||
"self": false,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
# Submitting issues
|
||||
|
||||
For **support/discussions**, there is [Mozilla Discourse](https://discourse.mozilla-community.org/t/support-ublock-origin/6746).
|
||||
Please stop opening invalid issues regarding the "Legacy" label of uBlock Origin on AMO, it's all explained in the [Release notes](https://github.com/gorhill/uBlock/releases).
|
||||
|
||||
For **support/discussions/help**, there is [/r/uBlockOrigin](https://www.reddit.com/r/uBlockOrigin/) on Reddit -- this is where I see the most activity for people helping each other regarding uBlock Origin.
|
||||
|
||||
For **filter-related issues**, report on the respective filter list support site, or at [uBlockOrigin/uAssets](https://github.com/uBlockOrigin/uAssets/issues). Use [the logger](https://github.com/gorhill/uBlock/wiki/The-logger) to diagnose/confirm filter-related issues. If something does not work properly with uBO enabled, the **first step** is to rule out filter-related issues.
|
||||
|
||||
Ignorance of the above rules is no excuse: **Opening an issue for purpose of support or discussion, or opening a filter-related issue will result in the user being immediately blocked.** Given the [amount of invalid issues being opened](https://github.com/gorhill/uBlock/issues?q=is%3Aissue+label%3Ainvalid+is%3Aclosed), I have no choice but to resort to such a drastic measure. You will still be able to open filter list issues at [uBlockOrigin/uAssets](https://github.com/uBlockOrigin/uAssets/issues).
|
||||
|
||||
**The issue tracker is for provable issues only:** You will have to make the case that the issue is really with uBlock Origin and not something else on your side. To make a case means to provide detailed steps so that anybody can reproduce the issue. Be sure to rule out that the issue is not caused by something specific on your side.
|
||||
**The issue tracker is for provable issues only:** You will have to make the case that the issue is really with uBlock Origin and not something else on your side. To make a case means to provide detailed steps so that anybody can reproduce the issue. Be sure to rule out that the issue is not caused by something specific on your side. Specifically, _speculated_ performance issues will be marked as invalid and closed if they do not come with **actual profiling data + analysis** supporting the claim.
|
||||
|
||||
**Any issue opened without effort to provide the required details for me (or anybody else) to reproduce the problem will be closed as _invalid_.** If you provide more details thereafter for me to reproduce the issue, I will reopen it if I can confirm there is indeed an issue with uBlock Origin. Example of detailed steps:
|
||||
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -1,10 +1,10 @@
|
|||
[](https://travis-ci.org/gorhill/uBlock)
|
||||
[](https://crowdin.com/project/ublock)
|
||||
[](https://crowdin.com/project/ublock)
|
||||
[](https://github.com/gorhill/uBlock/blob/master/LICENSE.txt)
|
||||
|
||||
***
|
||||
|
||||
##### BEWARE! uBlock Origin is COMPLETELY UNRELATED to the web site ublock.org
|
||||
##### BEWARE! uBlock Origin is (and has always been) COMPLETELY UNRELATED to the web site ublock.org
|
||||
|
||||
The donations sought by the [individual](https://github.com/chrisaljoudi/) behind `ublock.org` (_"to keeps uBlock development possible"_, [a misrepresentation](https://en.wikipedia.org/wiki/UBlock_Origin#uBlock_.28ublock.org.29)) are _not_ benefiting any of those who contributed most to create uBlock Origin ([developers](https://github.com/gorhill/uBlock/graphs/contributors), [translators](https://crowdin.com/project/ublock), and all those who put efforts in opening detailed issues). For the differences between uBlock Origin and uBlock, see the unbiased [Wikipedia article](https://en.wikipedia.org/wiki/UBlock_Origin).
|
||||
|
||||
|
|
@ -66,6 +66,8 @@ uBlock Origin
|
|||
|
||||
Visit the [uBlock Origin's wiki](https://github.com/gorhill/uBlock/wiki) for documentation.
|
||||
|
||||
For support/questions/help, there is [/r/uBlockOrigin](https://www.reddit.com/r/uBlockOrigin/) on Reddit.
|
||||
|
||||
## Philosophy
|
||||
|
||||
uBlock Origin (or uBlock₀) is not an *ad blocker*; it's a general-purpose blocker. uBlock₀ blocks ads through its support of the [Adblock Plus filter syntax](https://adblockplus.org/en/filters). uBlock₀ [extends](https://github.com/gorhill/uBlock/wiki/Filter-syntax-extensions) the syntax and is designed to work with custom rules and filters. Furthermore, advanced mode allows uBlock₀ to work in [default-deny mode](https://github.com/gorhill/uBlock/wiki/Dynamic-filtering:-default-deny), which mode will cause [all 3rd-party network requests](https://requestpolicycontinued.github.io/#what-are-cross-site-requests) to be blocked by default, unless allowed by the user.
|
||||
|
|
@ -122,16 +124,12 @@ You can install the latest version [manually](https://github.com/gorhill/uBlock/
|
|||
|
||||
It is expected that uBlock Origin is compatible with any Chromium-based browsers.
|
||||
|
||||
**Important:** Chromium-based browsers do not relay [websocket connections](https://en.wikipedia.org/wiki/WebSocket) to the extension API. This means websites can use websocket connections to bypass uBO (or any other blocker). This can be remediated by installing uBO's companion extension [uBO-Extra](https://github.com/gorhill/uBO-Extra).
|
||||
|
||||
#### Firefox / Firefox for Android
|
||||
|
||||
[Firefox Add-ons web site](https://addons.mozilla.org/addon/ublock-origin/). There is also a development version if you want to test uBlock Origin with the latest changes: see [_uBlock Origin Version History_](https://addons.mozilla.org/addon/ublock-origin/versions/beta)
|
||||
|
||||
uBlock Origin is compatible with [SeaMonkey](http://www.seamonkey-project.org/), [Pale Moon](https://www.palemoon.org/), and possibly other browsers based on Firefox.
|
||||
|
||||
The Firefox version of uBlock Origin has [an extra feature](https://github.com/gorhill/uBlock/wiki/Inline-script-tag-filtering) currently not yet available on Chromium-based browsers -- which feature is of great help to foil attempts by many web sites to circumvent blockers.
|
||||
|
||||
Also of interest: [Deploying uBlock Origin for Firefox with CCK2 and Group Policy](http://decentsecurity.com/ublock-for-firefox-deployment/).
|
||||
|
||||
Thanks to Debian contributor [Sean Whitton](https://wiki.debian.org/SeanWhitton), users of Debian 9 or later or Ubuntu 16.04 or later may simply
|
||||
|
|
@ -153,7 +151,7 @@ Development version available at <https://github.com/el1t/uBlock-Safari#ublock-o
|
|||
|
||||
#### Note for all browsers
|
||||
|
||||
To benefit from uBlock Origin's higher efficiency, it's advised that you don't use other inefficient blockers at the same time (such as AdBlock or Adblock Plus). uBlock₀ will do [as well or better](#blocking) than most popular ad blockers.
|
||||
To benefit from uBlock Origin's higher efficiency, it's advised that you don't use other inefficient blockers at the same time (such as AdBlock or Adblock Plus). uBlock₀ will do [as well or better](#blocking) than most popular ad blockers. Other blockers can also prevent uBlock₀'s privacy or anti-blocker features from working properly.
|
||||
|
||||
## Release History
|
||||
|
||||
|
|
|
|||
|
|
@ -364,8 +364,8 @@
|
|||
"off": true,
|
||||
"title": "EST: Eesti saitidele kohandatud filter",
|
||||
"lang": "et",
|
||||
"contentURL": "http://adblock.ee/list.php",
|
||||
"supportURL": "http://adblock.ee/"
|
||||
"contentURL": "https://adblock.ee/list.php",
|
||||
"supportURL": "https://adblock.ee/"
|
||||
},
|
||||
"EU-prebake": {
|
||||
"content": "filters",
|
||||
|
|
|
|||
26
dist/README.md
vendored
26
dist/README.md
vendored
|
|
@ -1,6 +1,6 @@
|
|||
## INSTALL
|
||||
|
||||
#### Chromium
|
||||
### Chromium
|
||||
|
||||
- Download and unzip `ublock0.chromium.zip` ([latest release desirable](https://github.com/gorhill/uBlock/releases)).
|
||||
- Rename the unzipped directory to `ublock`
|
||||
|
|
@ -20,26 +20,42 @@ Remember that you have to update manually also. For some users, updating manuall
|
|||
- You can update when **you** want
|
||||
- If ever a new version sucks, you can easily just re-install the previous one
|
||||
|
||||
#### Firefox
|
||||
### Firefox webext
|
||||
|
||||
Compatible with Firefox 52 and beyond.
|
||||
|
||||
- Download `ublock0.webext.xpi` ([latest release desirable](https://github.com/gorhill/uBlock/releases)).
|
||||
- Drag and drop the previously downloaded `ublock0.webext.xpi` into Firefox
|
||||
|
||||
On Linux, the settings are saved in a JSON file located at `~/.mozilla/firefox/[profile name]/browser-extension-data/uBlock0@raymondhill.net/storage.js`.
|
||||
|
||||
When you uninstall the extension, Firefox deletes that file, so all your settings are lost when you uninstall.
|
||||
|
||||
### Firefox legacy
|
||||
|
||||
Compatible with Firefox 24 to Firefox 56.
|
||||
|
||||
- Download `ublock0.firefox.xpi` ([latest release desirable](https://github.com/gorhill/uBlock/releases)).
|
||||
- Drag and drop the previously downloaded `ublock0.firefox.xpi` into Firefox
|
||||
|
||||
With Firefox 43 and beyond, you may need to toggle the setting `xpinstall.signatures.required` to `false` in `about:config`.
|
||||
|
||||
Your uBlock Origin settings are kept intact even after you uninstall the addon.
|
||||
|
||||
On Linux, the settings are saved in a SQlite file located at `~/.mozilla/firefox/[profile name]/extension-data/ublock0.sqlite`.
|
||||
|
||||
On Windows, the settings are saved in a SQlite file located at `%APPDATA%\Mozilla\Firefox\Profiles\[profile name]\extension-data\ublock0.sqlite`.
|
||||
|
||||
#### Build instructions (for developers)
|
||||
### Build instructions (for developers)
|
||||
|
||||
- Clone [uBlock](https://github.com/gorhill/uBlock) and [uAssets](https://github.com/uBlockOrigin/uAssets) repositories in the same parent directory
|
||||
- Set path to uBlock: `cd uBlock`
|
||||
- Optional: Select the version to build: `git checkout <tag>`
|
||||
- Build the plugin:
|
||||
- Chromium: `./tools/make-chromium.sh`
|
||||
- Firefox: `./tools/make-firefox.sh all`
|
||||
- Firefox webext: `./tools/make-webext.sh all`
|
||||
- Firefox legacy: `./tools/make-firefox.sh all`
|
||||
- Load the result of the build into your browser:
|
||||
- Chromium: load the unpacked extension folder `/uBlock/dist/build/uBlock0.chromium/` in Chromium to use the extension.
|
||||
- Firefox: drag-and-drop `/uBlock/dist/build/uBlock0.firefox.xpi` into Firefox.
|
||||
- Firefox: drag-and-drop `/uBlock/dist/build/uBlock0.firefox.xpi` or `/uBlock/dist/build/uBlock0.webext.xpi` into Firefox.
|
||||
|
||||
|
|
|
|||
2
dist/description/description-ca.txt
vendored
2
dist/description/description-ca.txt
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Un bloquejador eficient: el consum de memòria i de processador és baix però, no obstant això, pot carregar i aplicar milers de filtres més que altres bloquejadors coneguts.
|
||||
Un blocador eficient: Amb un consum discret de memòria i de processador, pot carregar i aplicar milers de filtres més que altres aplicacions semblants.
|
||||
|
||||
Gràfic de l'eficiència: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-efficiency-compared
|
||||
|
||||
|
|
|
|||
8
dist/description/description-sr.txt
vendored
8
dist/description/description-sr.txt
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Ефикасан блокатор: ниски процесорски и меморијски захтеви и може учитати и применити хиљаде филтера више него остали популарни блокатори.
|
||||
Ефикасан блокатор: ниски процесорски и меморијски захтеви а може учитати и применити хиљаде филтера више него остали популарни блокатори.
|
||||
|
||||
Илустровани преглед његове ефикасности: https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-efficiency-compared
|
||||
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
***
|
||||
|
||||
Флексибилан је, више је од блокатора реклама: може читати и стварати филтере из хост датотека.
|
||||
Флексибилан је, више је од блокатора реклама: може читати и креирати филтере из хост датотека.
|
||||
|
||||
Одмах по инсталирању, следећи спискови филтера су учитани и спроведени:
|
||||
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
***
|
||||
|
||||
Без предефинисаних спискова филтера, ово проширење је ништа. Тако да ако икад желите да допринесете нешто, размислите о људима који напорно раде одржавајући спискове филтера које користите и који су доступни за бесплатно коришћење свима.
|
||||
Без предефинисаних спискова филтера, ово проширење је ништа. Тако да ако икад желите да допринесете нечим, размислите о људима који напорно раде одржавајући спискове филтера које користите и који су доступни за бесплатно коришћење свима.
|
||||
|
||||
***
|
||||
|
||||
|
|
@ -45,5 +45,5 @@
|
|||
|
||||
Ово је рана верзија, имајте то на уму када будете оцењивали.
|
||||
|
||||
Листа измена:
|
||||
Евиденција промена:
|
||||
https://github.com/gorhill/uBlock/releases
|
||||
|
|
|
|||
14
dist/description/description-tr.txt
vendored
14
dist/description/description-tr.txt
vendored
|
|
@ -1,13 +1,13 @@
|
|||
Etkili bir engelleyici: Belleği ve işlemciyi yormaz, yine de diğer popüler engelleyicilere göre binlerce daha fazla süzgeci yükleyip uygulayabilir.
|
||||
Etkili bir engelleyici: Belleği ve işlemciyi yormaz, yine de diğer popüler engelleyicilere göre binlerce daha çok süzgeci yükleyip uygulayabilir.
|
||||
|
||||
Verimliliğine örneklendirilmiş genel bakış:
|
||||
https://github.com/gorhill/uBlock/wiki/uBlock-vs.-ABP:-efficiency-compared
|
||||
|
||||
Kullanımı: Arayüzdeki büyük güç düğmesi mevcut web sitesinde uBlock'u kalıcı olarak etkisiz/etkin kılmak içindir. Bu yalnızca mevcut web sitesine uygulanır, evrensel bir güç düğmesi değildir.
|
||||
Kullanımı: Arayüzdeki büyük güç düğmesi o anki web sitesinde, uBlock'u kalıcı olarak devre dışı bırakmak/etkinleştirmek içindir. Bu yalnızca o anki web sitesine uygulanır, evrensel bir güç düğmesi değildir.
|
||||
|
||||
***
|
||||
|
||||
Esnek, bir "reklam engelleyici"den daha fazlası: Alan adları dosyalarınızdan süzgeçleri okuyabilir ve oluşturabilir.
|
||||
Esnek, bir "reklam engelleyici"den daha fazlası: Ayrıca alan adları dosyalarınızdan süzgeçleri okuyabilir ve oluşturabilir.
|
||||
|
||||
Hazır olarak şu süzgeç listeleri yüklüdür ve uygulanır:
|
||||
|
||||
|
|
@ -23,21 +23,21 @@ Hazır olarak şu süzgeç listeleri yüklüdür ve uygulanır:
|
|||
- hpHosts'un Reklam ve izleyici sunucuları
|
||||
- MVPS HOSTS
|
||||
- Spam404
|
||||
- Ve daha birçoğu
|
||||
- Ve daha başkaları
|
||||
|
||||
Tabii ki, daha fazla süzgeç etkinleştirildikçe, bellek kullanımı da yükselir. Ama, Fanboy'un iki ekstra listesi, hpHosts'un reklam ve izleyici sunucuları ekledikten sonra dahi uBlock diğer oldukça popüler olan engelleyicilere göre daha az bellek kullanır.
|
||||
Elbette, daha çok süzgeç etkinleştirildikçe, bellek kullanımı da artar. Yine de, Fanboy'un iki ekstra listesi, hpHosts'un reklam ve izleyici sunucuları ekledikten sonra bile uBlock diğer oldukça popüler engelleyicilere göre daha az bellek kullanır.
|
||||
|
||||
Ayrıca, bazı ekstra listelerin seçilmesinin web sitelerinin bozulması olasılığını artırabileceğini unutmayın -- özellikle normalde alan adları dosyası olarak kullanılan listelerin.
|
||||
|
||||
***
|
||||
|
||||
Ön yüklü gelen süzgeç listeleri olmadan, bu eklenti hiçbir işe yaramaz. Eğer gerçekten bir şekilde katkıda bulunmak isterseniz, herkes tarafından özgürce kullanıma imkan veren, kullandığınız süzgeç listelerini oluşturmak için uğraşan insanları düşünün.
|
||||
Ön yüklü gelen süzgeç listeleri olmadan, bu eklenti bir işe yaramaz. Bu yüzden, gerçekten bir şekilde katkıda bulunmak isterseniz, herkesin özgürce kullanması için sunulan kullandığınız süzgeç listelerini oluşturmak için uğraşan insanları düşünün.
|
||||
|
||||
***
|
||||
|
||||
Özgür.
|
||||
Açık kaynak kamu lisanslı (GPLv3)
|
||||
Kullanıcılar tarafından kullanıcılar için.
|
||||
Kullanıcılardan kullanıcılara.
|
||||
|
||||
Katkıda bulunanlar @ Github: https://github.com/gorhill/uBlock/graphs/contributors
|
||||
Katkıda bulunanlar @ Crowdin: https://crowdin.net/project/ublock
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<script async src="js/is-webrtc-supported.js"></script>
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
|
||||
"name": "uBlock Origin",
|
||||
"version": "1.13.4",
|
||||
"version": "1.14.8",
|
||||
|
||||
"commands": {
|
||||
"launch-element-zapper": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="js/vapi-client.js"></script>
|
||||
<script src="js/options_ui.js"></script>
|
||||
<title></title>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,22 @@ var noopFunc = function(){};
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
if (
|
||||
typeof browser === 'object' &&
|
||||
browser !== null &&
|
||||
browser.runtime instanceof Object &&
|
||||
typeof browser.runtime.getBrowserInfo === 'function'
|
||||
) {
|
||||
browser.runtime.getBrowserInfo().then(function(info) {
|
||||
vAPI.supportsUserStylesheets =
|
||||
info.name === 'Firefox' &&
|
||||
parseInt(info.version, 10) > 52;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.app = {
|
||||
name: manifest.name,
|
||||
version: manifest.version
|
||||
|
|
@ -327,7 +343,9 @@ vAPI.tabs.registerListeners = function() {
|
|||
};
|
||||
|
||||
var onActivated = function(details) {
|
||||
vAPI.contextMenu.onMustUpdate(details.tabId);
|
||||
if ( vAPI.contextMenu instanceof Object ) {
|
||||
vAPI.contextMenu.onMustUpdate(details.tabId);
|
||||
}
|
||||
};
|
||||
|
||||
var onUpdated = function(tabId, changeInfo, tab) {
|
||||
|
|
@ -478,12 +496,12 @@ vAPI.tabs.open = function(details) {
|
|||
var targetURLWithoutHash = pos === -1 ? targetURL : targetURL.slice(0, pos);
|
||||
|
||||
chrome.tabs.query({ url: targetURLWithoutHash }, function(tabs) {
|
||||
var tab = tabs[0];
|
||||
if ( chrome.runtime.lastError ) { /* noop */ }
|
||||
var tab = Array.isArray(tabs) && tabs[0];
|
||||
if ( !tab ) {
|
||||
wrapper();
|
||||
return;
|
||||
}
|
||||
|
||||
var _details = {
|
||||
active: true,
|
||||
url: undefined
|
||||
|
|
@ -608,32 +626,71 @@ vAPI.tabs.injectScript = function(tabId, details, callback) {
|
|||
// Since we may be called asynchronously, the tab id may not exist
|
||||
// anymore, so this ensures it does still exist.
|
||||
|
||||
vAPI.setIcon = function(tabId, iconStatus, badge) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
if ( tabId === 0 ) {
|
||||
return;
|
||||
}
|
||||
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/browserAction#Browser_compatibility
|
||||
// Firefox for Android does no support browser.browserAction.setIcon().
|
||||
|
||||
var onIconReady = function() {
|
||||
if ( vAPI.lastError() ) {
|
||||
return;
|
||||
vAPI.setIcon = (function() {
|
||||
var browserAction = chrome.browserAction,
|
||||
titleTemplate = chrome.runtime.getManifest().name + ' ({badge})';
|
||||
var iconPaths = [
|
||||
{
|
||||
'19': 'img/browsericons/icon19-off.png',
|
||||
'38': 'img/browsericons/icon38-off.png'
|
||||
},
|
||||
{
|
||||
'19': 'img/browsericons/icon19.png',
|
||||
'38': 'img/browsericons/icon38.png'
|
||||
}
|
||||
chrome.browserAction.setBadgeText({ tabId: tabId, text: badge });
|
||||
if ( badge !== '' ) {
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
];
|
||||
|
||||
return function(tabId, iconStatus, badge) {
|
||||
tabId = toChromiumTabId(tabId);
|
||||
if ( tabId === 0 ) { return; }
|
||||
|
||||
if ( browserAction.setIcon !== undefined ) {
|
||||
browserAction.setIcon(
|
||||
{
|
||||
tabId: tabId,
|
||||
path: iconPaths[iconStatus === 'on' ? 1 : 0]
|
||||
},
|
||||
function onIconReady() {
|
||||
if ( vAPI.lastError() ) { return; }
|
||||
chrome.browserAction.setBadgeText({
|
||||
tabId: tabId,
|
||||
text: badge
|
||||
});
|
||||
if ( badge !== '' ) {
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
tabId: tabId,
|
||||
color: '#666'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ( browserAction.setTitle !== undefined ) {
|
||||
browserAction.setTitle({
|
||||
tabId: tabId,
|
||||
color: '#666'
|
||||
title: titleTemplate.replace(
|
||||
'{badge}',
|
||||
iconStatus === 'on' ? (badge !== '' ? badge : '0') : 'off'
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
if ( vAPI.contextMenu instanceof Object ) {
|
||||
vAPI.contextMenu.onMustUpdate(tabId);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
var iconPaths = iconStatus === 'on' ?
|
||||
{ '19': 'img/browsericons/icon19.png', '38': 'img/browsericons/icon38.png' } :
|
||||
{ '19': 'img/browsericons/icon19-off.png', '38': 'img/browsericons/icon38-off.png' };
|
||||
|
||||
chrome.browserAction.setIcon({ tabId: tabId, path: iconPaths }, onIconReady);
|
||||
vAPI.contextMenu.onMustUpdate(tabId);
|
||||
};
|
||||
chrome.browserAction.onClicked.addListener(function(tab) {
|
||||
vAPI.tabs.open({
|
||||
select: true,
|
||||
url: 'popup.html?tabId=' + tab.id + '&mobile=1'
|
||||
});
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
|
@ -655,8 +712,8 @@ vAPI.messaging.listen = function(listenerName, callback) {
|
|||
/******************************************************************************/
|
||||
|
||||
vAPI.messaging.onPortMessage = (function() {
|
||||
var messaging = vAPI.messaging;
|
||||
var toAuxPending = {};
|
||||
var messaging = vAPI.messaging,
|
||||
toAuxPending = {};
|
||||
|
||||
// Use a wrapper to avoid closure and to allow reuse.
|
||||
var CallbackWrapper = function(port, request, timeout) {
|
||||
|
|
@ -703,8 +760,8 @@ vAPI.messaging.onPortMessage = (function() {
|
|||
};
|
||||
|
||||
var toAux = function(details, portFrom) {
|
||||
var port, portTo;
|
||||
var chromiumTabId = toChromiumTabId(details.toTabId);
|
||||
var port, portTo,
|
||||
chromiumTabId = toChromiumTabId(details.toTabId);
|
||||
|
||||
// TODO: This could be an issue with a lot of tabs: easy to address
|
||||
// with a port name to tab id map.
|
||||
|
|
@ -761,6 +818,32 @@ vAPI.messaging.onPortMessage = (function() {
|
|||
wrapper.callback(details.msg);
|
||||
};
|
||||
|
||||
var toFramework = function(msg, sender) {
|
||||
var tabId = sender && sender.tab && sender.tab.id;
|
||||
if ( !tabId ) { return; }
|
||||
switch ( msg.what ) {
|
||||
case 'userCSS':
|
||||
var details = {
|
||||
code: undefined,
|
||||
frameId: sender.frameId,
|
||||
matchAboutBlank: true
|
||||
};
|
||||
if ( vAPI.supportsUserStylesheets === true ) {
|
||||
details.cssOrigin = 'user';
|
||||
}
|
||||
if ( msg.toRemove ) {
|
||||
details.code = msg.toRemove;
|
||||
chrome.tabs.removeCSS(tabId, details);
|
||||
}
|
||||
if ( msg.toAdd ) {
|
||||
details.code = msg.toAdd;
|
||||
details.runAt = 'document_start';
|
||||
chrome.tabs.insertCSS(tabId, details);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return function(request, port) {
|
||||
// Auxiliary process to auxiliary process
|
||||
if ( request.toTabId !== undefined ) {
|
||||
|
|
@ -774,6 +857,13 @@ vAPI.messaging.onPortMessage = (function() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Content process to main process: framework handler.
|
||||
// No callback supported/needed for now.
|
||||
if ( request.channelName === 'vapi-background' ) {
|
||||
toFramework(request.msg, port.sender);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auxiliary process to main process: prepare response
|
||||
var callback = messaging.NOOPFUNC;
|
||||
if ( request.auxProcessId !== undefined ) {
|
||||
|
|
@ -781,8 +871,8 @@ vAPI.messaging.onPortMessage = (function() {
|
|||
}
|
||||
|
||||
// Auxiliary process to main process: specific handler
|
||||
var r = messaging.UNHANDLED;
|
||||
var listener = messaging.listeners[request.channelName];
|
||||
var r = messaging.UNHANDLED,
|
||||
listener = messaging.listeners[request.channelName];
|
||||
if ( typeof listener === 'function' ) {
|
||||
r = listener(request.msg, port.sender, callback);
|
||||
}
|
||||
|
|
@ -856,296 +946,10 @@ vAPI.messaging.broadcast = function(message) {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net = {};
|
||||
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contextMenus#Browser_compatibility
|
||||
// Firefox for Android does no support browser.contextMenus.
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net.registerListeners = function() {
|
||||
var µb = µBlock,
|
||||
µburi = µb.URI,
|
||||
wrApi = chrome.webRequest;
|
||||
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=410382
|
||||
// Between Chromium 38-48, plug-ins' network requests were reported as
|
||||
// type "other" instead of "object".
|
||||
var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent);
|
||||
|
||||
// legacy Chromium understands only these network request types.
|
||||
var validTypes = {
|
||||
main_frame: true,
|
||||
sub_frame: true,
|
||||
stylesheet: true,
|
||||
script: true,
|
||||
image: true,
|
||||
object: true,
|
||||
xmlhttprequest: true,
|
||||
other: true
|
||||
};
|
||||
// modern Chromium/WebExtensions: more types available.
|
||||
if ( wrApi.ResourceType ) {
|
||||
(function() {
|
||||
for ( var typeKey in wrApi.ResourceType ) {
|
||||
if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) {
|
||||
validTypes[wrApi.ResourceType[typeKey]] = true;
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
var extToTypeMap = new Map([
|
||||
['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'],
|
||||
['mp3','media'],['mp4','media'],['webm','media'],
|
||||
['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image']
|
||||
]);
|
||||
|
||||
var denormalizeTypes = function(aa) {
|
||||
if ( aa.length === 0 ) {
|
||||
return Object.keys(validTypes);
|
||||
}
|
||||
var out = [];
|
||||
var i = aa.length,
|
||||
type,
|
||||
needOther = true;
|
||||
while ( i-- ) {
|
||||
type = aa[i];
|
||||
if ( validTypes[type] ) {
|
||||
out.push(type);
|
||||
}
|
||||
if ( type === 'other' ) {
|
||||
needOther = false;
|
||||
}
|
||||
}
|
||||
if ( needOther ) {
|
||||
out.push('other');
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
var headerValue = function(headers, name) {
|
||||
var i = headers.length;
|
||||
while ( i-- ) {
|
||||
if ( headers[i].name.toLowerCase() === name ) {
|
||||
return headers[i].value.trim();
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
var normalizeRequestDetails = function(details) {
|
||||
details.tabId = details.tabId.toString();
|
||||
|
||||
var type = details.type;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1493
|
||||
// Chromium 49+/WebExtensions support a new request type: `ping`,
|
||||
// which is fired as a result of using `navigator.sendBeacon`.
|
||||
if ( type === 'ping' ) {
|
||||
details.type = 'beacon';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type === 'imageset' ) {
|
||||
details.type = 'image';
|
||||
return;
|
||||
}
|
||||
|
||||
// The rest of the function code is to normalize type
|
||||
if ( type !== 'other' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to map known "extension" part of URL to request type.
|
||||
var path = µburi.pathFromURI(details.url),
|
||||
pos = path.indexOf('.', path.length - 6);
|
||||
if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) {
|
||||
details.type = type;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to extract type from response headers if present.
|
||||
if ( details.responseHeaders ) {
|
||||
type = headerValue(details.responseHeaders, 'content-type');
|
||||
if ( type.startsWith('font/') ) {
|
||||
details.type = 'font';
|
||||
return;
|
||||
}
|
||||
if ( type.startsWith('image/') ) {
|
||||
details.type = 'image';
|
||||
return;
|
||||
}
|
||||
if ( type.startsWith('audio/') || type.startsWith('video/') ) {
|
||||
details.type = 'media';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/862
|
||||
// If no transposition possible, transpose to `object` as per
|
||||
// Chromium bug 410382
|
||||
// https://code.google.com/p/chromium/issues/detail?id=410382
|
||||
if ( is_v38_48 ) {
|
||||
details.type = 'object';
|
||||
}
|
||||
};
|
||||
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=129353
|
||||
// https://github.com/gorhill/uBlock/issues/1497
|
||||
// Expose websocket-based network requests to uBO's filtering engine,
|
||||
// logger, etc.
|
||||
// Counterpart of following block of code is found in "vapi-client.js" --
|
||||
// search for "https://github.com/gorhill/uBlock/issues/1497".
|
||||
//
|
||||
// Once uBO 1.11.1 and uBO-Extra 2.12 are widespread, the image-based
|
||||
// handling code can be removed.
|
||||
var onBeforeWebsocketRequest = function(details) {
|
||||
if ( (details.type !== 'image') &&
|
||||
(details.method !== 'HEAD' || details.type !== 'xmlhttprequest')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
var requestURL = details.url,
|
||||
matches = /[?&]u(?:rl)?=([^&]+)/.exec(requestURL);
|
||||
if ( matches === null ) { return; }
|
||||
details.type = 'websocket';
|
||||
details.url = decodeURIComponent(matches[1]);
|
||||
var r = onBeforeRequestClient(details);
|
||||
if ( r && r.cancel ) { return r; }
|
||||
// Redirect to the provided URL, or a 1x1 data: URI if none provided.
|
||||
matches = /[?&]r=([^&]+)/.exec(requestURL);
|
||||
return {
|
||||
redirectUrl: matches !== null ?
|
||||
decodeURIComponent(matches[1]) :
|
||||
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
|
||||
};
|
||||
};
|
||||
|
||||
var onBeforeRequestClient = this.onBeforeRequest.callback;
|
||||
var onBeforeRequest = validTypes.websocket
|
||||
// modern Chromium/WebExtensions: type 'websocket' is supported
|
||||
? function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeRequestClient(details);
|
||||
}
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
// https://github.com/gorhill/uBlock/issues/1497
|
||||
if ( details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') ) {
|
||||
var r = onBeforeWebsocketRequest(details);
|
||||
if ( r !== undefined ) { return r; }
|
||||
}
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeRequestClient(details);
|
||||
};
|
||||
|
||||
// This is needed for Chromium 49-55.
|
||||
var onBeforeSendHeaders = validTypes.csp_report
|
||||
// modern Chromium/WebExtensions: type 'csp_report' is supported
|
||||
? null
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
if ( details.type !== 'ping' || details.method !== 'POST' ) { return; }
|
||||
var type = headerValue(details.requestHeaders, 'content-type');
|
||||
if ( type === '' ) { return; }
|
||||
if ( type.endsWith('/csp-report') ) {
|
||||
details.type = 'csp_report';
|
||||
return onBeforeRequestClient(details);
|
||||
}
|
||||
};
|
||||
|
||||
var onHeadersReceivedClient = this.onHeadersReceived.callback,
|
||||
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
|
||||
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
|
||||
var onHeadersReceived = validTypes.font
|
||||
// modern Chromium/WebExtensions: type 'font' is supported
|
||||
? function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
if (
|
||||
onHeadersReceivedClientTypes.length !== 0 &&
|
||||
onHeadersReceivedClientTypes.indexOf(details.type) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return onHeadersReceivedClient(details);
|
||||
}
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
// Hack to work around Chromium API limitations, where requests of
|
||||
// type `font` are returned as `other`. For example, our normalization
|
||||
// fail at transposing `other` into `font` for URLs which are outside
|
||||
// what is expected. At least when headers are received we can check
|
||||
// for content type `font/*`. Blocking at onHeadersReceived time is
|
||||
// less worse than not blocking at all. Also, due to Chromium bug,
|
||||
// `other` always becomes `object` when it can't be normalized into
|
||||
// something else. Test case for "unfriendly" font URLs:
|
||||
// https://www.google.com/fonts
|
||||
if ( details.type === 'font' ) {
|
||||
var r = onBeforeRequestClient(details);
|
||||
if ( typeof r === 'object' && r.cancel === true ) {
|
||||
return { cancel: true };
|
||||
}
|
||||
}
|
||||
if (
|
||||
onHeadersReceivedClientTypes.length !== 0 &&
|
||||
onHeadersReceivedClientTypes.indexOf(details.type) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return onHeadersReceivedClient(details);
|
||||
};
|
||||
|
||||
var urls, types;
|
||||
|
||||
if ( onBeforeRequest ) {
|
||||
urls = this.onBeforeRequest.urls || ['<all_urls>'];
|
||||
types = this.onBeforeRequest.types || undefined;
|
||||
if (
|
||||
(validTypes.websocket) &&
|
||||
(types === undefined || types.indexOf('websocket') !== -1) &&
|
||||
(urls.indexOf('<all_urls>') === -1)
|
||||
) {
|
||||
if ( urls.indexOf('ws://*/*') === -1 ) {
|
||||
urls.push('ws://*/*');
|
||||
}
|
||||
if ( urls.indexOf('wss://*/*') === -1 ) {
|
||||
urls.push('wss://*/*');
|
||||
}
|
||||
}
|
||||
wrApi.onBeforeRequest.addListener(
|
||||
onBeforeRequest,
|
||||
{ urls: urls, types: types },
|
||||
this.onBeforeRequest.extra
|
||||
);
|
||||
}
|
||||
|
||||
// Chromium 48 and lower does not support `ping` type.
|
||||
// Chromium 56 and higher does support `csp_report` stype.
|
||||
if ( onBeforeSendHeaders ) {
|
||||
wrApi.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeaders,
|
||||
{
|
||||
'urls': [ '<all_urls>' ],
|
||||
'types': [ 'ping' ]
|
||||
},
|
||||
[ 'blocking', 'requestHeaders' ]
|
||||
);
|
||||
}
|
||||
|
||||
if ( onHeadersReceived ) {
|
||||
urls = this.onHeadersReceived.urls || ['<all_urls>'];
|
||||
types = onHeadersReceivedTypes;
|
||||
wrApi.onHeadersReceived.addListener(
|
||||
onHeadersReceived,
|
||||
{ urls: urls, types: types },
|
||||
this.onHeadersReceived.extra
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.contextMenu = {
|
||||
vAPI.contextMenu = chrome.contextMenus && {
|
||||
_callback: null,
|
||||
_entries: [],
|
||||
_createEntry: function(entry) {
|
||||
|
|
@ -1271,7 +1075,7 @@ vAPI.punycodeURL = function(url) {
|
|||
// https://github.com/gorhill/uBlock/issues/900
|
||||
// Also, UC Browser: http://www.upsieutoc.com/image/WXuH
|
||||
|
||||
vAPI.adminStorage = {
|
||||
vAPI.adminStorage = chrome.storage.managed && {
|
||||
getItem: function(key, callback) {
|
||||
var onRead = function(store) {
|
||||
var data;
|
||||
|
|
@ -1317,7 +1121,7 @@ vAPI.cloud = (function() {
|
|||
|
||||
var options = {
|
||||
defaultDeviceName: window.navigator.platform,
|
||||
deviceName: window.localStorage.getItem('deviceName') || ''
|
||||
deviceName: vAPI.localStorage.getItem('deviceName') || ''
|
||||
};
|
||||
|
||||
// This is used to find out a rough count of how many chunks exists:
|
||||
|
|
@ -1461,7 +1265,7 @@ vAPI.cloud = (function() {
|
|||
}
|
||||
|
||||
if ( typeof details.deviceName === 'string' ) {
|
||||
window.localStorage.setItem('deviceName', details.deviceName);
|
||||
vAPI.localStorage.setItem('deviceName', details.deviceName);
|
||||
options.deviceName = details.deviceName;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,70 +72,6 @@ if ( vAPI.sessionId ) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var referenceCounter = 0;
|
||||
|
||||
vAPI.lock = function() {
|
||||
referenceCounter += 1;
|
||||
};
|
||||
|
||||
vAPI.unlock = function() {
|
||||
referenceCounter -= 1;
|
||||
if ( referenceCounter === 0 ) {
|
||||
// Eventually there will be code here to flush the javascript code
|
||||
// from this file out of memory when it ends up unused.
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.executionCost = {
|
||||
start: function(){},
|
||||
stop: function(){}
|
||||
};
|
||||
/*
|
||||
vAPI.executionCost = {
|
||||
tcost: 0,
|
||||
tstart: 0,
|
||||
nstart: 0,
|
||||
level: 1,
|
||||
start: function() {
|
||||
if ( this.nstart === 0 ) {
|
||||
this.tstart = window.performance.now();
|
||||
}
|
||||
this.nstart += 1;
|
||||
},
|
||||
stop: function(mark) {
|
||||
this.nstart -= 1;
|
||||
if ( this.nstart !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var tcost = window.performance.now() - this.tstart;
|
||||
this.tcost += tcost;
|
||||
if ( mark === undefined ) {
|
||||
return;
|
||||
}
|
||||
var top = window === window.top;
|
||||
if ( !top && this.level < 2 ) {
|
||||
return;
|
||||
}
|
||||
var context = window === window.top ? ' top' : 'frame';
|
||||
var percent = this.tcost / window.performance.now() * 100;
|
||||
console.log(
|
||||
'uBO cost (%s): %sms/%s%% (%s: %sms)',
|
||||
context,
|
||||
this.tcost.toFixed(1),
|
||||
percent.toFixed(1),
|
||||
mark,
|
||||
tcost.toFixed(2)
|
||||
);
|
||||
}
|
||||
};
|
||||
*/
|
||||
vAPI.executionCost.start();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.randomToken = function() {
|
||||
return String.fromCharCode(Date.now() % 26 + 97) +
|
||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
||||
|
|
@ -412,8 +348,6 @@ vAPI.shutdown.add(function() {
|
|||
// https://www.youtube.com/watch?v=rT5zCHn0tsg
|
||||
// https://www.youtube.com/watch?v=E-jS4e3zacI
|
||||
|
||||
vAPI.executionCost.stop('vapi-client.js');
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -67,12 +67,6 @@ vAPI.download = function(details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.insertHTML = function(node, html) {
|
||||
node.innerHTML = html;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.getURL = chrome.runtime.getURL;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -100,6 +94,26 @@ try {
|
|||
} catch (ex) {
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2824
|
||||
// Use a dummy localStorage if for some reasons it's not available.
|
||||
if ( vAPI.localStorage instanceof Object === false ) {
|
||||
vAPI.localStorage = {
|
||||
length: 0,
|
||||
clear: function() {
|
||||
},
|
||||
getItem: function() {
|
||||
return null;
|
||||
},
|
||||
key: function() {
|
||||
throw new RangeError();
|
||||
},
|
||||
removeItem: function() {
|
||||
},
|
||||
setItem: function() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})(this);
|
||||
|
|
|
|||
313
platform/chromium/vapi-webrequest.js
Normal file
313
platform/chromium/vapi-webrequest.js
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2017 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
|
||||
*/
|
||||
|
||||
// For background page
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net = {};
|
||||
|
||||
vAPI.net.registerListeners = function() {
|
||||
|
||||
var µb = µBlock,
|
||||
µburi = µb.URI,
|
||||
wrApi = chrome.webRequest;
|
||||
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=410382
|
||||
// Between Chromium 38-48, plug-ins' network requests were reported as
|
||||
// type "other" instead of "object".
|
||||
var is_v38_48 = /\bChrom[a-z]+\/(?:3[89]|4[0-8])\.[\d.]+\b/.test(navigator.userAgent);
|
||||
|
||||
// legacy Chromium understands only these network request types.
|
||||
var validTypes = {
|
||||
main_frame: true,
|
||||
sub_frame: true,
|
||||
stylesheet: true,
|
||||
script: true,
|
||||
image: true,
|
||||
object: true,
|
||||
xmlhttprequest: true,
|
||||
other: true
|
||||
};
|
||||
// modern Chromium/WebExtensions: more types available.
|
||||
if ( wrApi.ResourceType ) {
|
||||
(function() {
|
||||
for ( var typeKey in wrApi.ResourceType ) {
|
||||
if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) {
|
||||
validTypes[wrApi.ResourceType[typeKey]] = true;
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
var extToTypeMap = new Map([
|
||||
['eot','font'],['otf','font'],['svg','font'],['ttf','font'],['woff','font'],['woff2','font'],
|
||||
['mp3','media'],['mp4','media'],['webm','media'],
|
||||
['gif','image'],['ico','image'],['jpeg','image'],['jpg','image'],['png','image'],['webp','image']
|
||||
]);
|
||||
|
||||
var denormalizeTypes = function(aa) {
|
||||
if ( aa.length === 0 ) {
|
||||
return Object.keys(validTypes);
|
||||
}
|
||||
var out = [];
|
||||
var i = aa.length,
|
||||
type,
|
||||
needOther = true;
|
||||
while ( i-- ) {
|
||||
type = aa[i];
|
||||
if ( validTypes[type] ) {
|
||||
out.push(type);
|
||||
}
|
||||
if ( type === 'other' ) {
|
||||
needOther = false;
|
||||
}
|
||||
}
|
||||
if ( needOther ) {
|
||||
out.push('other');
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
var headerValue = function(headers, name) {
|
||||
var i = headers.length;
|
||||
while ( i-- ) {
|
||||
if ( headers[i].name.toLowerCase() === name ) {
|
||||
return headers[i].value.trim();
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
var normalizeRequestDetails = function(details) {
|
||||
details.tabId = details.tabId.toString();
|
||||
|
||||
var type = details.type;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1493
|
||||
// Chromium 49+/WebExtensions support a new request type: `ping`,
|
||||
// which is fired as a result of using `navigator.sendBeacon`.
|
||||
if ( type === 'ping' ) {
|
||||
details.type = 'beacon';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type === 'imageset' ) {
|
||||
details.type = 'image';
|
||||
return;
|
||||
}
|
||||
|
||||
// The rest of the function code is to normalize type
|
||||
if ( type !== 'other' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to map known "extension" part of URL to request type.
|
||||
var path = µburi.pathFromURI(details.url),
|
||||
pos = path.indexOf('.', path.length - 6);
|
||||
if ( pos !== -1 && (type = extToTypeMap.get(path.slice(pos + 1))) ) {
|
||||
details.type = type;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to extract type from response headers if present.
|
||||
if ( details.responseHeaders ) {
|
||||
type = headerValue(details.responseHeaders, 'content-type');
|
||||
if ( type.startsWith('font/') ) {
|
||||
details.type = 'font';
|
||||
return;
|
||||
}
|
||||
if ( type.startsWith('image/') ) {
|
||||
details.type = 'image';
|
||||
return;
|
||||
}
|
||||
if ( type.startsWith('audio/') || type.startsWith('video/') ) {
|
||||
details.type = 'media';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/862
|
||||
// If no transposition possible, transpose to `object` as per
|
||||
// Chromium bug 410382
|
||||
// https://code.google.com/p/chromium/issues/detail?id=410382
|
||||
if ( is_v38_48 ) {
|
||||
details.type = 'object';
|
||||
}
|
||||
};
|
||||
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=129353
|
||||
// https://github.com/gorhill/uBlock/issues/1497
|
||||
// Expose websocket-based network requests to uBO's filtering engine,
|
||||
// logger, etc.
|
||||
// Counterpart of following block of code is found in "vapi-client.js" --
|
||||
// search for "https://github.com/gorhill/uBlock/issues/1497".
|
||||
//
|
||||
// Once uBO 1.11.1 and uBO-Extra 2.12 are widespread, the image-based
|
||||
// handling code can be removed.
|
||||
var onBeforeWebsocketRequest = function(details) {
|
||||
if ( (details.type !== 'image') &&
|
||||
(details.method !== 'HEAD' || details.type !== 'xmlhttprequest')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
var requestURL = details.url,
|
||||
matches = /[?&]u(?:rl)?=([^&]+)/.exec(requestURL);
|
||||
if ( matches === null ) { return; }
|
||||
details.type = 'websocket';
|
||||
details.url = decodeURIComponent(matches[1]);
|
||||
var r = onBeforeRequestClient(details);
|
||||
if ( r && r.cancel ) { return r; }
|
||||
// Redirect to the provided URL, or a 1x1 data: URI if none provided.
|
||||
matches = /[?&]r=([^&]+)/.exec(requestURL);
|
||||
return {
|
||||
redirectUrl: matches !== null ?
|
||||
decodeURIComponent(matches[1]) :
|
||||
'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
|
||||
};
|
||||
};
|
||||
|
||||
var onBeforeRequestClient = this.onBeforeRequest.callback;
|
||||
var onBeforeRequest = validTypes.websocket
|
||||
// modern Chromium/WebExtensions: type 'websocket' is supported
|
||||
? function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeRequestClient(details);
|
||||
}
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
// https://github.com/gorhill/uBlock/issues/1497
|
||||
if ( details.url.endsWith('ubofix=f41665f3028c7fd10eecf573336216d3') ) {
|
||||
var r = onBeforeWebsocketRequest(details);
|
||||
if ( r !== undefined ) { return r; }
|
||||
}
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeRequestClient(details);
|
||||
};
|
||||
|
||||
// This is needed for Chromium 49-55.
|
||||
var onBeforeSendHeaders = validTypes.csp_report
|
||||
// modern Chromium/WebExtensions: type 'csp_report' is supported
|
||||
? null
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
if ( details.type !== 'ping' || details.method !== 'POST' ) { return; }
|
||||
var type = headerValue(details.requestHeaders, 'content-type');
|
||||
if ( type === '' ) { return; }
|
||||
if ( type.endsWith('/csp-report') ) {
|
||||
details.type = 'csp_report';
|
||||
return onBeforeRequestClient(details);
|
||||
}
|
||||
};
|
||||
|
||||
var onHeadersReceivedClient = this.onHeadersReceived.callback,
|
||||
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
|
||||
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
|
||||
var onHeadersReceived = validTypes.font
|
||||
// modern Chromium/WebExtensions: type 'font' is supported
|
||||
? function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
if (
|
||||
onHeadersReceivedClientTypes.length !== 0 &&
|
||||
onHeadersReceivedClientTypes.indexOf(details.type) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return onHeadersReceivedClient(details);
|
||||
}
|
||||
// legacy Chromium
|
||||
: function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
// Hack to work around Chromium API limitations, where requests of
|
||||
// type `font` are returned as `other`. For example, our normalization
|
||||
// fail at transposing `other` into `font` for URLs which are outside
|
||||
// what is expected. At least when headers are received we can check
|
||||
// for content type `font/*`. Blocking at onHeadersReceived time is
|
||||
// less worse than not blocking at all. Also, due to Chromium bug,
|
||||
// `other` always becomes `object` when it can't be normalized into
|
||||
// something else. Test case for "unfriendly" font URLs:
|
||||
// https://www.google.com/fonts
|
||||
if ( details.type === 'font' ) {
|
||||
var r = onBeforeRequestClient(details);
|
||||
if ( typeof r === 'object' && r.cancel === true ) {
|
||||
return { cancel: true };
|
||||
}
|
||||
}
|
||||
if (
|
||||
onHeadersReceivedClientTypes.length !== 0 &&
|
||||
onHeadersReceivedClientTypes.indexOf(details.type) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return onHeadersReceivedClient(details);
|
||||
};
|
||||
|
||||
var urls, types;
|
||||
|
||||
if ( onBeforeRequest ) {
|
||||
urls = this.onBeforeRequest.urls || ['<all_urls>'];
|
||||
types = this.onBeforeRequest.types || undefined;
|
||||
if (
|
||||
(validTypes.websocket) &&
|
||||
(types === undefined || types.indexOf('websocket') !== -1) &&
|
||||
(urls.indexOf('<all_urls>') === -1)
|
||||
) {
|
||||
if ( urls.indexOf('ws://*/*') === -1 ) {
|
||||
urls.push('ws://*/*');
|
||||
}
|
||||
if ( urls.indexOf('wss://*/*') === -1 ) {
|
||||
urls.push('wss://*/*');
|
||||
}
|
||||
}
|
||||
wrApi.onBeforeRequest.addListener(
|
||||
onBeforeRequest,
|
||||
{ urls: urls, types: types },
|
||||
this.onBeforeRequest.extra
|
||||
);
|
||||
}
|
||||
|
||||
// Chromium 48 and lower does not support `ping` type.
|
||||
// Chromium 56 and higher does support `csp_report` stype.
|
||||
if ( onBeforeSendHeaders ) {
|
||||
wrApi.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeaders,
|
||||
{
|
||||
'urls': [ '<all_urls>' ],
|
||||
'types': [ 'ping' ]
|
||||
},
|
||||
[ 'blocking', 'requestHeaders' ]
|
||||
);
|
||||
}
|
||||
|
||||
if ( onHeadersReceived ) {
|
||||
urls = this.onHeadersReceived.urls || ['<all_urls>'];
|
||||
types = onHeadersReceivedTypes;
|
||||
wrApi.onHeadersReceived.addListener(
|
||||
onHeadersReceived,
|
||||
{ urls: urls, types: types },
|
||||
this.onHeadersReceived.extra
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<Description>
|
||||
<em:id>{{ec8030f7-c20a-464f-9b0e-13a3a9e97384}}</em:id>
|
||||
<em:minVersion>24.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:maxVersion>57.0a1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<Description>
|
||||
<em:id>{{aa3c5121-dab2-40e2-81ca-7ea25febc110}}</em:id>
|
||||
<em:minVersion>27.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:maxVersion>57.0a1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
|
|
|||
|
|
@ -680,6 +680,12 @@ var winWatcher = (function() {
|
|||
if ( !win || windowToIdMap.delete(win) !== true ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/uBlockOrigin/uAssets/issues/567
|
||||
// We need to cleanup if and only if the window being closed is
|
||||
// the actual top window.
|
||||
if ( win.gBrowser && win.gBrowser.ownerGlobal !== win ) {
|
||||
return;
|
||||
}
|
||||
if ( typeof api.onCloseWindow === 'function' ) {
|
||||
api.onCloseWindow(win);
|
||||
}
|
||||
|
|
@ -3125,6 +3131,7 @@ vAPI.toolbarButton = {
|
|||
'#' + this.viewId + ',',
|
||||
'#' + this.viewId + ' > iframe {',
|
||||
'height: 290px;',
|
||||
'max-width: none !important;',
|
||||
'min-width: 0 !important;',
|
||||
'overflow: hidden !important;',
|
||||
'padding: 0 !important;',
|
||||
|
|
|
|||
|
|
@ -54,63 +54,6 @@ var vAPI = self.vAPI;
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var referenceCounter = 0;
|
||||
|
||||
vAPI.lock = function() {
|
||||
referenceCounter += 1;
|
||||
};
|
||||
|
||||
vAPI.unlock = function() {
|
||||
referenceCounter -= 1;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.executionCost = {
|
||||
start: function(){},
|
||||
stop: function(){}
|
||||
};
|
||||
/*
|
||||
vAPI.executionCost = vAPI.executionCost || {
|
||||
tcost: 0,
|
||||
tstart: 0,
|
||||
nstart: 0,
|
||||
level: 1,
|
||||
start: function() {
|
||||
if ( this.nstart === 0 ) {
|
||||
this.tstart = window.performance.now();
|
||||
}
|
||||
this.nstart += 1;
|
||||
},
|
||||
stop: function(mark) {
|
||||
this.nstart -= 1;
|
||||
if ( this.nstart !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var tcost = window.performance.now() - this.tstart;
|
||||
this.tcost += tcost;
|
||||
if ( mark === undefined ) {
|
||||
return;
|
||||
}
|
||||
var top = window === window.top;
|
||||
if ( !top && this.level < 2 ) {
|
||||
return;
|
||||
}
|
||||
var context = window === window.top ? ' top' : 'frame';
|
||||
var percent = this.tcost / window.performance.now() * 100;
|
||||
console.log(
|
||||
'uBO cost (' + context + '): ' +
|
||||
this.tcost.toFixed(1) + 'ms/' +
|
||||
percent.toFixed(1) + '% (' +
|
||||
mark + ': ' + tcost.toFixed(2) + 'ms)'
|
||||
);
|
||||
}
|
||||
};
|
||||
*/
|
||||
vAPI.executionCost.start();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.firefox = true;
|
||||
|
||||
vAPI.randomToken = function() {
|
||||
|
|
@ -498,10 +441,6 @@ if ( window !== window.top ) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.executionCost.stop('vapi-client.js');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
})(this);
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -75,30 +75,6 @@ vAPI.download = function(details) {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.insertHTML = (function() {
|
||||
const parser = Components.classes['@mozilla.org/parserutils;1']
|
||||
.getService(Components.interfaces.nsIParserUtils);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/845
|
||||
// Apparently dashboard pages execute with `about:blank` principal.
|
||||
|
||||
return function(node, html) {
|
||||
while ( node.firstChild ) {
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
|
||||
node.appendChild(parser.parseFragment(
|
||||
html,
|
||||
parser.SanitizerAllowStyle,
|
||||
false,
|
||||
Services.io.newURI('about:blank', null, null),
|
||||
document.documentElement
|
||||
));
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.getURL = function(path) {
|
||||
return 'chrome://' + location.host + '/content/' + path.replace(/^\/+/, '');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,5 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
|
||||
"name": "uBlock Origin",
|
||||
"version": "1.9.15.101",
|
||||
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_extShortDesc__",
|
||||
"icons": {
|
||||
"16": "img/icon_16.png",
|
||||
"128": "img/icon_128.png"
|
||||
},
|
||||
|
||||
"author": "All uBlock Origin contributors",
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"19": "img/browsericons/icon19.png",
|
||||
|
|
@ -19,11 +8,20 @@
|
|||
"default_title": "uBlock Origin",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
|
||||
"author": "All uBlock Origin contributors",
|
||||
"background": {
|
||||
"page": "background.html"
|
||||
},
|
||||
"commands": {
|
||||
"launch-element-zapper": {
|
||||
"description": "__MSG_popupTipZapper__"
|
||||
},
|
||||
"launch-element-picker": {
|
||||
"description": "__MSG_popupTipPicker__"
|
||||
},
|
||||
"launch-logger": {
|
||||
"description": "__MSG_popupTipLog__"
|
||||
}
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*"],
|
||||
|
|
@ -38,8 +36,16 @@
|
|||
"all_frames": false
|
||||
}
|
||||
],
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_extShortDesc__",
|
||||
"icons": {
|
||||
"16": "img/icon_16.png",
|
||||
"128": "img/icon_128.png"
|
||||
},
|
||||
"incognito": "split",
|
||||
"minimum_chrome_version": "38.0",
|
||||
"manifest_version": 2,
|
||||
"minimum_opera_version": "25.0",
|
||||
"name": "uBlock Origin",
|
||||
"optional_permissions": [ "file:///*" ],
|
||||
"options_page": "dashboard.html",
|
||||
"permissions": [
|
||||
|
|
@ -53,5 +59,6 @@
|
|||
"webRequestBlocking",
|
||||
"<all_urls>"
|
||||
],
|
||||
"short_name": "uBlock₀"
|
||||
"short_name": "uBlock₀",
|
||||
"version": "1.9.15.101"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
<script src="lib/publicsuffixlist.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-background.js"></script>
|
||||
<script src="js/vapi-cachestorage.js"></script><!-- Optional -->
|
||||
<script src="js/background.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/uritools.js"></script>
|
||||
|
|
|
|||
4
platform/webext/bootstrap.js
vendored
4
platform/webext/bootstrap.js
vendored
|
|
@ -29,8 +29,8 @@ const hostName = 'ublock0';
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
function startup({ webExtension }) {
|
||||
webExtension.startup().then(api => {
|
||||
function startup({ webExtension }, reason) {
|
||||
webExtension.startup(reason).then(api => {
|
||||
let { browser } = api,
|
||||
storageMigrator;
|
||||
let onMessage = function(message, sender, callback) {
|
||||
|
|
|
|||
|
|
@ -27,21 +27,31 @@
|
|||
|
||||
(function() {
|
||||
let µb = µBlock;
|
||||
let migratedKeys = new Set();
|
||||
let reCacheStorageKeys = /^(?:assetCacheRegistry|assetSourceRegistry|cache\/.+|selfie)$/;
|
||||
|
||||
let migrateAll = function(callback) {
|
||||
let mustRestart = false;
|
||||
|
||||
let migrateKeyValue = function(details, callback) {
|
||||
// https://github.com/gorhill/uBlock/issues/2653
|
||||
// Be ready to deal graciously with corrupted DB.
|
||||
if ( migratedKeys.has(details.key) ) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
migratedKeys.add(details.key);
|
||||
let bin = {};
|
||||
bin[details.key] = JSON.parse(details.value);
|
||||
self.browser.storage.local.set(bin, callback);
|
||||
mustRestart = true;
|
||||
if ( reCacheStorageKeys.test(details.key) ) {
|
||||
vAPI.cacheStorage.set(bin, callback);
|
||||
} else {
|
||||
vAPI.storage.set(bin, callback);
|
||||
}
|
||||
};
|
||||
|
||||
let migrateNext = function() {
|
||||
self.browser.runtime.sendMessage({ what: 'webext:storageMigrateNext' }, response => {
|
||||
if ( response.key === undefined ) {
|
||||
if ( mustRestart ) {
|
||||
if ( migratedKeys.size !== 0 ) {
|
||||
self.browser.runtime.reload();
|
||||
} else {
|
||||
callback();
|
||||
|
|
@ -57,7 +67,7 @@
|
|||
self.browser.runtime.sendMessage({ what: 'webext:storageMigrateDone' });
|
||||
return callback();
|
||||
}
|
||||
self.browser.storage.local.set({ legacyStorageMigrated: true });
|
||||
vAPI.storage.set({ legacyStorageMigrated: true });
|
||||
migrateNext();
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>uBlock0-webext@raymondhill.net</em:id>
|
||||
<em:id>uBlock0@raymondhill.net</em:id>
|
||||
<em:version>{version}</em:version>
|
||||
<em:name>{name}</em:name>
|
||||
<em:description>{description}</em:description>
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{{ec8030f7-c20a-464f-9b0e-13a3a9e97384}}</em:id>
|
||||
<em:minVersion>52.0a1</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:minVersion>54.0</em:minVersion>
|
||||
<em:maxVersion>56.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<Description>
|
||||
<em:id>{{aa3c5121-dab2-40e2-81ca-7ea25febc110}}</em:id>
|
||||
<em:minVersion>54.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:maxVersion>56.*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,84 +1,81 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
|
||||
"name": "uBlock Origin",
|
||||
"version": "1.9.15.101",
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "uBlock0@raymondhill.net",
|
||||
"strict_min_version": "52.0a1"
|
||||
}
|
||||
},
|
||||
|
||||
"commands": {
|
||||
"launch-element-zapper": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Z"
|
||||
},
|
||||
"description": "__MSG_popupTipZapper__"
|
||||
},
|
||||
"launch-element-picker": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+X"
|
||||
},
|
||||
"description": "__MSG_popupTipPicker__"
|
||||
},
|
||||
"launch-logger": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+L"
|
||||
},
|
||||
"description": "__MSG_popupTipLog__"
|
||||
}
|
||||
},
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_extShortDesc__",
|
||||
"icons": {
|
||||
"16": "img/icon_16.png",
|
||||
"128": "img/icon_128.png"
|
||||
},
|
||||
|
||||
"browser_action": {
|
||||
"browser_style": false,
|
||||
"default_icon": {
|
||||
"19": "img/browsericons/icon19.png",
|
||||
"38": "img/browsericons/icon38.png"
|
||||
},
|
||||
"default_title": "uBlock Origin",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
|
||||
"author": "All uBlock Origin contributors",
|
||||
"background": {
|
||||
"page": "background.html"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*"],
|
||||
"js": ["js/vapi-client.js", "js/contentscript.js"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
},
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*"],
|
||||
"js": ["js/scriptlets/subscriber.js"],
|
||||
"run_at": "document_idle",
|
||||
"all_frames": false
|
||||
}
|
||||
],
|
||||
"minimum_chrome_version": "26.0",
|
||||
"options_ui": {
|
||||
"page": "options_ui.html"
|
||||
},
|
||||
"permissions": [
|
||||
"contextMenus",
|
||||
"privacy",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"<all_urls>"
|
||||
],
|
||||
"short_name": "uBlock₀"
|
||||
"applications":{
|
||||
"gecko":{
|
||||
"id":"uBlock0@raymondhill.net",
|
||||
"strict_min_version":"52.0"
|
||||
}
|
||||
},
|
||||
"author":"All uBlock Origin contributors",
|
||||
"background":{
|
||||
"page":"background.html"
|
||||
},
|
||||
"browser_action":{
|
||||
"browser_style":false,
|
||||
"default_icon":{
|
||||
"19":"img/browsericons/icon19.png",
|
||||
"38":"img/browsericons/icon38.png"
|
||||
},
|
||||
"default_title":"uBlock Origin",
|
||||
"default_popup":"popup.html"
|
||||
},
|
||||
"commands":{
|
||||
"launch-element-zapper":{
|
||||
"description":"__MSG_popupTipZapper__"
|
||||
},
|
||||
"launch-element-picker":{
|
||||
"description":"__MSG_popupTipPicker__"
|
||||
},
|
||||
"launch-logger":{
|
||||
"description":"__MSG_popupTipLog__"
|
||||
}
|
||||
},
|
||||
"content_scripts":[
|
||||
{
|
||||
"matches":[
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
"js":[
|
||||
"js/vapi-client.js",
|
||||
"js/vapi-usercss.js",
|
||||
"js/contentscript.js"
|
||||
],
|
||||
"run_at":"document_start",
|
||||
"all_frames":true
|
||||
},
|
||||
{
|
||||
"matches":[
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
],
|
||||
"js":[
|
||||
"js/scriptlets/subscriber.js"
|
||||
],
|
||||
"run_at":"document_idle",
|
||||
"all_frames":false
|
||||
}
|
||||
],
|
||||
"default_locale":"en",
|
||||
"description":"__MSG_extShortDesc__",
|
||||
"icons":{
|
||||
"16":"img/icon_16.png",
|
||||
"128":"img/icon_128.png"
|
||||
},
|
||||
"manifest_version":2,
|
||||
"name":"uBlock Origin",
|
||||
"options_ui":{
|
||||
"page":"options_ui.html"
|
||||
},
|
||||
"permissions":[
|
||||
"contextMenus",
|
||||
"privacy",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"<all_urls>"
|
||||
],
|
||||
"short_name":"uBlock₀",
|
||||
"version":"1.9.15.101"
|
||||
}
|
||||
|
|
|
|||
13
platform/webext/options_ui.html
Normal file
13
platform/webext/options_ui.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="dashboard.html" data-i18n="popupTipDashboard" target="uBO-dashboard"></a><br>
|
||||
<a href="logger-ui.html" data-i18n="popupTipLog" target="uBO-logger"></a>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/i18n.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
269
platform/webext/vapi-cachestorage.js
Normal file
269
platform/webext/vapi-cachestorage.js
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2016-2017 The uBlock Origin authors
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
/* global indexedDB, IDBDatabase */
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// The code below has been originally manually imported from:
|
||||
// Commit: https://github.com/nikrolls/uBlock-Edge/commit/d1538ea9bea89d507219d3219592382eee306134
|
||||
// Commit date: 29 October 2016
|
||||
// Commit author: https://github.com/nikrolls
|
||||
// Commit message: "Implement cacheStorage using IndexedDB"
|
||||
|
||||
// The original imported code has been subsequently modified as it was not
|
||||
// compatible with Firefox.
|
||||
// (a Promise thing, see https://github.com/dfahlander/Dexie.js/issues/317)
|
||||
// Furthermore, code to migrate from browser.storage.local to vAPI.cacheStorage
|
||||
// has been added, for seamless migration of cache-related entries into
|
||||
// indexedDB.
|
||||
|
||||
vAPI.cacheStorage = (function() {
|
||||
const STORAGE_NAME = 'uBlock0CacheStorage';
|
||||
var db;
|
||||
var pending = [];
|
||||
|
||||
// prime the db so that it's ready asap for next access.
|
||||
getDb(noopfn);
|
||||
|
||||
return { get, set, remove, clear, getBytesInUse };
|
||||
|
||||
function get(input, callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
if ( input === null ) {
|
||||
return getAllFromDb(callback);
|
||||
}
|
||||
var toRead, output = {};
|
||||
if ( typeof input === 'string' ) {
|
||||
toRead = [ input ];
|
||||
} else if ( Array.isArray(input) ) {
|
||||
toRead = input;
|
||||
} else /* if ( typeof input === 'object' ) */ {
|
||||
toRead = Object.keys(input);
|
||||
output = input;
|
||||
}
|
||||
return getFromDb(toRead, output, callback);
|
||||
}
|
||||
|
||||
function set(input, callback) {
|
||||
putToDb(input, callback);
|
||||
}
|
||||
|
||||
function remove(key, callback) {
|
||||
deleteFromDb(key, callback);
|
||||
}
|
||||
|
||||
function clear(callback) {
|
||||
clearDb(callback);
|
||||
}
|
||||
|
||||
function getBytesInUse(keys, callback) {
|
||||
// TODO: implement this
|
||||
callback(0);
|
||||
}
|
||||
|
||||
function genericErrorHandler(error) {
|
||||
console.error('[uBlock0 cacheStorage]', error);
|
||||
}
|
||||
|
||||
function noopfn() {
|
||||
}
|
||||
|
||||
function processPendings() {
|
||||
var cb;
|
||||
while ( (cb = pending.shift()) ) {
|
||||
cb(db);
|
||||
}
|
||||
}
|
||||
|
||||
function getDb(callback) {
|
||||
if ( pending === undefined ) {
|
||||
return callback();
|
||||
}
|
||||
if ( pending.length !== 0 ) {
|
||||
return pending.push(callback);
|
||||
}
|
||||
if ( db instanceof IDBDatabase ) {
|
||||
return callback(db);
|
||||
}
|
||||
pending.push(callback);
|
||||
if ( pending.length !== 1 ) { return; }
|
||||
// This will fail in private browsing mode.
|
||||
var req = indexedDB.open(STORAGE_NAME, 1);
|
||||
req.onupgradeneeded = function(ev) {
|
||||
db = ev.target.result;
|
||||
db.onerror = genericErrorHandler;
|
||||
var table = db.createObjectStore(STORAGE_NAME, { keyPath: 'key' });
|
||||
table.createIndex('value', 'value', { unique: false });
|
||||
};
|
||||
req.onsuccess = function(ev) {
|
||||
db = ev.target.result;
|
||||
db.onerror = genericErrorHandler;
|
||||
processPendings();
|
||||
};
|
||||
req.onerror = function() {
|
||||
console.log(this.error);
|
||||
processPendings();
|
||||
pending = undefined;
|
||||
};
|
||||
}
|
||||
|
||||
function getFromDb(keys, store, callback) {
|
||||
if ( typeof callback !== 'function' ) { return; }
|
||||
if ( keys.length === 0 ) { return callback(store); }
|
||||
var notfoundKeys = new Set(keys);
|
||||
var gotOne = function() {
|
||||
if ( typeof this.result === 'object' ) {
|
||||
store[this.result.key] = this.result.value;
|
||||
notfoundKeys.delete(this.result.key);
|
||||
}
|
||||
};
|
||||
getDb(function(db) {
|
||||
if ( !db ) { return callback(); }
|
||||
var transaction = db.transaction(STORAGE_NAME);
|
||||
transaction.oncomplete = transaction.onerror = function() {
|
||||
// TODO: remove once storage.local is clean
|
||||
if ( notfoundKeys.size === 0 ) {
|
||||
vAPI.storage.remove(keys);
|
||||
return callback(store);
|
||||
}
|
||||
maybeMigrate(Array.from(notfoundKeys), store, callback);
|
||||
};
|
||||
var table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( var key of keys ) {
|
||||
var req = table.get(key);
|
||||
req.onsuccess = gotOne;
|
||||
req.onerror = noopfn;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Migrate from storage API
|
||||
// TODO: removes once all users are migrated to the new cacheStorage.
|
||||
function maybeMigrate(keys, store, callback) {
|
||||
var toMigrate = new Set(),
|
||||
i = keys.length;
|
||||
while ( i-- ) {
|
||||
var key = keys[i];
|
||||
toMigrate.add(key);
|
||||
// If migrating a compiled list, also migrate the non-compiled
|
||||
// counterpart.
|
||||
if ( /^cache\/compiled\//.test(key) ) {
|
||||
toMigrate.add(key.replace('/compiled', ''));
|
||||
}
|
||||
}
|
||||
vAPI.storage.get(Array.from(toMigrate), function(bin) {
|
||||
if ( bin instanceof Object === false ) {
|
||||
return callback(store);
|
||||
}
|
||||
var migratedKeys = Object.keys(bin);
|
||||
if ( migratedKeys.length === 0 ) {
|
||||
return callback(store);
|
||||
}
|
||||
var i = migratedKeys.length;
|
||||
while ( i-- ) {
|
||||
var key = migratedKeys[i];
|
||||
store[key] = bin[key];
|
||||
}
|
||||
vAPI.storage.remove(migratedKeys);
|
||||
vAPI.cacheStorage.set(bin);
|
||||
callback(store);
|
||||
});
|
||||
}
|
||||
|
||||
function getAllFromDb(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
getDb(function(db) {
|
||||
if ( !db ) { return callback(); }
|
||||
var output = {};
|
||||
var transaction = db.transaction(STORAGE_NAME);
|
||||
transaction.oncomplete = transaction.onerror = function() {
|
||||
callback(output);
|
||||
};
|
||||
var table = transaction.objectStore(STORAGE_NAME),
|
||||
req = table.openCursor();
|
||||
req.onsuccess = function(ev) {
|
||||
var cursor = ev.target.result;
|
||||
if ( !cursor ) { return; }
|
||||
output[cursor.key] = cursor.value;
|
||||
cursor.continue();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function putToDb(input, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
var keys = Object.keys(input);
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
getDb(function(db) {
|
||||
if ( !db ) { return callback(); }
|
||||
var transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete = transaction.onerror = callback;
|
||||
var table = transaction.objectStore(STORAGE_NAME),
|
||||
entry = {};
|
||||
for ( var key of keys ) {
|
||||
entry.key = key;
|
||||
entry.value = input[key];
|
||||
table.put(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFromDb(input, callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
var keys = Array.isArray(input) ? input.slice() : [ input ];
|
||||
if ( keys.length === 0 ) { return callback(); }
|
||||
getDb(function(db) {
|
||||
if ( !db ) { return callback(); }
|
||||
var transaction = db.transaction(STORAGE_NAME, 'readwrite');
|
||||
transaction.oncomplete = transaction.onerror = callback;
|
||||
var table = transaction.objectStore(STORAGE_NAME);
|
||||
for ( var key of keys ) {
|
||||
table.delete(key);
|
||||
}
|
||||
});
|
||||
// TODO: removes once all users are migrated to the new cacheStorage.
|
||||
vAPI.storage.remove(keys);
|
||||
}
|
||||
|
||||
function clearDb(callback) {
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = noopfn;
|
||||
}
|
||||
getDb(function(db) {
|
||||
if ( !db ) { return callback(); }
|
||||
var req = db.transaction(STORAGE_NAME, 'readwrite')
|
||||
.objectStore(STORAGE_NAME)
|
||||
.clear();
|
||||
req.onsuccess = req.onerror = callback;
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
/******************************************************************************/
|
||||
77
platform/webext/vapi-usercss.js
Normal file
77
platform/webext/vapi-usercss.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2017 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';
|
||||
|
||||
// For content pages
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
(function() {
|
||||
if ( typeof vAPI !== 'object' ) { return; }
|
||||
|
||||
vAPI.userCSS = {
|
||||
_userCSS: '',
|
||||
_disabled: false,
|
||||
_send: function(toRemove, toAdd) {
|
||||
vAPI.messaging.send('vapi-background', {
|
||||
what: 'userCSS',
|
||||
toRemove: toRemove,
|
||||
toAdd: toAdd
|
||||
});
|
||||
},
|
||||
add: function(cssText) {
|
||||
if ( cssText === '' ) { return; }
|
||||
var before = this._userCSS,
|
||||
after = before;
|
||||
if ( after !== '' ) { after += '\n'; }
|
||||
after += cssText;
|
||||
this._userCSS = after;
|
||||
if ( this._disabled ) { return; }
|
||||
this._send(before, after);
|
||||
},
|
||||
remove: function(cssText) {
|
||||
if ( cssText === '' || this._userCSS === '' ) { return; }
|
||||
var before = this._userCSS,
|
||||
after = before;
|
||||
after = before.replace(cssText, '').trim();
|
||||
this._userCSS = after;
|
||||
if ( this._disabled ) { return; }
|
||||
this._send(before, after);
|
||||
},
|
||||
toggle: function(state) {
|
||||
if ( state === undefined ) {
|
||||
state = this._disabled;
|
||||
}
|
||||
if ( state !== this._disabled ) { return; }
|
||||
this._disabled = !state;
|
||||
if ( this._userCSS === '' ) { return; }
|
||||
var toAdd, toRemove;
|
||||
if ( state ) {
|
||||
toAdd = this._userCSS;
|
||||
} else {
|
||||
toRemove = this._userCSS;
|
||||
}
|
||||
this._send(toRemove, toAdd);
|
||||
}
|
||||
};
|
||||
vAPI.hideNode = vAPI.unhideNode = function(){};
|
||||
})();
|
||||
182
platform/webext/vapi-webrequest.js
Normal file
182
platform/webext/vapi-webrequest.js
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2017 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
|
||||
*/
|
||||
|
||||
// For background page
|
||||
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net = {};
|
||||
|
||||
vAPI.net.registerListeners = function() {
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2950
|
||||
// Firefox 55 does not normalize URLs to ASCII, uBO must do this itself.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=945240
|
||||
var mustPunycode = false;
|
||||
(function() {
|
||||
if (
|
||||
typeof browser === 'object' &&
|
||||
browser !== null &&
|
||||
browser.runtime instanceof Object &&
|
||||
typeof browser.runtime.getBrowserInfo === 'function'
|
||||
) {
|
||||
browser.runtime.getBrowserInfo().then(info => {
|
||||
mustPunycode = info.name === 'Firefox' &&
|
||||
/^5[0-6]\./.test(info.version);
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
var wrApi = browser.webRequest;
|
||||
|
||||
// legacy Chromium understands only these network request types.
|
||||
var validTypes = {
|
||||
main_frame: true,
|
||||
sub_frame: true,
|
||||
stylesheet: true,
|
||||
script: true,
|
||||
image: true,
|
||||
object: true,
|
||||
xmlhttprequest: true,
|
||||
other: true
|
||||
};
|
||||
// modern Chromium/WebExtensions: more types available.
|
||||
if ( wrApi.ResourceType ) {
|
||||
for ( let typeKey in wrApi.ResourceType ) {
|
||||
if ( wrApi.ResourceType.hasOwnProperty(typeKey) ) {
|
||||
validTypes[wrApi.ResourceType[typeKey]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var denormalizeTypes = function(aa) {
|
||||
if ( aa.length === 0 ) {
|
||||
return Object.keys(validTypes);
|
||||
}
|
||||
var out = [];
|
||||
var i = aa.length,
|
||||
type,
|
||||
needOther = true;
|
||||
while ( i-- ) {
|
||||
type = aa[i];
|
||||
if ( validTypes[type] ) {
|
||||
out.push(type);
|
||||
}
|
||||
if ( type === 'other' ) {
|
||||
needOther = false;
|
||||
}
|
||||
}
|
||||
if ( needOther ) {
|
||||
out.push('other');
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
var punycode = self.punycode;
|
||||
var reMustNormalizeHostname = /[^0-9a-z._-]/;
|
||||
var parsedURL = new URL('about:blank');
|
||||
|
||||
var normalizeRequestDetails = function(details) {
|
||||
details.tabId = details.tabId.toString();
|
||||
|
||||
if (
|
||||
mustPunycode === true &&
|
||||
reMustNormalizeHostname.test(details.url) === true
|
||||
) {
|
||||
parsedURL.href = details.url;
|
||||
details.url = details.url.replace(
|
||||
parsedURL.hostname,
|
||||
punycode.toASCII(parsedURL.hostname)
|
||||
);
|
||||
}
|
||||
|
||||
var type = details.type;
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1493
|
||||
// Chromium 49+/WebExtensions support a new request type: `ping`,
|
||||
// which is fired as a result of using `navigator.sendBeacon`.
|
||||
if ( type === 'ping' ) {
|
||||
details.type = 'beacon';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type === 'imageset' ) {
|
||||
details.type = 'image';
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
var onBeforeRequestClient = this.onBeforeRequest.callback;
|
||||
var onBeforeRequest = function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
return onBeforeRequestClient(details);
|
||||
};
|
||||
|
||||
var onHeadersReceivedClient = this.onHeadersReceived.callback,
|
||||
onHeadersReceivedClientTypes = this.onHeadersReceived.types.slice(0),
|
||||
onHeadersReceivedTypes = denormalizeTypes(onHeadersReceivedClientTypes);
|
||||
var onHeadersReceived = function(details) {
|
||||
normalizeRequestDetails(details);
|
||||
if (
|
||||
onHeadersReceivedClientTypes.length !== 0 &&
|
||||
onHeadersReceivedClientTypes.indexOf(details.type) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
return onHeadersReceivedClient(details);
|
||||
};
|
||||
|
||||
if ( onBeforeRequest ) {
|
||||
let urls = this.onBeforeRequest.urls || ['<all_urls>'];
|
||||
let types = this.onBeforeRequest.types || undefined;
|
||||
if (
|
||||
(validTypes.websocket) &&
|
||||
(types === undefined || types.indexOf('websocket') !== -1) &&
|
||||
(urls.indexOf('<all_urls>') === -1)
|
||||
) {
|
||||
if ( urls.indexOf('ws://*/*') === -1 ) {
|
||||
urls.push('ws://*/*');
|
||||
}
|
||||
if ( urls.indexOf('wss://*/*') === -1 ) {
|
||||
urls.push('wss://*/*');
|
||||
}
|
||||
}
|
||||
wrApi.onBeforeRequest.addListener(
|
||||
onBeforeRequest,
|
||||
{ urls: urls, types: types },
|
||||
this.onBeforeRequest.extra
|
||||
);
|
||||
}
|
||||
|
||||
if ( onHeadersReceived ) {
|
||||
let urls = this.onHeadersReceived.urls || ['<all_urls>'];
|
||||
let types = onHeadersReceivedTypes;
|
||||
wrApi.onHeadersReceived.addListener(
|
||||
onHeadersReceived,
|
||||
{ urls: urls, types: types },
|
||||
this.onHeadersReceived.extra
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<input type="checkbox"><!--
|
||||
--><a class="content" type="text/plain" target="_blank" href=""></a>​<!--
|
||||
--><a class="fa support" href="" target="_blank"></a>​<!--
|
||||
--><a class="fa remove" href=""></a>​<!--
|
||||
--><a class="fa remove" href=""></a>​<!--
|
||||
--><a class="fa mustread" href="" target="_blank"></a>​<!--
|
||||
--><span class="fa status unsecure" title="http"></span>​<!--
|
||||
--><span class="counts dim"></span>​<!--
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@
|
|||
"description":"English: One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored."
|
||||
},
|
||||
"3pExternalListObsolete":{
|
||||
"message":"متقادم.",
|
||||
"message":"إنتهت صلاحيته.",
|
||||
"description":"used as a tooltip for the out-of-date icon beside a list"
|
||||
},
|
||||
"3pLastUpdate":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Kliknutím sem otevřete ovládací panel",
|
||||
"message":"Otevřít ovládací panel",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Klõpsa, et avada töölaud",
|
||||
"message":"Ava töölaud",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Klik kontrol panela irekitzeko",
|
||||
"message":"Ireki kontrol panela",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
"description":"appears as tab name in dashboard"
|
||||
},
|
||||
"advancedSettingsPageName":{
|
||||
"message":"Advanced settings",
|
||||
"message":"تنظیمات پیشرفته",
|
||||
"description":"Title for the advanced settings page"
|
||||
},
|
||||
"popupPowerSwitchInfo":{
|
||||
|
|
@ -68,11 +68,11 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"برای باز کردن داشبورد کلیک کنید",
|
||||
"message":"باز کردن داشبورد",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"ورود به حالت انتخاب اشیاء",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
"description":"English: Enter element picker mode"
|
||||
},
|
||||
"popupTipLog":{
|
||||
"message":"بازنمایی ثبت درخواست",
|
||||
"message":"رفتن به لاگ درخواست",
|
||||
"description":"Tooltip used for the logger icon in the panel"
|
||||
},
|
||||
"popupTipNoPopups":{
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsAdvancedUserSettings":{
|
||||
"message":"advanced settings",
|
||||
"message":"تنظیمات پیشرفته",
|
||||
"description":"For the tooltip of a link which gives access to advanced settings"
|
||||
},
|
||||
"settingsPrefetchingDisabledPrompt":{
|
||||
|
|
@ -348,11 +348,11 @@
|
|||
"description":"used as a tooltip for the clock icon beside a list"
|
||||
},
|
||||
"3pUpdating":{
|
||||
"message":"Updating...",
|
||||
"message":"درحال بروزرسانی...",
|
||||
"description":"used as a tooltip for the spinner icon beside a list"
|
||||
},
|
||||
"3pNetworkError":{
|
||||
"message":"A network error prevented the resource from being updated.",
|
||||
"message":"یک خطای شبکه از بروزشدن منابع جلوگیری کرد.",
|
||||
"description":"used as a tooltip for error icon beside a list"
|
||||
},
|
||||
"1pFormatHint":{
|
||||
|
|
@ -680,7 +680,7 @@
|
|||
"description":"used as a prompt for the user to provide a custom device name"
|
||||
},
|
||||
"advancedSettingsWarning":{
|
||||
"message":"Warning! Change these advanced settings at your own risk.",
|
||||
"message":"هشدار! این تنظیمات پیشرفته را با مسئولیت خود تغییر دهید.",
|
||||
"description":"A warning to users at the top of 'Advanced settings' page"
|
||||
},
|
||||
"genericSubmit":{
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Avaa hallintapaneeli napsauttamalla",
|
||||
"message":"Hallintapaneelityökaluun",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"Aktivoi elementtien piilotus\/palautus -poimintatyökalu",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
"description":""
|
||||
},
|
||||
"popupHitDomainCountPrompt":{
|
||||
"message":"yhdistetyt verkkotunnukset",
|
||||
"message":"aktiiviset verkkotunnusyhteydet",
|
||||
"description":"appears in popup"
|
||||
},
|
||||
"popupHitDomainCount":{
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
"description":"English: Make use of context menu where appropriate"
|
||||
},
|
||||
"settingsColorBlindPrompt":{
|
||||
"message":"Mukauta värisokeille",
|
||||
"message":"Aktivoi vaihtoehtoiset värit puna-vihervärien sijaan",
|
||||
"description":"English: Color-blind friendly"
|
||||
},
|
||||
"settingsCloudStorageEnabledPrompt":{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
"description":"appears as tab name in dashboard"
|
||||
},
|
||||
"statsPageName":{
|
||||
"message":"uBlock₀ — Logger",
|
||||
"message":"uBlock - Talaan",
|
||||
"description":"Title for the logger window"
|
||||
},
|
||||
"aboutPageName":{
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
"description":"appears as tab name in dashboard"
|
||||
},
|
||||
"advancedSettingsPageName":{
|
||||
"message":"Advanced settings",
|
||||
"message":"Mga pinalawig na ayos",
|
||||
"description":"Title for the advanced settings page"
|
||||
},
|
||||
"popupPowerSwitchInfo":{
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"Buksan ang element zapper na paraan",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -84,19 +84,19 @@
|
|||
"description":"Tooltip used for the logger icon in the panel"
|
||||
},
|
||||
"popupTipNoPopups":{
|
||||
"message":"Toggle the blocking of all popups for this site",
|
||||
"message":"Palit-ayos sa paghalang ng mga labasin sa site",
|
||||
"description":"Tooltip for the no-popups per-site switch"
|
||||
},
|
||||
"popupTipNoLargeMedia":{
|
||||
"message":"Toggle the blocking of large media elements for this site",
|
||||
"message":"Palit-ayos sa paghalang ng mga malaking media element sa site",
|
||||
"description":"Tooltip for the no-large-media per-site switch"
|
||||
},
|
||||
"popupTipNoCosmeticFiltering":{
|
||||
"message":"Toggle cosmetic filtering for this site",
|
||||
"message":"Palit-ayos ng panala ng itsura para sa site na ito",
|
||||
"description":"Tooltip for the no-cosmetic-filtering per-site switch"
|
||||
},
|
||||
"popupTipNoRemoteFonts":{
|
||||
"message":"Toggle the blocking of remote fonts for this site",
|
||||
"message":"Palit-ayos sa paghalang ng malayuang itsura ng titik para sa site na ito",
|
||||
"description":"Tooltip for the no-remote-fonts per-site switch"
|
||||
},
|
||||
"popupTipGlobalRules":{
|
||||
|
|
@ -116,15 +116,15 @@
|
|||
"description":"Tooltip when hovering over the eraser in the dynamic filtering pane."
|
||||
},
|
||||
"popupAnyRulePrompt":{
|
||||
"message":"all",
|
||||
"message":"lahat",
|
||||
"description":""
|
||||
},
|
||||
"popupImageRulePrompt":{
|
||||
"message":"images",
|
||||
"message":"mga imahe",
|
||||
"description":""
|
||||
},
|
||||
"popup3pAnyRulePrompt":{
|
||||
"message":"3rd-party",
|
||||
"message":"Pang-tatlo na personalidad",
|
||||
"description":""
|
||||
},
|
||||
"popup3pPassiveRulePrompt":{
|
||||
|
|
@ -156,19 +156,19 @@
|
|||
"description":"appears in popup"
|
||||
},
|
||||
"pickerCreate":{
|
||||
"message":"Create",
|
||||
"message":"Gumawa",
|
||||
"description":"English: Create"
|
||||
},
|
||||
"pickerPick":{
|
||||
"message":"Pick",
|
||||
"message":"Pili",
|
||||
"description":"English: Pick"
|
||||
},
|
||||
"pickerQuit":{
|
||||
"message":"Quit",
|
||||
"message":"Tumigil",
|
||||
"description":"English: Quit"
|
||||
},
|
||||
"pickerPreview":{
|
||||
"message":"Preview",
|
||||
"message":"Paunang-tingin",
|
||||
"description":"Element picker preview mode: will cause the elements matching the current filter to be removed from the page"
|
||||
},
|
||||
"pickerNetFilters":{
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
"description":"English: Click, Ctrl-click"
|
||||
},
|
||||
"pickerContextMenuEntry":{
|
||||
"message":"Block element",
|
||||
"message":"Paghalang sa elemento",
|
||||
"description":"English: Block element"
|
||||
},
|
||||
"settingsCollapseBlockedPrompt":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Klik om it dashboerd te iepenjen",
|
||||
"message":"Dashboerd iepenje",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"לחץ כדי לפתוח את לוח המחוונים",
|
||||
"message":"פתח את פאנל הקונפיגורציות",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@
|
|||
"description":"English: Quit"
|
||||
},
|
||||
"pickerPreview":{
|
||||
"message":"Preview",
|
||||
"message":"पूर्वावलोकन",
|
||||
"description":"Element picker preview mode: will cause the elements matching the current filter to be removed from the page"
|
||||
},
|
||||
"pickerNetFilters":{
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsAdvancedUserSettings":{
|
||||
"message":"advanced settings",
|
||||
"message":"उन्नत सेटिंग्स",
|
||||
"description":"For the tooltip of a link which gives access to advanced settings"
|
||||
},
|
||||
"settingsPrefetchingDisabledPrompt":{
|
||||
|
|
@ -272,7 +272,7 @@
|
|||
"description":"Appears aside each filter list in the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pAutoUpdatePrompt1":{
|
||||
"message":"Auto-update filter lists",
|
||||
"message":"स्व-अद्यतन फ़िल्टर सूचियां",
|
||||
"description":"A checkbox in the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pUpdateNow":{
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Elemváltó mód aktiválása",
|
||||
"message":"Elem eltávolító mód",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -580,7 +580,7 @@
|
|||
"description":"Message asking user to confirm reset"
|
||||
},
|
||||
"errorCantConnectTo":{
|
||||
"message":"Csatlakozás sikertelen a következő címhez: {{url}}",
|
||||
"message":"Hálózati hiba: {{msg}}",
|
||||
"description":"English: Network error: {{msg}}"
|
||||
},
|
||||
"subscriberConfirm":{
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Klik untuk membuka dasbor",
|
||||
"message":"Buka dasbor",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"Memasuki mode penghapus elemen",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Clicca per aprire il dashboard",
|
||||
"message":"Clicca per aprire il pannello",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
@ -224,7 +224,7 @@
|
|||
"description":"English: "
|
||||
},
|
||||
"settingsHyperlinkAuditingDisabledPrompt":{
|
||||
"message":"Disabilita la revisione degli hyperlink",
|
||||
"message":"Disabilita la revisione dei collegamenti ipertestuali",
|
||||
"description":"English: "
|
||||
},
|
||||
"settingsWebRTCIPAddressHiddenPrompt":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"クリックしてダッシュボードを開く",
|
||||
"message":"ダッシュボードを開く",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
"description":"Tooltip for the no-large-media per-site switch"
|
||||
},
|
||||
"popupTipNoCosmeticFiltering":{
|
||||
"message":"このサイトの要素隠蔽フィルターを切り替える",
|
||||
"message":"このサイトの要素隠蔽フィルターを切り替えます",
|
||||
"description":"Tooltip for the no-cosmetic-filtering per-site switch"
|
||||
},
|
||||
"popupTipNoRemoteFonts":{
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
"description":"English: header for a type of filter in the element picker dialog"
|
||||
},
|
||||
"pickerCosmeticFilters":{
|
||||
"message":"要素隠蔽フィルター",
|
||||
"message":"要素隠蔽フィルタ",
|
||||
"description":"English: Cosmetic filters"
|
||||
},
|
||||
"pickerCosmeticFiltersHint":{
|
||||
|
|
@ -204,7 +204,7 @@
|
|||
"description":"English: Make use of context menu where appropriate"
|
||||
},
|
||||
"settingsColorBlindPrompt":{
|
||||
"message":"uBlock₀を優しい色使いにする",
|
||||
"message":"uBlock₀を色盲の方に優しい色にする",
|
||||
"description":"English: Color-blind friendly"
|
||||
},
|
||||
"settingsCloudStorageEnabledPrompt":{
|
||||
|
|
@ -240,7 +240,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsNoCosmeticFilteringPrompt":{
|
||||
"message":"要素隠蔽フィルターを無効にする",
|
||||
"message":"要素隠蔽フィルタを無効にする",
|
||||
"description":""
|
||||
},
|
||||
"settingsNoLargeMediaPrompt":{
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsStorageUsed":{
|
||||
"message":"使用中のストレージ: {{value}} bytes",
|
||||
"message":"使用中のストレージ: {{value}} バイト",
|
||||
"description":"English: Storage used: {{}} bytes"
|
||||
},
|
||||
"settingsLastRestorePrompt":{
|
||||
|
|
@ -264,7 +264,7 @@
|
|||
"description":"English: Last backup:"
|
||||
},
|
||||
"3pListsOfBlockedHostsPrompt":{
|
||||
"message":"{{netFilterCount}} ネットワークフィルター+{{cosmeticFilterCount}} 要素隠蔽フィルター:",
|
||||
"message":"{{netFilterCount}}ネットワークフィルタ+{{cosmeticFilterCount}}コスメチックフィルタ:",
|
||||
"description":"Appears at the top of the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pListsOfBlockedHostsPerListStats":{
|
||||
|
|
@ -284,7 +284,7 @@
|
|||
"description":"A button in the in the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pParseAllABPHideFiltersPrompt1":{
|
||||
"message":"要素隠蔽フィルターを解析、施行する",
|
||||
"message":"要素隠蔽フィルタを解析、施行する。",
|
||||
"description":"English: Parse and enforce Adblock+ element hiding filters."
|
||||
},
|
||||
"3pParseAllABPHideFiltersInfo":{
|
||||
|
|
@ -340,11 +340,11 @@
|
|||
"description":"English: One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored."
|
||||
},
|
||||
"3pExternalListObsolete":{
|
||||
"message":"新しいバージョンがあります",
|
||||
"message":"古いバージョンです",
|
||||
"description":"used as a tooltip for the out-of-date icon beside a list"
|
||||
},
|
||||
"3pLastUpdate":{
|
||||
"message":"最終更新: {{ago}}\nクリックすると強制的に更新します",
|
||||
"message":"最終更新: {{ago}}",
|
||||
"description":"used as a tooltip for the clock icon beside a list"
|
||||
},
|
||||
"3pUpdating":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Klik om het dashboard te openen",
|
||||
"message":"Dashboard openen",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Kliknij, aby otworzyć panel sterowania",
|
||||
"message":"Otwórz panel sterowania",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
@ -344,7 +344,7 @@
|
|||
"description":"used as a tooltip for the out-of-date icon beside a list"
|
||||
},
|
||||
"3pLastUpdate":{
|
||||
"message":"Zaktualizowano: {{ago}}.\nKliknij by wymusić aktualizację.",
|
||||
"message":"Zaktualizowano: {{ago}}.\nKliknij, aby wymusić aktualizację.",
|
||||
"description":"used as a tooltip for the clock icon beside a list"
|
||||
},
|
||||
"3pUpdating":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Clique para abrir o painel",
|
||||
"message":"Abrir painel de controle",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Clic pentru a deschide tabloul de bord",
|
||||
"message":"Deschide panoul de control",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
"message":"Войти в режим выбора элемента",
|
||||
"message":"Войти в режим выбора элементов",
|
||||
"description":"English: Enter element picker mode"
|
||||
},
|
||||
"popupTipLog":{
|
||||
|
|
@ -100,11 +100,11 @@
|
|||
"description":"Tooltip for the no-remote-fonts per-site switch"
|
||||
},
|
||||
"popupTipGlobalRules":{
|
||||
"message":"Глобальные правила: эта колонка предназначена для правил, применяемых ко всем сайтам.",
|
||||
"message":"Глобальные правила: этот столбец предназначен для правил, применяемых ко всем сайтам.",
|
||||
"description":"Tooltip when hovering the top-most cell of the global-rules column."
|
||||
},
|
||||
"popupTipLocalRules":{
|
||||
"message":"Локальные правила: эта колонка предназначена для правил, применяемых только к текущему сайту.\nЛокальные правила замещают глобальные.",
|
||||
"message":"Локальные правила: этот столбец предназначен для правил, применяемых только к текущему сайту.\nЛокальные правила переопределяют глобальные.",
|
||||
"description":"Tooltip when hovering the top-most cell of the local-rules column."
|
||||
},
|
||||
"popupTipSaveRules":{
|
||||
|
|
@ -180,7 +180,7 @@
|
|||
"description":"English: Cosmetic filters"
|
||||
},
|
||||
"pickerCosmeticFiltersHint":{
|
||||
"message":"Щелчок, Ctrl+щелчок",
|
||||
"message":"Клик, Ctrl+клик",
|
||||
"description":"English: Click, Ctrl-click"
|
||||
},
|
||||
"pickerContextMenuEntry":{
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"Vklopi način izbire elementov",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -208,7 +208,7 @@
|
|||
"description":"English: Color-blind friendly"
|
||||
},
|
||||
"settingsCloudStorageEnabledPrompt":{
|
||||
"message":"Omogoči podporo za shrambo v oblako",
|
||||
"message":"Omogoči podporo za shrambo v oblaku",
|
||||
"description":""
|
||||
},
|
||||
"settingsAdvancedUserPrompt":{
|
||||
|
|
@ -348,11 +348,11 @@
|
|||
"description":"used as a tooltip for the clock icon beside a list"
|
||||
},
|
||||
"3pUpdating":{
|
||||
"message":"Updating...",
|
||||
"message":"Posodabljanje ...",
|
||||
"description":"used as a tooltip for the spinner icon beside a list"
|
||||
},
|
||||
"3pNetworkError":{
|
||||
"message":"A network error prevented the resource from being updated.",
|
||||
"message":"Omrežna napaka je preprečila posodobitev virov.",
|
||||
"description":"used as a tooltip for error icon beside a list"
|
||||
},
|
||||
"1pFormatHint":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Кликните за отварање контролне табле",
|
||||
"message":"Отвори контролну таблу",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
"description":"Tooltip for the no-cosmetic-filtering per-site switch"
|
||||
},
|
||||
"popupTipNoRemoteFonts":{
|
||||
"message":"Укључи\/искључи блокирање спољних фонтова за овај сајт",
|
||||
"message":"Укључи\/искључи блокирање удаљених фонтова за овај сајт",
|
||||
"description":"Tooltip for the no-remote-fonts per-site switch"
|
||||
},
|
||||
"popupTipGlobalRules":{
|
||||
|
|
@ -108,11 +108,11 @@
|
|||
"description":"Tooltip when hovering the top-most cell of the local-rules column."
|
||||
},
|
||||
"popupTipSaveRules":{
|
||||
"message":"Кликните да бисте измене учинили трајним.",
|
||||
"message":"Кликните да бисте промене учинили трајним.",
|
||||
"description":"Tooltip when hovering over the padlock in the dynamic filtering pane."
|
||||
},
|
||||
"popupTipRevertRules":{
|
||||
"message":"Кликните да бисте вратили измене.",
|
||||
"message":"Кликните да бисте вратили промене.",
|
||||
"description":"Tooltip when hovering over the eraser in the dynamic filtering pane."
|
||||
},
|
||||
"popupAnyRulePrompt":{
|
||||
|
|
@ -304,7 +304,7 @@
|
|||
"description":"English: Lists of blocked hosts"
|
||||
},
|
||||
"3pApplyChanges":{
|
||||
"message":"Примени измене",
|
||||
"message":"Примени промене",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"3pGroupAds":{
|
||||
|
|
@ -372,7 +372,7 @@
|
|||
"description":"English: my-ublock-static-filters_{{datetime}}.txt"
|
||||
},
|
||||
"1pApplyChanges":{
|
||||
"message":"Примени измене",
|
||||
"message":"Примени промене",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"rulesPermanentHeader":{
|
||||
|
|
@ -440,7 +440,7 @@
|
|||
"description":"English: my-ublock-whitelist_{{datetime}}.txt"
|
||||
},
|
||||
"whitelistApply":{
|
||||
"message":"Примени измене",
|
||||
"message":"Примени промене",
|
||||
"description":"English: Apply changes"
|
||||
},
|
||||
"logRequestsHeaderType":{
|
||||
|
|
@ -532,7 +532,7 @@
|
|||
"description":"Below this sentence, the filter lists in which the filter was found"
|
||||
},
|
||||
"aboutChangelog":{
|
||||
"message":"Дневник измена",
|
||||
"message":"Евиденција промена",
|
||||
"description":"English: Change log"
|
||||
},
|
||||
"aboutWiki":{
|
||||
|
|
@ -688,7 +688,7 @@
|
|||
"description":"for generic 'Submit' buttons"
|
||||
},
|
||||
"genericApplyChanges":{
|
||||
"message":"Примени измене",
|
||||
"message":"Примени промене",
|
||||
"description":"for generic 'Apply changes' buttons"
|
||||
},
|
||||
"genericRevert":{
|
||||
|
|
|
|||
|
|
@ -68,15 +68,15 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Kontrol panelini aç",
|
||||
"message":"Kontrol panelini açar",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Öğe silme moduna gir",
|
||||
"message":"Öge silme moduna gir",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
"message":"Öğe seçme moduna gir",
|
||||
"message":"Öge seçme moduna gir",
|
||||
"description":"English: Enter element picker mode"
|
||||
},
|
||||
"popupTipLog":{
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
"description":"Tooltip for the no-popups per-site switch"
|
||||
},
|
||||
"popupTipNoLargeMedia":{
|
||||
"message":"Bu site için büyük medya öğelerini engellemeyi aç\/kapa",
|
||||
"message":"Bu site için büyük medya ögelerini engellemeyi aç\/kapa",
|
||||
"description":"Tooltip for the no-large-media per-site switch"
|
||||
},
|
||||
"popupTipNoCosmeticFiltering":{
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
"description":"English: Click, Ctrl-click"
|
||||
},
|
||||
"pickerContextMenuEntry":{
|
||||
"message":"Ögeyi engelle",
|
||||
"message":"Öge engelle",
|
||||
"description":"English: Block element"
|
||||
},
|
||||
"settingsCollapseBlockedPrompt":{
|
||||
|
|
@ -244,7 +244,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsNoLargeMediaPrompt":{
|
||||
"message":"Belirlenenden büyük medya öğelerini engelle {{input:number}} kB",
|
||||
"message":"Belirlenenden büyük medya ögelerini engelle {{input:number}} kB",
|
||||
"description":""
|
||||
},
|
||||
"settingsNoRemoteFontsPrompt":{
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
"description":""
|
||||
},
|
||||
"settingsStorageUsed":{
|
||||
"message":"Kullanılan Alan: {{value}} bayt",
|
||||
"message":"Kullanılan Alan: {{value}} byte",
|
||||
"description":"English: Storage used: {{}} bytes"
|
||||
},
|
||||
"settingsLastRestorePrompt":{
|
||||
|
|
@ -280,7 +280,7 @@
|
|||
"description":"A button in the in the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pPurgeAll":{
|
||||
"message":"Tüm önbelleği temizle",
|
||||
"message":"Tüm önbellekleri temizle",
|
||||
"description":"A button in the in the _3rd-party filters_ pane"
|
||||
},
|
||||
"3pParseAllABPHideFiltersPrompt1":{
|
||||
|
|
@ -288,11 +288,11 @@
|
|||
"description":"English: Parse and enforce Adblock+ element hiding filters."
|
||||
},
|
||||
"3pParseAllABPHideFiltersInfo":{
|
||||
"message":"<p>Bu seçenek <a href=\"https:\/\/adblockplus.org\/en\/faq_internal#elemhide\"> Adblock Plus-uyumlu “öğe gizleme” süzgeçlerinin<\/a> işlenmesini ve uygulanmasını sağlar. Bu süzgeçler aslında kozmetiktir, bir web sayfasında görsel rahatsızlık yaratan ve ağ isteği-tabanlı süzme motoru tarafından engellenemeyecek olan öğelerin gizlenmesine yarar.<\/p><p>Bu özelliği etkinleştirmek uBlock₀'in bellek kullanımını artırır.<\/p>",
|
||||
"message":"<p>Bu seçenek <a href=\"https:\/\/adblockplus.org\/en\/faq_internal#elemhide\"> Adblock Plus-uyumlu “öge gizleme” süzgeçlerinin<\/a> işlenmesini ve uygulanmasını sağlar. Bu süzgeçler aslında kozmetiktir, bir web sayfasında görsel rahatsızlık yaratan ve ağ isteği-tabanlı süzme motoru tarafından engellenemeyecek olan ögelerin gizlenmesine yarar.<\/p><p>Bu özelliği etkinleştirmek uBlock₀'in bellek kullanımını artırır.<\/p>",
|
||||
"description":"Describes the purpose of the 'Parse and enforce cosmetic filters' feature."
|
||||
},
|
||||
"3pIgnoreGenericCosmeticFilters":{
|
||||
"message":"Genel kozmetik süzgeçleri yoksay.",
|
||||
"message":"Genel kozmetik süzgeçleri yok say",
|
||||
"description":"This will cause uBO to ignore all generic cosmetic filters."
|
||||
},
|
||||
"3pIgnoreGenericCosmeticFiltersInfo":{
|
||||
|
|
@ -336,7 +336,7 @@
|
|||
"description":"English: Custom"
|
||||
},
|
||||
"3pExternalListsHint":{
|
||||
"message":"Her satırda bir URL. ‘!’ ile başlayan satırlar göz ardı edilir. Geçersiz URL'ler sessizce yoksayılır.",
|
||||
"message":"Her satırda bir URL. ‘!’ ile başlayan satırlar göz ardı edilir. Geçersiz URL'ler sessizce yok sayılır.",
|
||||
"description":"English: One URL per line. Lines prefixed with ‘!’ will be ignored. Invalid URLs will be silently ignored."
|
||||
},
|
||||
"3pExternalListObsolete":{
|
||||
|
|
@ -464,15 +464,15 @@
|
|||
"description":"Appears in the logger's tab selector"
|
||||
},
|
||||
"logBehindTheScene":{
|
||||
"message":"Sahne arkası",
|
||||
"message":"Perde arkası",
|
||||
"description":"Pretty name for behind-the-scene network requests"
|
||||
},
|
||||
"logFilterPrompt":{
|
||||
"message":"günlük kayıtlarını süz",
|
||||
"message":"günlük girişlerini süz",
|
||||
"description":"English: filter log entries"
|
||||
},
|
||||
"logMaxEntriesTip":{
|
||||
"message":"Maksimum günlük kayıt sayısı",
|
||||
"message":"Maksimum günlük giriş sayısı",
|
||||
"description":"Tooltip informaing that the input field is to set the maximum number of entries in the log"
|
||||
},
|
||||
"loggerURLFilteringContextLabel":{
|
||||
|
|
@ -568,11 +568,11 @@
|
|||
"description":"English: Reset to default settings..."
|
||||
},
|
||||
"aboutRestoreDataConfirm":{
|
||||
"message":"Tüm ayarlarınız {{time}} tarihinde yedeklenmiş veriler kullanarak değiştirilecek ve uBlock₀ yeniden başlayacak. \n\nYedeklenmiş verileriniz kullanılarak mevcut tüm ayarlarınız değiştirilsin mi?",
|
||||
"message":"Tüm ayarlarınız {{time}} tarihinde yedeklenmiş veriler kullanarak değiştirilecek ve uBlock₀ yeniden başlayacak. \n\nYedeklenmiş verileriniz kullanılarak var olan tüm ayarlarınız değiştirilsin mi?",
|
||||
"description":"Message asking user to confirm restore"
|
||||
},
|
||||
"aboutRestoreDataError":{
|
||||
"message":"Veri okunamıyor ya da geçersiz",
|
||||
"message":"Veri okunamadı veya geçersiz",
|
||||
"description":"Message to display when an error occurred during restore"
|
||||
},
|
||||
"aboutResetDataConfirm":{
|
||||
|
|
@ -588,7 +588,7 @@
|
|||
"description":"English: The message seen by the user to confirm subscription to a ABP filter list"
|
||||
},
|
||||
"elapsedOneMinuteAgo":{
|
||||
"message":"1 dakika önce",
|
||||
"message":"bir dakika önce",
|
||||
"description":"English: a minute ago"
|
||||
},
|
||||
"elapsedManyMinutesAgo":{
|
||||
|
|
@ -596,7 +596,7 @@
|
|||
"description":"English: {{value}} minutes ago"
|
||||
},
|
||||
"elapsedOneHourAgo":{
|
||||
"message":"1 saat önce",
|
||||
"message":"bir saat önce",
|
||||
"description":"English: an hour ago"
|
||||
},
|
||||
"elapsedManyHoursAgo":{
|
||||
|
|
@ -604,7 +604,7 @@
|
|||
"description":"English: {{value}} hours ago"
|
||||
},
|
||||
"elapsedOneDayAgo":{
|
||||
"message":"1 gün önce",
|
||||
"message":"bir gün önce",
|
||||
"description":"English: a day ago"
|
||||
},
|
||||
"elapsedManyDaysAgo":{
|
||||
|
|
@ -628,7 +628,7 @@
|
|||
"description":"English: uBlock₀ has prevented the following page from loading:"
|
||||
},
|
||||
"docblockedPrompt2":{
|
||||
"message":"Aşağıdaki süzgeçten dolayı",
|
||||
"message":"Bu süzgeç nedeniyle",
|
||||
"description":"English: Because of the following filter"
|
||||
},
|
||||
"docblockedNoParamsPrompt":{
|
||||
|
|
@ -640,7 +640,7 @@
|
|||
"description":"English: List of filter list names follows"
|
||||
},
|
||||
"docblockedBack":{
|
||||
"message":"Geri dön",
|
||||
"message":"Geri git",
|
||||
"description":"English: Go back"
|
||||
},
|
||||
"docblockedClose":{
|
||||
|
|
@ -664,11 +664,11 @@
|
|||
"description":"tooltip"
|
||||
},
|
||||
"cloudPull":{
|
||||
"message":"Bulut depodan içe aktar",
|
||||
"message":"Bulut depodan al",
|
||||
"description":"tooltip"
|
||||
},
|
||||
"cloudPullAndMerge":{
|
||||
"message":"Bulut depodan içe aktar ve şu anki ayarlarla birleştir",
|
||||
"message":"Bulut depodan al ve şu anki ayarlarla birleştir",
|
||||
"description":"tooltip"
|
||||
},
|
||||
"cloudNoData":{
|
||||
|
|
@ -700,7 +700,7 @@
|
|||
"description":""
|
||||
},
|
||||
"contextMenuTemporarilyAllowLargeMediaElements":{
|
||||
"message":"Geçici olarak büyük medya öğelerine izin ver",
|
||||
"message":"Geçici olarak büyük medya ögelerine izin ver",
|
||||
"description":"A context menu entry, present when large media elements have been blocked on the current site"
|
||||
},
|
||||
"dummy":{
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"Bấm để mở bảng điều khiển",
|
||||
"message":"Mở bảng điều khiển",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"Chuyển sang chế độ chọn phần tử",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
@ -344,7 +344,7 @@
|
|||
"description":"used as a tooltip for the out-of-date icon beside a list"
|
||||
},
|
||||
"3pLastUpdate":{
|
||||
"message":"Cập nhật trước: {{ago}}",
|
||||
"message":"Cập nhật mới: {{ago}}.\nClick để cập nhập.",
|
||||
"description":"used as a tooltip for the clock icon beside a list"
|
||||
},
|
||||
"3pUpdating":{
|
||||
|
|
@ -424,7 +424,7 @@
|
|||
"description":"English: dynamic rule syntax and full documentation."
|
||||
},
|
||||
"whitelistPrompt":{
|
||||
"message":"Danh sách tên các máy chủ mà µBlock₀ sẽ bị vô hiệu. Một mục nhập trên mỗi dòng. Tên máy chủ không hợp lệ sẽ được tự động bỏ qua.",
|
||||
"message":"Danh sách tên các máy chủ mà uBlock₀ sẽ bị chặn. Một mục nhập trên mỗi dòng. Tên máy chủ không hợp lệ sẽ được tự động bỏ qua.",
|
||||
"description":"English: An overview of the content of the dashboard's Whitelist pane."
|
||||
},
|
||||
"whitelistImport":{
|
||||
|
|
@ -580,7 +580,7 @@
|
|||
"description":"Message asking user to confirm reset"
|
||||
},
|
||||
"errorCantConnectTo":{
|
||||
"message":"Không thể kết nối đến {{url}}",
|
||||
"message":"Lỗi kết nối: {{msg}}",
|
||||
"description":"English: Network error: {{msg}}"
|
||||
},
|
||||
"subscriberConfirm":{
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@
|
|||
"description":"English: or"
|
||||
},
|
||||
"popupTipDashboard":{
|
||||
"message":"单击打开控制面板",
|
||||
"message":"打开控制面板",
|
||||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
"description":"English: Click to open the dashboard"
|
||||
},
|
||||
"popupTipZapper":{
|
||||
"message":"Enter element zapper mode",
|
||||
"message":"進入元素選擇器模式",
|
||||
"description":"Tooltip for the element-zapper icon in the popup panel"
|
||||
},
|
||||
"popupTipPicker":{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
<title>uBlock — About</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/common.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/about.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
@ -19,7 +18,7 @@
|
|||
<li><a href="https://github.com/gorhill/uBlock" data-i18n="aboutCode"></a>
|
||||
<li><span data-i18n="aboutContributors"></span>
|
||||
<ul>
|
||||
<li><a href="https://github.com/gorhill/uBlock/graphs/contributors">Github</a>
|
||||
<li><a href="https://github.com/gorhill/uBlock/graphs/contributors">GitHub</a>
|
||||
<li><a href="https://crowdin.net/project/ublock">Crowdin</a>
|
||||
</ul>
|
||||
<li><a href="https://github.com/bestiejs/punycode.js" target="_blank">Punycode.js</a> by <a href="https://github.com/mathiasbynens">Mathias Bynens</a>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
<script src="lib/publicsuffixlist.js"></script>
|
||||
<script src="js/vapi-common.js"></script>
|
||||
<script src="js/vapi-background.js"></script>
|
||||
<script src="js/vapi-webrequest.js"></script><!-- Forks can pick the webext, chromium, or their own implementation -->
|
||||
<script src="js/vapi-cachestorage.js"></script><!-- Optional -->
|
||||
<script src="js/background.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/uritools.js"></script>
|
||||
|
|
|
|||
20
src/cloud-ui.html
Normal file
20
src/cloud-ui.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<button id="cloudPush" type="button" title="cloudPush"></button>
|
||||
<span data-i18n="cloudNoData"></span>
|
||||
<button id="cloudPull" type="button" title="cloudPull" disabled></button>
|
||||
<button id="cloudPullAndMerge" type="button" title="cloudPullAndMerge" disabled></button>
|
||||
<span id="cloudCog" class="fa"></span>
|
||||
<div id="cloudOptions">
|
||||
<div>
|
||||
<p><label data-i18n="cloudDeviceNamePrompt"></label> <input id="cloudDeviceName" type="text" value="">
|
||||
<p><button id="cloudOptionsSubmit" type="button" data-i18n="genericSubmit"></button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
ul {
|
||||
padding-__MSG_@@bidi_start_edge__: 1em;
|
||||
margin-__MSG_@@bidi_start_edge__: 1em;
|
||||
}
|
||||
|
|
@ -578,12 +578,12 @@ body.colorBlind #netFilteringDialog .dialog > div.containers > div.dynamic tr.e
|
|||
|
||||
#filterFinderDialog .dialog {
|
||||
padding: 1em;
|
||||
word-break: break-all;
|
||||
}
|
||||
#filterFinderDialog .dialog code {
|
||||
background: #eee;
|
||||
font-size: 85%;
|
||||
padding: 3px;
|
||||
word-break: break-all;
|
||||
}
|
||||
#filterFinderDialog .dialog ul {
|
||||
font-size: larger;
|
||||
|
|
|
|||
|
|
@ -193,20 +193,24 @@ body[dir="ltr"] #extraTools > span > span.badge {
|
|||
body[dir="rtl"] #extraTools > span > span.badge {
|
||||
right: 100%;
|
||||
}
|
||||
#extraTools > span.on > span:last-of-type {
|
||||
#extraTools > span > span:last-of-type {
|
||||
color: #e00;
|
||||
font-size: 1.1em;
|
||||
left: 0;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
transform: translateX(-50%);
|
||||
visibility: hidden;
|
||||
}
|
||||
#extraTools > span.on > span:last-of-type:after {
|
||||
content: '\2715';
|
||||
#extraTools > span > span:last-of-type > svg {
|
||||
stroke: red;
|
||||
stroke-width: 2;
|
||||
width: 1em;
|
||||
}
|
||||
#extraTools > span.on > span:last-of-type {
|
||||
visibility: visible;
|
||||
}
|
||||
#extraTools > span:hover {
|
||||
color: #444;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#refresh {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<link rel="stylesheet" href="css/common.css" type="text/css">
|
||||
<style>
|
||||
|
|
|
|||
|
|
@ -985,6 +985,22 @@ var updateFirst = function() {
|
|||
updateNext();
|
||||
};
|
||||
|
||||
// Firefox extension reviewers do not want uBO/webext to fetch its *own*
|
||||
// scriptlets/resources asset from the project's *own* repo (github.com).
|
||||
var noRemoteResources = false;
|
||||
(function() {
|
||||
if (
|
||||
typeof browser === 'object' &&
|
||||
browser !== null &&
|
||||
browser.runtime instanceof Object &&
|
||||
typeof browser.runtime.getBrowserInfo === 'function'
|
||||
) {
|
||||
browser.runtime.getBrowserInfo().then(function(info) {
|
||||
noRemoteResources = info.vendor === 'Mozilla';
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
var updateNext = function() {
|
||||
var assetDict, cacheDict;
|
||||
|
||||
|
|
@ -1007,6 +1023,10 @@ var updateNext = function() {
|
|||
if ( cacheEntry && (cacheEntry.writeTime + assetEntry.updateAfter * 86400000) > now ) {
|
||||
continue;
|
||||
}
|
||||
// Update of user scripts/resources forbidden?
|
||||
if ( assetKey === 'ublock-resources' && noRemoteResources === true ) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
fireNotification(
|
||||
'before-asset-updated',
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ var µBlock = (function() { // jshint ignore:line
|
|||
'behind-the-scene',
|
||||
'chrome-extension-scheme',
|
||||
'chrome-scheme',
|
||||
'loopconversation.about-scheme',
|
||||
'moz-extension-scheme',
|
||||
'opera-scheme',
|
||||
'vivaldi-scheme',
|
||||
|
|
|
|||
|
|
@ -182,30 +182,32 @@ var onInitialize = function(options) {
|
|||
|
||||
fetchCloudData();
|
||||
|
||||
var html = [
|
||||
'<button id="cloudPush" type="button" title="cloudPush"></button>',
|
||||
'<span data-i18n="cloudNoData"></span>',
|
||||
'<button id="cloudPull" type="button" title="cloudPull" disabled></button> ',
|
||||
'<button id="cloudPullAndMerge" type="button" title="cloudPullAndMerge" disabled></button>',
|
||||
'<span id="cloudCog" class="fa"></span>',
|
||||
'<div id="cloudOptions">',
|
||||
' <div>',
|
||||
' <p><label data-i18n="cloudDeviceNamePrompt"></label> <input id="cloudDeviceName" type="text" value="">',
|
||||
' <p><button id="cloudOptionsSubmit" type="button" data-i18n="genericSubmit"></button>',
|
||||
' </div>',
|
||||
'</div>',
|
||||
].join('');
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'cloud-ui.html', true);
|
||||
xhr.overrideMimeType('text/html;charset=utf-8');
|
||||
xhr.responseType = 'text';
|
||||
xhr.onload = function() {
|
||||
this.onload = null;
|
||||
var parser = new DOMParser(),
|
||||
parsed = parser.parseFromString(this.responseText, 'text/html'),
|
||||
fromParent = parsed.body;
|
||||
while ( fromParent.firstElementChild !== null ) {
|
||||
widget.appendChild(
|
||||
document.adoptNode(fromParent.firstElementChild)
|
||||
);
|
||||
}
|
||||
|
||||
vAPI.insertHTML(widget, html);
|
||||
vAPI.i18n.render(widget);
|
||||
widget.classList.remove('hide');
|
||||
vAPI.i18n.render(widget);
|
||||
widget.classList.remove('hide');
|
||||
|
||||
uDom('#cloudPush').on('click', pushData);
|
||||
uDom('#cloudPull').on('click', pullData);
|
||||
uDom('#cloudPullAndMerge').on('click', pullAndMergeData);
|
||||
uDom('#cloudCog').on('click', openOptions);
|
||||
uDom('#cloudOptions').on('click', closeOptions);
|
||||
uDom('#cloudOptionsSubmit').on('click', submitOptions);
|
||||
uDom('#cloudPush').on('click', pushData);
|
||||
uDom('#cloudPull').on('click', pullData);
|
||||
uDom('#cloudPullAndMerge').on('click', pullAndMergeData);
|
||||
uDom('#cloudCog').on('click', openOptions);
|
||||
uDom('#cloudOptions').on('click', closeOptions);
|
||||
uDom('#cloudOptionsSubmit').on('click', submitOptions);
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
messaging.send('cloudWidget', { what: 'cloudGetOptions' }, onInitialize);
|
||||
|
|
|
|||
|
|
@ -77,17 +77,15 @@
|
|||
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
// Abort execution if our global vAPI object does not exist.
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/456
|
||||
// https://github.com/gorhill/uBlock/issues/2029
|
||||
|
||||
// Abort execution by throwing if an unexpected condition arise.
|
||||
// - https://github.com/chrisaljoudi/uBlock/issues/456
|
||||
if ( typeof vAPI !== 'undefined' ) { // >>>>>>>> start of HUGE-IF-BLOCK
|
||||
|
||||
if ( typeof vAPI !== 'object' ) {
|
||||
throw new Error('uBlock Origin: aborting content scripts for ' + window.location);
|
||||
}
|
||||
vAPI.lock();
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.matchesProp = (function() {
|
||||
var docElem = document.documentElement;
|
||||
|
|
@ -131,6 +129,20 @@ vAPI.SafeAnimationFrame.prototype.clear = function() {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.injectScriptlet = function(doc, text) {
|
||||
if ( !doc ) { return; }
|
||||
try {
|
||||
var script = doc.createElement('script');
|
||||
script.appendChild(doc.createTextNode(text));
|
||||
(doc.head || doc.documentElement).appendChild(script);
|
||||
} catch (ex) {
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// The DOM filterer is the heart of uBO's cosmetic filtering.
|
||||
|
||||
vAPI.domFilterer = (function() {
|
||||
|
|
@ -167,6 +179,10 @@ var cosmeticFiltersActivated = function() {
|
|||
// Probably no longer need to watch for style tags removal/tampering with fix
|
||||
// to https://github.com/gorhill/uBlock/issues/963
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2810
|
||||
// With Firefox Nightly, it may happens style tags are injected before the
|
||||
// head element is present.
|
||||
|
||||
var platformUserCSS = (function() {
|
||||
if ( vAPI.userCSS instanceof Object ) {
|
||||
return vAPI.userCSS;
|
||||
|
|
@ -179,8 +195,9 @@ var platformUserCSS = (function() {
|
|||
var style = document.createElement('style');
|
||||
style.setAttribute('type', 'text/css');
|
||||
style.textContent = css;
|
||||
if ( document.head ) {
|
||||
document.head.appendChild(style);
|
||||
var parent = document.head || document.documentElement;
|
||||
if ( parent !== null ) {
|
||||
parent.appendChild(style);
|
||||
}
|
||||
this.styles.push(style);
|
||||
if ( style.sheet ) {
|
||||
|
|
@ -800,7 +817,6 @@ return domFilterer;
|
|||
if ( !cfeDetails || !cfeDetails.ready ) {
|
||||
vAPI.domWatcher = vAPI.domCollapser = vAPI.domFilterer =
|
||||
vAPI.domSurveyor = vAPI.domIsLoaded = null;
|
||||
vAPI.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -836,7 +852,6 @@ return domFilterer;
|
|||
// Library of resources is located at:
|
||||
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
||||
if ( cfeDetails.scripts ) {
|
||||
elem = document.createElement('script');
|
||||
// Have the injected script tag remove itself when execution completes:
|
||||
// to keep DOM as clean as possible.
|
||||
text = cfeDetails.scripts +
|
||||
|
|
@ -848,8 +863,7 @@ return domFilterer;
|
|||
" p.removeChild(c);\n" +
|
||||
" }\n" +
|
||||
"})();";
|
||||
elem.appendChild(document.createTextNode(text));
|
||||
parent.appendChild(elem);
|
||||
vAPI.injectScriptlet(document, text);
|
||||
vAPI.injectedScripts = text;
|
||||
}
|
||||
}
|
||||
|
|
@ -885,7 +899,7 @@ return domFilterer;
|
|||
vAPI.domWatcher = (function() {
|
||||
|
||||
var domLayoutObserver = null,
|
||||
ignoreTags = { 'head': 1, 'link': 1, 'meta': 1, 'script': 1, 'style': 1 },
|
||||
ignoreTags = new Set([ 'head', 'link', 'meta', 'script', 'style' ]),
|
||||
addedNodeLists = [],
|
||||
addedNodes = [],
|
||||
removedNodes = false,
|
||||
|
|
@ -894,30 +908,30 @@ vAPI.domWatcher = (function() {
|
|||
var safeObserverHandler = function() {
|
||||
safeObserverHandlerTimer.clear();
|
||||
var i = addedNodeLists.length,
|
||||
j = addedNodes.length,
|
||||
nodeList, iNode, node;
|
||||
while ( i-- ) {
|
||||
nodeList = addedNodeLists[i];
|
||||
iNode = nodeList.length;
|
||||
while ( iNode-- ) {
|
||||
node = nodeList[iNode];
|
||||
if ( node.nodeType !== 1 ) {
|
||||
continue;
|
||||
if (
|
||||
node.nodeType === 1 &&
|
||||
ignoreTags.has(node.localName) === false &&
|
||||
node.parentElement !== null
|
||||
) {
|
||||
addedNodes[j++] = node;
|
||||
}
|
||||
if ( ignoreTags[node.localName] === 1 ) {
|
||||
continue;
|
||||
}
|
||||
addedNodes.push(node);
|
||||
}
|
||||
}
|
||||
addedNodeLists.length = 0;
|
||||
if ( addedNodes.length !== 0 || removedNodes ) {
|
||||
listeners[0](addedNodes);
|
||||
if ( listeners[1] ) {
|
||||
listeners[1](addedNodes);
|
||||
}
|
||||
addedNodes.length = 0;
|
||||
removedNodes = false;
|
||||
if ( j === 0 && removedNodes === false ) { return; }
|
||||
listeners[0](addedNodes);
|
||||
if ( listeners[1] ) {
|
||||
listeners[1](addedNodes);
|
||||
}
|
||||
addedNodes.length = 0;
|
||||
removedNodes = false;
|
||||
};
|
||||
|
||||
var safeObserverHandlerTimer = new vAPI.SafeAnimationFrame(safeObserverHandler);
|
||||
|
|
@ -994,78 +1008,94 @@ vAPI.domWatcher = (function() {
|
|||
/******************************************************************************/
|
||||
|
||||
vAPI.domCollapser = (function() {
|
||||
var timer = null;
|
||||
var pendingRequests = Object.create(null);
|
||||
var roundtripRequests = [];
|
||||
var resquestIdGenerator = 1,
|
||||
processTimer,
|
||||
toProcess = [],
|
||||
toFilter = [],
|
||||
toCollapse = new Map(),
|
||||
cachedBlockedSet,
|
||||
cachedBlockedSetHash,
|
||||
cachedBlockedSetTimer;
|
||||
var src1stProps = {
|
||||
'embed': 'src',
|
||||
'iframe': 'src',
|
||||
'img': 'src',
|
||||
'object': 'data'
|
||||
};
|
||||
var src2ndProps = {
|
||||
'img': 'srcset'
|
||||
};
|
||||
var netSelectorCacheCount = 0;
|
||||
var messaging = vAPI.messaging;
|
||||
var tagToTypeMap = {
|
||||
embed: 'object',
|
||||
iframe: 'sub_frame',
|
||||
img: 'image',
|
||||
object: 'object'
|
||||
};
|
||||
var netSelectorCacheCount = 0,
|
||||
messaging = vAPI.messaging;
|
||||
|
||||
// Because a while ago I have observed constructors are faster than
|
||||
// literal object instanciations.
|
||||
var RoundtripRequest = function(tag, attr, url) {
|
||||
this.tag = tag;
|
||||
this.attr = attr;
|
||||
this.url = url;
|
||||
this.collapse = false;
|
||||
var cachedBlockedSetClear = function() {
|
||||
cachedBlockedSet =
|
||||
cachedBlockedSetHash =
|
||||
cachedBlockedSetTimer = undefined;
|
||||
};
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
||||
// Do not remove fragment from src URL
|
||||
var onProcessed = function(response) {
|
||||
// This can happens if uBO is restarted.
|
||||
if ( !response ) {
|
||||
if ( !response ) { // This happens if uBO is disabled or restarted.
|
||||
toCollapse.clear();
|
||||
return;
|
||||
}
|
||||
var requests = response.result;
|
||||
if ( requests === null || Array.isArray(requests) === false ) {
|
||||
|
||||
var targets = toCollapse.get(response.id);
|
||||
if ( targets === undefined ) { return; }
|
||||
toCollapse.delete(response.id);
|
||||
if ( cachedBlockedSetHash !== response.hash ) {
|
||||
cachedBlockedSet = new Set(response.blockedResources);
|
||||
cachedBlockedSetHash = response.hash;
|
||||
if ( cachedBlockedSetTimer !== undefined ) {
|
||||
clearTimeout(cachedBlockedSetTimer);
|
||||
}
|
||||
cachedBlockedSetTimer = vAPI.setTimeout(cachedBlockedSetClear, 30000);
|
||||
}
|
||||
if ( cachedBlockedSet === undefined || cachedBlockedSet.size === 0 ) {
|
||||
return;
|
||||
}
|
||||
var selectors = [],
|
||||
iframeLoadEventPatch = vAPI.iframeLoadEventPatch,
|
||||
netSelectorCacheCountMax = response.netSelectorCacheCountMax,
|
||||
aa = [ null ],
|
||||
request, key, entry, target, value;
|
||||
// https://github.com/gorhill/uBlock/issues/2256
|
||||
var iframeLoadEventPatch = vAPI.iframeLoadEventPatch;
|
||||
// Important: process in chronological order -- this ensures the
|
||||
// cached selectors are the most useful ones.
|
||||
for ( var i = 0, ni = requests.length; i < ni; i++ ) {
|
||||
request = requests[i];
|
||||
key = request.tag + ' ' + request.attr + ' ' + request.url;
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
tag, prop, src, value;
|
||||
|
||||
for ( var target of targets ) {
|
||||
tag = target.localName;
|
||||
prop = src1stProps[tag];
|
||||
if ( prop === undefined ) { continue; }
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
prop = src2ndProps[tag];
|
||||
if ( prop === undefined ) { continue; }
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) { continue; }
|
||||
}
|
||||
if ( cachedBlockedSet.has(tagToTypeMap[tag] + ' ' + src) === false ) {
|
||||
continue;
|
||||
}
|
||||
delete pendingRequests[key];
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/869
|
||||
if ( !request.collapse ) {
|
||||
continue;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/399
|
||||
// Never remove elements from the DOM, just hide them
|
||||
target.style.setProperty('display', 'none', 'important');
|
||||
target.hidden = true;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1048
|
||||
// Use attribute to construct CSS rule
|
||||
if (
|
||||
netSelectorCacheCount <= netSelectorCacheCountMax &&
|
||||
(value = target.getAttribute(prop))
|
||||
) {
|
||||
selectors.push(tag + '[' + prop + '="' + value + '"]');
|
||||
netSelectorCacheCount += 1;
|
||||
}
|
||||
if ( Array.isArray(entry) === false ) {
|
||||
aa[0] = entry;
|
||||
entry = aa;
|
||||
}
|
||||
for ( var j = 0, nj = entry.length; j < nj; j++ ) {
|
||||
target = entry[j];
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/399
|
||||
// Never remove elements from the DOM, just hide them
|
||||
target.style.setProperty('display', 'none', 'important');
|
||||
target.hidden = true;
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1048
|
||||
// Use attribute to construct CSS rule
|
||||
if (
|
||||
netSelectorCacheCount <= netSelectorCacheCountMax &&
|
||||
(value = target.getAttribute(request.attr))
|
||||
) {
|
||||
selectors.push(request.tag + '[' + request.attr + '="' + value + '"]');
|
||||
netSelectorCacheCount += 1;
|
||||
}
|
||||
if ( iframeLoadEventPatch ) { iframeLoadEventPatch(target); }
|
||||
if ( iframeLoadEventPatch !== undefined ) {
|
||||
iframeLoadEventPatch(target);
|
||||
}
|
||||
}
|
||||
if ( selectors.length !== 0 ) {
|
||||
|
|
@ -1082,9 +1112,10 @@ vAPI.domCollapser = (function() {
|
|||
};
|
||||
|
||||
var send = function() {
|
||||
timer = null;
|
||||
processTimer = undefined;
|
||||
toCollapse.set(resquestIdGenerator, toProcess);
|
||||
// https://github.com/gorhill/uBlock/issues/1927
|
||||
// Normalize hostname to avoid trailing dot of FQHN.
|
||||
// Normalize hostname to avoid trailing dot of FQHN.
|
||||
var pageHostname = window.location.hostname || '';
|
||||
if (
|
||||
pageHostname.length &&
|
||||
|
|
@ -1092,62 +1123,34 @@ vAPI.domCollapser = (function() {
|
|||
) {
|
||||
pageHostname = pageHostname.slice(0, -1);
|
||||
}
|
||||
messaging.send(
|
||||
'contentscript',
|
||||
{
|
||||
what: 'filterRequests',
|
||||
pageURL: window.location.href,
|
||||
pageHostname: pageHostname,
|
||||
requests: roundtripRequests
|
||||
}, onProcessed
|
||||
);
|
||||
roundtripRequests = [];
|
||||
var msg = {
|
||||
what: 'getCollapsibleBlockedRequests',
|
||||
id: resquestIdGenerator,
|
||||
pageURL: window.location.href,
|
||||
pageHostname: pageHostname,
|
||||
resources: toFilter,
|
||||
hash: cachedBlockedSetHash
|
||||
};
|
||||
messaging.send('contentscript', msg, onProcessed);
|
||||
toProcess = [];
|
||||
toFilter = [];
|
||||
resquestIdGenerator += 1;
|
||||
};
|
||||
|
||||
var process = function(delay) {
|
||||
if ( roundtripRequests.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
if ( toProcess.length === 0 ) { return; }
|
||||
if ( delay === 0 ) {
|
||||
clearTimeout(timer);
|
||||
if ( processTimer !== undefined ) {
|
||||
clearTimeout(processTimer);
|
||||
}
|
||||
send();
|
||||
} else if ( timer === null ) {
|
||||
timer = vAPI.setTimeout(send, delay || 20);
|
||||
} else if ( processTimer === undefined ) {
|
||||
processTimer = vAPI.setTimeout(send, delay || 20);
|
||||
}
|
||||
};
|
||||
|
||||
var add = function(target) {
|
||||
var tag = target.localName;
|
||||
var prop = src1stProps[tag];
|
||||
if ( prop === undefined ) {
|
||||
return;
|
||||
}
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
||||
// Do not remove fragment from src URL
|
||||
var src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
prop = src2ndProps[tag];
|
||||
if ( prop === undefined ) {
|
||||
return;
|
||||
}
|
||||
src = target[prop];
|
||||
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var key = tag + ' ' + prop + ' ' + src,
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
pendingRequests[key] = target;
|
||||
roundtripRequests.push(new RoundtripRequest(tag, prop, src));
|
||||
} else if ( Array.isArray(entry) ) {
|
||||
entry.push(target);
|
||||
} else {
|
||||
pendingRequests[key] = [ entry, target ];
|
||||
}
|
||||
toProcess[toProcess.length] = target;
|
||||
};
|
||||
|
||||
var addMany = function(targets) {
|
||||
|
|
@ -1177,12 +1180,7 @@ vAPI.domCollapser = (function() {
|
|||
// and which scripts are selectively looked-up from:
|
||||
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
||||
if ( vAPI.injectedScripts ) {
|
||||
var scriptTag = document.createElement('script');
|
||||
scriptTag.appendChild(document.createTextNode(vAPI.injectedScripts));
|
||||
var parent = iframe.contentDocument && iframe.contentDocument.head;
|
||||
if ( parent ) {
|
||||
parent.appendChild(scriptTag);
|
||||
}
|
||||
vAPI.injectScriptlet(iframe.contentDocument, vAPI.injectedScripts);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1198,19 +1196,12 @@ vAPI.domCollapser = (function() {
|
|||
primeLocalIFrame(iframe);
|
||||
return;
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
var key = 'iframe' + ' ' + 'src' + ' ' + src,
|
||||
entry = pendingRequests[key];
|
||||
if ( entry === undefined ) {
|
||||
pendingRequests[key] = iframe;
|
||||
roundtripRequests.push(new RoundtripRequest('iframe', 'src', src));
|
||||
} else if ( Array.isArray(entry) ) {
|
||||
entry.push(iframe);
|
||||
} else {
|
||||
pendingRequests[key] = [ entry, iframe ];
|
||||
}
|
||||
if ( src.lastIndexOf('http', 0) !== 0 ) { return; }
|
||||
toFilter[toFilter.length] = {
|
||||
type: 'sub_frame',
|
||||
url: iframe.src
|
||||
};
|
||||
add(iframe);
|
||||
};
|
||||
|
||||
var addIFrames = function(iframes) {
|
||||
|
|
@ -1221,8 +1212,10 @@ vAPI.domCollapser = (function() {
|
|||
};
|
||||
|
||||
var onResourceFailed = function(ev) {
|
||||
vAPI.domCollapser.add(ev.target);
|
||||
vAPI.domCollapser.process();
|
||||
if ( tagToTypeMap[ev.target.localName] !== undefined ) {
|
||||
vAPI.domCollapser.add(ev.target);
|
||||
vAPI.domCollapser.process();
|
||||
}
|
||||
};
|
||||
|
||||
var domChangedHandler = function(nodes) {
|
||||
|
|
@ -1247,7 +1240,6 @@ vAPI.domCollapser = (function() {
|
|||
// - Future requests not blocked yet
|
||||
// - Elements dynamically added to the page
|
||||
// - Elements which resource URL changes
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/7
|
||||
// Preferring getElementsByTagName over querySelectorAll:
|
||||
// http://jsperf.com/queryselectorall-vs-getelementsbytagname/145
|
||||
|
|
@ -1270,8 +1262,8 @@ vAPI.domCollapser = (function() {
|
|||
vAPI.shutdown.add(function() {
|
||||
document.removeEventListener('error', onResourceFailed, true);
|
||||
vAPI.domWatcher.removeListener(domChangedHandler);
|
||||
if ( timer !== null ) {
|
||||
clearTimeout(timer);
|
||||
if ( processTimer !== undefined ) {
|
||||
clearTimeout(processTimer);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -1559,7 +1551,7 @@ vAPI.domSurveyor = (function() {
|
|||
v = node.id;
|
||||
if ( typeof v !== 'string' ) { continue; }
|
||||
v = '#' + v.trim();
|
||||
if ( !qq.has(v) && v.length !== 1 ) {
|
||||
if ( qq.has(v) === false && v.length !== 1 ) {
|
||||
ll[lli] = v; lli++; qq.add(v);
|
||||
}
|
||||
}
|
||||
|
|
@ -1569,9 +1561,9 @@ vAPI.domSurveyor = (function() {
|
|||
node = nodes[i];
|
||||
vv = node.className;
|
||||
if ( typeof vv !== 'string' ) { continue; }
|
||||
if ( !rews.test(vv) ) {
|
||||
if ( rews.test(vv) === false ) {
|
||||
v = '.' + vv;
|
||||
if ( !qq.has(v) && v.length !== 1 ) {
|
||||
if ( qq.has(v) === false && v.length !== 1 ) {
|
||||
ll[lli] = v; lli++; qq.add(v);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1579,7 +1571,7 @@ vAPI.domSurveyor = (function() {
|
|||
j = vv.length;
|
||||
while ( j-- ) {
|
||||
v = '.' + vv[j];
|
||||
if ( !qq.has(v) ) {
|
||||
if ( qq.has(v) === false ) {
|
||||
ll[lli] = v; lli++; qq.add(v);
|
||||
}
|
||||
}
|
||||
|
|
@ -1623,9 +1615,7 @@ vAPI.domSurveyor = (function() {
|
|||
vAPI.domIsLoaded = function(ev) {
|
||||
// This can happen on Firefox. For instance:
|
||||
// https://github.com/gorhill/uBlock/issues/1893
|
||||
if ( window.location === null ) {
|
||||
return;
|
||||
}
|
||||
if ( window.location === null ) { return; }
|
||||
|
||||
var slowLoad = ev instanceof Event;
|
||||
if ( slowLoad ) {
|
||||
|
|
@ -1690,3 +1680,5 @@ vAPI.domIsLoaded = function(ev) {
|
|||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
} // <<<<<<<< end of HUGE-IF-BLOCK
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
if ( vAPI.contextMenu === undefined ) {
|
||||
return {
|
||||
update: function() {}
|
||||
};
|
||||
}
|
||||
|
||||
var µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1529,6 +1529,15 @@ FilterContainer.prototype.retrieveUserScripts = function(domain, hostname) {
|
|||
return;
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2835
|
||||
// Do not inject scriptlets if the site is under an `allow` rule.
|
||||
if (
|
||||
µb.userSettings.advancedUserEnabled === true &&
|
||||
µb.sessionFirewall.evaluateCellZY(hostname, hostname, '*') === 2
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exceptions should be rare, so we check for exception only if there are
|
||||
// scriptlets returned.
|
||||
var exceptions = [], j, token;
|
||||
|
|
|
|||
|
|
@ -701,16 +701,22 @@ var netFilteringManager = (function() {
|
|||
};
|
||||
|
||||
var parseStaticInputs = function() {
|
||||
var filter = '';
|
||||
var options = [];
|
||||
var block = selectValue('select.static.action') === '';
|
||||
var filter = '',
|
||||
options = [],
|
||||
block = selectValue('select.static.action') === '';
|
||||
if ( !block ) {
|
||||
filter = '@@';
|
||||
}
|
||||
var value = selectValue('select.static.url');
|
||||
if ( value !== '' ) {
|
||||
filter += '||' + value;
|
||||
if ( value.slice(-1) === '/' ) {
|
||||
value += '*';
|
||||
} else if ( /[/?]/.test(value) === false ) {
|
||||
value += '^';
|
||||
}
|
||||
value = '||' + value;
|
||||
}
|
||||
filter += value;
|
||||
value = selectValue('select.static.type');
|
||||
if ( value !== '' ) {
|
||||
options.push(uglyTypeFromSelector('static'));
|
||||
|
|
@ -974,7 +980,7 @@ var netFilteringManager = (function() {
|
|||
if ( pos === -1 ) {
|
||||
pos = path.length;
|
||||
}
|
||||
urls.unshift(rootURL + path.slice(0, pos));
|
||||
urls.unshift(rootURL + path.slice(0, pos + 1));
|
||||
}
|
||||
var query = matches[4] || '';
|
||||
if ( query !== '') {
|
||||
|
|
@ -1042,7 +1048,7 @@ var netFilteringManager = (function() {
|
|||
var rePlaceholder = /\{\{[^}]+?\}\}/g;
|
||||
var nodes = [];
|
||||
var match, pos = 0;
|
||||
var select, option, i, value;
|
||||
var select, option, n, i, value;
|
||||
for (;;) {
|
||||
match = rePlaceholder.exec(template);
|
||||
if ( match === null ) {
|
||||
|
|
@ -1088,8 +1094,8 @@ var netFilteringManager = (function() {
|
|||
case '{{url}}':
|
||||
select = document.createElement('select');
|
||||
select.className = 'static url';
|
||||
for ( i = 0; i < targetURLs.length; i++ ) {
|
||||
value = targetURLs[i].replace(/^[a-z]+:\/\//, '');
|
||||
for ( i = 0, n = targetURLs.length; i < n; i++ ) {
|
||||
value = targetURLs[i].replace(/^[a-z-]+:\/\//, '');
|
||||
option = document.createElement('option');
|
||||
option.setAttribute('value', value);
|
||||
option.textContent = shortenLongString(value, 128);
|
||||
|
|
@ -1221,8 +1227,8 @@ var reverseLookupManager = (function() {
|
|||
if ( Array.isArray(lists) === false || lists.length === 0 ) {
|
||||
return null;
|
||||
}
|
||||
var node;
|
||||
var p = document.createElement('p');
|
||||
var node,
|
||||
p = document.createElement('p');
|
||||
|
||||
reSentence1.lastIndex = 0;
|
||||
var matches = reSentence1.exec(sentence1Template);
|
||||
|
|
@ -1231,7 +1237,10 @@ var reverseLookupManager = (function() {
|
|||
} else {
|
||||
node = uDom.nodeFromSelector('#filterFinderDialogSentence1 > span').cloneNode(true);
|
||||
node.childNodes[0].textContent = sentence1Template.slice(0, matches.index);
|
||||
node.childNodes[1].textContent = filter;
|
||||
// https://github.com/gorhill/uBlock/issues/2753
|
||||
node.childNodes[1].textContent = filter.length <= 1024
|
||||
? filter
|
||||
: filter.slice(0, 1023) + '…';
|
||||
node.childNodes[2].textContent = sentence1Template.slice(reSentence1.lastIndex);
|
||||
}
|
||||
p.appendChild(node);
|
||||
|
|
@ -1267,9 +1276,7 @@ var reverseLookupManager = (function() {
|
|||
|
||||
for ( var filter in response ) {
|
||||
var p = nodeFromFilter(filter, response[filter]);
|
||||
if ( p === null ) {
|
||||
continue;
|
||||
}
|
||||
if ( p === null ) { continue; }
|
||||
dialog.appendChild(p);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -452,56 +452,6 @@ vAPI.messaging.listen('popupPanel', onMessage);
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var tagNameToRequestTypeMap = {
|
||||
'embed': 'object',
|
||||
'iframe': 'sub_frame',
|
||||
'img': 'image',
|
||||
'object': 'object'
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// Evaluate many requests.
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1782
|
||||
// Treat `data:` URIs as 1st-party resources.
|
||||
|
||||
var filterRequests = function(pageStore, details) {
|
||||
var requests = details.requests;
|
||||
if ( µb.userSettings.collapseBlocked === false ) {
|
||||
return requests;
|
||||
}
|
||||
|
||||
//console.debug('messaging.js/contentscript-end.js: processing %d requests', requests.length);
|
||||
|
||||
var hostnameFromURI = µb.URI.hostnameFromURI,
|
||||
redirectEngine = µb.redirectEngine,
|
||||
punycodeURL = vAPI.punycodeURL;
|
||||
|
||||
// Create evaluation context
|
||||
var context = pageStore.createContextFromFrameHostname(details.pageHostname),
|
||||
request,
|
||||
i = requests.length;
|
||||
while ( i-- ) {
|
||||
request = requests[i];
|
||||
context.requestURL = punycodeURL(request.url);
|
||||
context.requestHostname = hostnameFromURI(context.requestURL);
|
||||
context.requestType = tagNameToRequestTypeMap[request.tag];
|
||||
if ( pageStore.filterRequest(context) !== 1 ) { continue; }
|
||||
// Redirected? (We do not hide redirected resources.)
|
||||
request.collapse = redirectEngine.matches(context) !== true;
|
||||
}
|
||||
|
||||
context.dispose();
|
||||
return requests;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var onMessage = function(request, sender, callback) {
|
||||
// Async
|
||||
switch ( request.what ) {
|
||||
|
|
@ -510,14 +460,29 @@ var onMessage = function(request, sender, callback) {
|
|||
}
|
||||
|
||||
// Sync
|
||||
var response;
|
||||
|
||||
var pageStore;
|
||||
var µb = µBlock,
|
||||
response,
|
||||
pageStore;
|
||||
if ( sender && sender.tab ) {
|
||||
pageStore = µb.pageStoreFromTabId(sender.tab.id);
|
||||
}
|
||||
|
||||
switch ( request.what ) {
|
||||
case 'getCollapsibleBlockedRequests':
|
||||
response = {
|
||||
id: request.id,
|
||||
hash: request.hash,
|
||||
netSelectorCacheCountMax: µb.cosmeticFilteringEngine.netSelectorCacheCountMax
|
||||
};
|
||||
if (
|
||||
µb.userSettings.collapseBlocked &&
|
||||
pageStore &&
|
||||
pageStore.getNetFilteringSwitch()
|
||||
) {
|
||||
pageStore.getBlockedResources(request, response);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'retrieveContentScriptParameters':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = {
|
||||
|
|
@ -541,15 +506,6 @@ var onMessage = function(request, sender, callback) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'filterRequests':
|
||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||
response = {
|
||||
result: filterRequests(pageStore, request),
|
||||
netSelectorCacheCountMax: µb.cosmeticFilteringEngine.netSelectorCacheCountMax
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return vAPI.messaging.UNHANDLED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*******************************************************************************
|
||||
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2014-2016 Raymond Hill
|
||||
Copyright (C) 2014-2017 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
|
||||
|
|
@ -43,59 +43,22 @@ var µb = µBlock;
|
|||
/******************************************************************************/
|
||||
|
||||
// To mitigate memory churning
|
||||
var netFilteringResultCacheEntryJunkyard = [];
|
||||
var netFilteringResultCacheEntryJunkyardMax = 200;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var NetFilteringResultCacheEntry = function(result, type, logData) {
|
||||
this.init(result, type, logData);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.prototype.init = function(result, type, logData) {
|
||||
this.result = result;
|
||||
this.type = type;
|
||||
this.time = Date.now();
|
||||
this.logData = logData;
|
||||
return this;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.prototype.dispose = function() {
|
||||
this.result = this.type = '';
|
||||
this.logData = undefined;
|
||||
if ( netFilteringResultCacheEntryJunkyard.length < netFilteringResultCacheEntryJunkyardMax ) {
|
||||
netFilteringResultCacheEntryJunkyard.push(this);
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCacheEntry.factory = function(result, type, logData) {
|
||||
if ( netFilteringResultCacheEntryJunkyard.length ) {
|
||||
return netFilteringResultCacheEntryJunkyard.pop().init(result, type, logData);
|
||||
}
|
||||
return new NetFilteringResultCacheEntry(result, type, logData);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
// To mitigate memory churning
|
||||
var netFilteringCacheJunkyard = [];
|
||||
var netFilteringCacheJunkyardMax = 10;
|
||||
var netFilteringCacheJunkyard = [],
|
||||
netFilteringCacheJunkyardMax = 10;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var NetFilteringResultCache = function() {
|
||||
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
|
||||
this.init();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.shelfLife = 15 * 1000;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.factory = function() {
|
||||
var entry = netFilteringCacheJunkyard.pop();
|
||||
if ( entry === undefined ) {
|
||||
|
|
@ -109,18 +72,16 @@ NetFilteringResultCache.factory = function() {
|
|||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.init = function() {
|
||||
this.urls = Object.create(null);
|
||||
this.count = 0;
|
||||
this.shelfLife = 15 * 1000;
|
||||
this.blocked = new Map();
|
||||
this.results = new Map();
|
||||
this.hash = 0;
|
||||
this.timer = null;
|
||||
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.dispose = function() {
|
||||
this.empty();
|
||||
this.boundPruneAsyncCallback = null;
|
||||
if ( netFilteringCacheJunkyard.length < netFilteringCacheJunkyardMax ) {
|
||||
netFilteringCacheJunkyard.push(this);
|
||||
}
|
||||
|
|
@ -129,33 +90,42 @@ NetFilteringResultCache.prototype.dispose = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.add = function(context, result, logData) {
|
||||
var url = context.requestURL,
|
||||
type = context.requestType,
|
||||
key = type + ' ' + url,
|
||||
entry = this.urls[key];
|
||||
if ( entry !== undefined ) {
|
||||
entry.result = result;
|
||||
entry.type = type;
|
||||
entry.time = Date.now();
|
||||
entry.logData = logData;
|
||||
return;
|
||||
}
|
||||
this.urls[key] = NetFilteringResultCacheEntry.factory(result, type, logData);
|
||||
if ( this.count === 0 ) {
|
||||
NetFilteringResultCache.prototype.rememberResult = function(context, result, logData) {
|
||||
if ( this.results.size === 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
this.count += 1;
|
||||
var key = context.pageHostname + ' ' + context.requestType + ' ' + context.requestURL;
|
||||
this.results.set(key, {
|
||||
result: result,
|
||||
logData: logData,
|
||||
tstamp: Date.now()
|
||||
});
|
||||
if ( result !== 1 ) { return; }
|
||||
var now = Date.now();
|
||||
this.blocked.set(key, now);
|
||||
this.hash = now;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.rememberBlock = function(details) {
|
||||
if ( this.blocked.size === 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
var now = Date.now();
|
||||
this.blocked.set(
|
||||
details.pageHostname + ' ' + details.requestType + ' ' + details.requestURL,
|
||||
now
|
||||
);
|
||||
this.hash = now;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.empty = function() {
|
||||
for ( var key in this.urls ) {
|
||||
this.urls[key].dispose();
|
||||
}
|
||||
this.urls = Object.create(null);
|
||||
this.count = 0;
|
||||
this.blocked.clear();
|
||||
this.results.clear();
|
||||
this.hash = 0;
|
||||
if ( this.timer !== null ) {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
|
|
@ -164,36 +134,6 @@ NetFilteringResultCache.prototype.empty = function() {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.compareEntries = function(a, b) {
|
||||
return this.urls[b].time - this.urls[a].time;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.prune = function() {
|
||||
var keys = Object.keys(this.urls).sort(this.compareEntries.bind(this));
|
||||
var obsolete = Date.now() - this.shelfLife;
|
||||
var key, entry;
|
||||
var i = keys.length;
|
||||
while ( i-- ) {
|
||||
key = keys[i];
|
||||
entry = this.urls[key];
|
||||
if ( entry.time > obsolete ) {
|
||||
break;
|
||||
}
|
||||
entry.dispose();
|
||||
delete this.urls[key];
|
||||
}
|
||||
this.count -= keys.length - i - 1;
|
||||
if ( this.count > 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=hcVpbsDyOhM
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.pruneAsync = function() {
|
||||
if ( this.timer === null ) {
|
||||
this.timer = vAPI.setTimeout(this.boundPruneAsyncCallback, this.shelfLife * 2);
|
||||
|
|
@ -202,13 +142,46 @@ NetFilteringResultCache.prototype.pruneAsync = function() {
|
|||
|
||||
NetFilteringResultCache.prototype.pruneAsyncCallback = function() {
|
||||
this.timer = null;
|
||||
this.prune();
|
||||
var obsolete = Date.now() - this.shelfLife,
|
||||
entry;
|
||||
for ( entry of this.blocked ) {
|
||||
if ( entry[1] <= obsolete ) {
|
||||
this.results.delete(entry[0]);
|
||||
this.blocked.delete(entry[0]);
|
||||
}
|
||||
}
|
||||
for ( entry of this.results ) {
|
||||
if ( entry[1].tstamp <= obsolete ) {
|
||||
this.results.delete(entry[0]);
|
||||
}
|
||||
}
|
||||
if ( this.blocked.size !== 0 || this.results.size !== 0 ) {
|
||||
this.pruneAsync();
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.lookup = function(context) {
|
||||
return this.urls[context.requestType + ' ' + context.requestURL] || undefined;
|
||||
NetFilteringResultCache.prototype.lookupResult = function(context) {
|
||||
return this.results.get(
|
||||
context.pageHostname + ' ' +
|
||||
context.requestType + ' ' +
|
||||
context.requestURL
|
||||
);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
NetFilteringResultCache.prototype.lookupAllBlocked = function(hostname) {
|
||||
var result = [],
|
||||
pos;
|
||||
for ( var entry of this.blocked ) {
|
||||
pos = entry[0].indexOf(' ');
|
||||
if ( entry[0].slice(0, pos) === hostname ) {
|
||||
result[result.length] = entry[0].slice(pos + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -610,24 +583,39 @@ PageStore.prototype.journalProcess = function(fromTimer) {
|
|||
PageStore.prototype.filterRequest = function(context) {
|
||||
this.logData = undefined;
|
||||
|
||||
var requestType = context.requestType;
|
||||
|
||||
// We want to short-term cache filtering results of collapsible types,
|
||||
// because they are likely to be reused, from network request handler and
|
||||
// from content script handler.
|
||||
if ( 'image media object sub_frame'.indexOf(requestType) === -1 ) {
|
||||
return this.filterRequestNoCache(context);
|
||||
}
|
||||
|
||||
if ( this.getNetFilteringSwitch() === false ) {
|
||||
this.netFilteringCache.add(context, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var entry = this.netFilteringCache.lookup(context);
|
||||
if ( entry !== undefined ) {
|
||||
this.logData = entry.logData;
|
||||
return entry.result;
|
||||
var requestType = context.requestType;
|
||||
|
||||
if ( requestType === 'csp_report' ) {
|
||||
if ( this.internalRedirectionCount !== 0 ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = { result: 1, source: 'global', raw: 'no-spurious-csp-report' };
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( requestType === 'font' ) {
|
||||
this.remoteFontCount += 1;
|
||||
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = µb.hnSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
var cacheableResult = this.cacheableResults[requestType] === true;
|
||||
|
||||
if ( cacheableResult ) {
|
||||
var entry = this.netFilteringCache.lookupResult(context);
|
||||
if ( entry !== undefined ) {
|
||||
this.logData = entry.logData;
|
||||
return entry.result;
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic URL filtering.
|
||||
|
|
@ -638,13 +626,13 @@ PageStore.prototype.filterRequest = function(context) {
|
|||
|
||||
// Dynamic hostname/type filtering.
|
||||
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
||||
result = µb.sessionFirewall.evaluateCellZY( context.rootHostname, context.requestHostname, requestType);
|
||||
result = µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
|
||||
if ( result !== 0 && result !== 3 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Static filtering: lowest filtering precedence.
|
||||
// Static filtering has lowest precedence.
|
||||
if ( result === 0 || result === 3 ) {
|
||||
result = µb.staticNetFilteringEngine.matchString(context);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
|
|
@ -652,11 +640,26 @@ PageStore.prototype.filterRequest = function(context) {
|
|||
}
|
||||
}
|
||||
|
||||
this.netFilteringCache.add(context, result, this.logData);
|
||||
if ( cacheableResult ) {
|
||||
this.netFilteringCache.rememberResult(context, result, this.logData);
|
||||
} else if ( result === 1 && this.collapsibleResources[requestType] === true ) {
|
||||
this.netFilteringCache.rememberBlock(context, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
PageStore.prototype.cacheableResults = {
|
||||
sub_frame: true
|
||||
};
|
||||
|
||||
PageStore.prototype.collapsibleResources = {
|
||||
image: true,
|
||||
media: true,
|
||||
object: true,
|
||||
sub_frame: true
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// The caller is responsible to check whether filtering is enabled or not.
|
||||
|
|
@ -689,67 +692,28 @@ PageStore.prototype.filterLargeMediaElement = function(size) {
|
|||
return 1;
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=drW8p_dTLD4
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
PageStore.prototype.filterRequestNoCache = function(context) {
|
||||
this.logData = undefined;
|
||||
|
||||
if ( this.getNetFilteringSwitch() === false ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var requestType = context.requestType;
|
||||
|
||||
if ( requestType === 'csp_report' ) {
|
||||
if ( this.internalRedirectionCount !== 0 ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = { result: 1, source: 'global', raw: 'no-spurious-csp-report' };
|
||||
}
|
||||
return 1;
|
||||
PageStore.prototype.getBlockedResources = function(request, response) {
|
||||
var resources = request.resources;
|
||||
if ( Array.isArray(resources) && resources.length !== 0 ) {
|
||||
var context = this.createContextFromFrameHostname(request.pageHostname);
|
||||
for ( var resource of resources ) {
|
||||
context.requestType = resource.type;
|
||||
context.requestHostname = µb.URI.hostnameFromURI(resource.url);
|
||||
context.requestURL = resource.url;
|
||||
this.filterRequest(context);
|
||||
}
|
||||
}
|
||||
|
||||
if ( requestType === 'font' ) {
|
||||
this.remoteFontCount += 1;
|
||||
if ( µb.hnSwitches.evaluateZ('no-remote-fonts', context.rootHostname) !== false ) {
|
||||
if ( µb.logger.isEnabled() ) {
|
||||
this.logData = µb.hnSwitches.toLogData();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if ( this.netFilteringCache.hash === response.hash ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
|
||||
// Dynamic URL filtering.
|
||||
if ( result === 0 ) {
|
||||
result = µb.sessionURLFiltering.evaluateZ(context.rootHostname, context.requestURL, requestType);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionURLFiltering.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic hostname/type filtering.
|
||||
if ( result === 0 && µb.userSettings.advancedUserEnabled ) {
|
||||
result = µb.sessionFirewall.evaluateCellZY(context.rootHostname, context.requestHostname, requestType);
|
||||
if ( result !== 0 && result !== 3 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.sessionFirewall.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
// Static filtering has lowest precedence.
|
||||
if ( result === 0 || result === 3 ) {
|
||||
result = µb.staticNetFilteringEngine.matchString(context);
|
||||
if ( result !== 0 && µb.logger.isEnabled() ) {
|
||||
this.logData = µb.staticNetFilteringEngine.toLogData();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
response.hash = this.netFilteringCache.hash;
|
||||
response.blockedResources = this.netFilteringCache.lookupAllBlocked(request.pageHostname);
|
||||
};
|
||||
|
||||
// https://www.youtube.com/watch?v=drW8p_dTLD4
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -999,7 +999,6 @@ var onHideTooltip = function() {
|
|||
uDom('#switch').on('click', toggleNetFilteringSwitch);
|
||||
uDom('#gotoZap').on('click', gotoZap);
|
||||
uDom('#gotoPick').on('click', gotoPick);
|
||||
uDom('a[href]').on('click', gotoURL);
|
||||
uDom('h2').on('click', toggleFirewallPane);
|
||||
uDom('#refresh').on('click', reloadTab);
|
||||
uDom('.hnSwitch').on('click', toggleHostnameSwitch);
|
||||
|
|
@ -1009,6 +1008,8 @@ var onHideTooltip = function() {
|
|||
|
||||
uDom('body').on('mouseenter', '[data-tip]', onShowTooltip)
|
||||
.on('mouseleave', '[data-tip]', onHideTooltip);
|
||||
|
||||
uDom('a[href]').on('click', gotoURL);
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1546,6 +1546,7 @@ pickerRoot.style.cssText = [
|
|||
'left: 0',
|
||||
'margin: 0',
|
||||
'max-height: none',
|
||||
'max-width: none',
|
||||
'opacity: 1',
|
||||
'outline: 0',
|
||||
'padding: 0',
|
||||
|
|
|
|||
|
|
@ -127,7 +127,10 @@ var onVersionReady = function(lastVersion) {
|
|||
/******************************************************************************/
|
||||
|
||||
var onSelfieReady = function(selfie) {
|
||||
if ( selfie === null || selfie.magic !== µb.systemSettings.selfieMagic ) {
|
||||
if (
|
||||
selfie instanceof Object === false ||
|
||||
selfie.magic !== µb.systemSettings.selfieMagic
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if ( publicSuffixList.fromSelfie(selfie.publicSuffixList) !== true ) {
|
||||
|
|
@ -221,13 +224,13 @@ var onFirstFetchReady = function(fetched) {
|
|||
onNetWhitelistReady(fetched.netWhitelist);
|
||||
onVersionReady(fetched.version);
|
||||
|
||||
// If we have a selfie, skip loading PSL, filters
|
||||
if ( onSelfieReady(fetched.selfie) ) {
|
||||
onAllReady();
|
||||
return;
|
||||
}
|
||||
|
||||
µb.loadPublicSuffixList(onPSLReady);
|
||||
// If we have a selfie, skip loading PSL, filter lists
|
||||
vAPI.cacheStorage.get('selfie', function(bin) {
|
||||
if ( bin instanceof Object && onSelfieReady(bin.selfie) ) {
|
||||
return onAllReady();
|
||||
}
|
||||
µb.loadPublicSuffixList(onPSLReady);
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
@ -266,7 +269,6 @@ var onSelectedFilterListsLoaded = function() {
|
|||
'lastBackupFile': '',
|
||||
'lastBackupTime': 0,
|
||||
'netWhitelist': µb.netWhitelistDefault,
|
||||
'selfie': null,
|
||||
'selfieMagic': '',
|
||||
'version': '0.0.0.0'
|
||||
};
|
||||
|
|
|
|||
|
|
@ -200,7 +200,11 @@ var rawToRegexStr = function(s, anchor) {
|
|||
.replace(me.escape3, '')
|
||||
.replace(me.escape4, '[^ ]*?');
|
||||
if ( anchor & 0x4 ) {
|
||||
reStr = '[0-9a-z.-]*?' + reStr;
|
||||
reStr = (
|
||||
reStr.startsWith('\\.') ?
|
||||
rawToRegexStr.reTextHostnameAnchor2 :
|
||||
rawToRegexStr.reTextHostnameAnchor1
|
||||
) + reStr;
|
||||
} else if ( anchor & 0x2 ) {
|
||||
reStr = '^' + reStr;
|
||||
}
|
||||
|
|
@ -213,6 +217,8 @@ rawToRegexStr.escape1 = /[.+?${}()|[\]\\]/g;
|
|||
rawToRegexStr.escape2 = /\^/g;
|
||||
rawToRegexStr.escape3 = /^\*|\*$/g;
|
||||
rawToRegexStr.escape4 = /\*/g;
|
||||
rawToRegexStr.reTextHostnameAnchor1 = '^[a-z-]+://(?:[^/?#]+\\.)?';
|
||||
rawToRegexStr.reTextHostnameAnchor2 = '^[a-z-]+://(?:[^/?#]+)?';
|
||||
|
||||
var filterFingerprinter = µb.CompiledLineWriter.fingerprint;
|
||||
|
||||
|
|
@ -449,7 +455,7 @@ FilterPlainHostname.prototype.match = function() {
|
|||
FilterPlainHostname.prototype.logData = function() {
|
||||
return {
|
||||
raw: '||' + this.s + '^',
|
||||
regex: rawToRegexStr(this.s, 0x4),
|
||||
regex: rawToRegexStr(this.s + '^'),
|
||||
compiled: this.compile()
|
||||
};
|
||||
};
|
||||
|
|
@ -623,14 +629,13 @@ FilterGenericHnAnchored.prototype.match = function(url) {
|
|||
if ( this.re === null ) {
|
||||
this.re = new RegExp(rawToRegexStr(this.s, this.anchor));
|
||||
}
|
||||
var matchStart = url.search(this.re);
|
||||
return matchStart !== -1 && isHnAnchored(url, matchStart);
|
||||
return this.re.test(url);
|
||||
};
|
||||
|
||||
FilterGenericHnAnchored.prototype.logData = function() {
|
||||
var out = {
|
||||
raw: '||' + this.s,
|
||||
regex: this.re.source,
|
||||
regex: rawToRegexStr(this.s, this.anchor & ~0x4),
|
||||
compiled: this.compile()
|
||||
};
|
||||
return out;
|
||||
|
|
@ -693,23 +698,30 @@ registerFilterClass(FilterGenericHnAndRightAnchored);
|
|||
/******************************************************************************/
|
||||
|
||||
var FilterRegex = function(s) {
|
||||
this.re = new RegExp(s, 'i');
|
||||
this.re = s;
|
||||
};
|
||||
|
||||
FilterRegex.prototype.match = function(url) {
|
||||
if ( typeof this.re === 'string' ) {
|
||||
this.re = new RegExp(this.re, 'i');
|
||||
}
|
||||
return this.re.test(url);
|
||||
};
|
||||
|
||||
FilterRegex.prototype.logData = function() {
|
||||
var s = typeof this.re === 'string' ? this.re : this.re.source;
|
||||
return {
|
||||
raw: '/' + this.re.source + '/',
|
||||
regex: this.re.source,
|
||||
raw: '/' + s + '/',
|
||||
regex: s,
|
||||
compiled: this.compile()
|
||||
};
|
||||
};
|
||||
|
||||
FilterRegex.prototype.compile = function() {
|
||||
return [ this.fid, this.re.source ];
|
||||
return [
|
||||
this.fid,
|
||||
typeof this.re === 'string' ? this.re : this.re.source
|
||||
];
|
||||
};
|
||||
|
||||
FilterRegex.compile = function(details) {
|
||||
|
|
@ -1794,6 +1806,10 @@ FilterParser.prototype.parse = function(raw) {
|
|||
// Hostname-anchored with no wildcard always have a token index of 0.
|
||||
var reHostnameToken = /^[0-9a-z]+/;
|
||||
var reGoodToken = /[%0-9a-z]{2,}/g;
|
||||
var reRegexToken = /[%0-9A-Za-z]{2,}/g;
|
||||
var reRegexTokenAbort = /[([]/;
|
||||
var reRegexBadPrefix = /(^|[^\\]\.|[*?{}\\])$/;
|
||||
var reRegexBadSuffix = /^([^\\]\.|\\[dw]|[([{}?*]|$)/;
|
||||
|
||||
var badTokens = new Set([
|
||||
'com',
|
||||
|
|
@ -1808,9 +1824,10 @@ var badTokens = new Set([
|
|||
'www'
|
||||
]);
|
||||
|
||||
var findFirstGoodToken = function(s) {
|
||||
FilterParser.prototype.findFirstGoodToken = function() {
|
||||
reGoodToken.lastIndex = 0;
|
||||
var matches, lpos,
|
||||
var s = this.f,
|
||||
matches, lpos,
|
||||
badTokenMatch = null;
|
||||
while ( (matches = reGoodToken.exec(s)) !== null ) {
|
||||
// https://github.com/gorhill/uBlock/issues/997
|
||||
|
|
@ -1833,19 +1850,48 @@ var findFirstGoodToken = function(s) {
|
|||
return badTokenMatch;
|
||||
};
|
||||
|
||||
FilterParser.prototype.extractTokenFromRegex = function() {
|
||||
reRegexToken.lastIndex = 0;
|
||||
var s = this.f,
|
||||
matches, prefix;
|
||||
while ( (matches = reRegexToken.exec(s)) !== null ) {
|
||||
prefix = s.slice(0, matches.index);
|
||||
if ( reRegexTokenAbort.test(prefix) ) { return; }
|
||||
if (
|
||||
reRegexBadPrefix.test(prefix) ||
|
||||
reRegexBadSuffix.test(s.slice(reRegexToken.lastIndex))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
this.token = matches[0].toLowerCase();
|
||||
this.tokenHash = µb.urlTokenizer.tokenHashFromString(this.token);
|
||||
this.tokenBeg = matches.index;
|
||||
if ( badTokens.has(this.token) === false ) { break; }
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1038
|
||||
// Single asterisk will match any URL.
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2781
|
||||
// For efficiency purpose, try to extract a token from a regex-based filter.
|
||||
|
||||
FilterParser.prototype.makeToken = function() {
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/1038
|
||||
// Single asterisk will match any URL.
|
||||
if ( this.isRegex || this.f === '*' ) { return; }
|
||||
if ( this.isRegex ) {
|
||||
this.extractTokenFromRegex();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.f === '*' ) { return; }
|
||||
|
||||
var matches = null;
|
||||
if ( (this.anchor & 0x4) !== 0 && this.f.indexOf('*') === -1 ) {
|
||||
matches = reHostnameToken.exec(this.f);
|
||||
}
|
||||
if ( matches === null ) {
|
||||
matches = findFirstGoodToken(this.f);
|
||||
matches = this.findFirstGoodToken();
|
||||
}
|
||||
if ( matches !== null ) {
|
||||
this.token = matches[0];
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@
|
|||
listKey = importedListKeys[i];
|
||||
entry = {
|
||||
content: 'filters',
|
||||
contentURL: importedListKeys[i],
|
||||
contentURL: listKey,
|
||||
external: true,
|
||||
group: 'custom',
|
||||
submitter: 'user',
|
||||
|
|
@ -477,6 +477,31 @@
|
|||
this.assets.registerAssetSource(listKey, entry);
|
||||
}
|
||||
|
||||
// Convert a no longer existing stock list into an imported list.
|
||||
var customListFromStockList = function(assetKey) {
|
||||
var oldEntry = oldAvailableLists[assetKey];
|
||||
if ( oldEntry === undefined || oldEntry.off === true ) { return; }
|
||||
var listURL = oldEntry.contentURL;
|
||||
if ( Array.isArray(listURL) ) {
|
||||
listURL = listURL[0];
|
||||
}
|
||||
var newEntry = {
|
||||
content: 'filters',
|
||||
contentURL: listURL,
|
||||
external: true,
|
||||
group: 'custom',
|
||||
submitter: 'user',
|
||||
title: oldEntry.title || ''
|
||||
};
|
||||
newAvailableLists[listURL] = newEntry;
|
||||
µb.assets.registerAssetSource(listURL, newEntry);
|
||||
importedListKeys.push(listURL);
|
||||
µb.userSettings.externalLists += '\n' + listURL;
|
||||
µb.userSettings.externalLists = µb.userSettings.externalLists.trim();
|
||||
vAPI.storage.set({ externalLists: µb.userSettings.externalLists });
|
||||
µb.saveSelectedFilterLists([ listURL ], true);
|
||||
};
|
||||
|
||||
// Final steps:
|
||||
// - reuse existing list metadata if any;
|
||||
// - unregister unreferenced imported filter lists if any.
|
||||
|
|
@ -487,8 +512,13 @@
|
|||
for ( assetKey in oldAvailableLists ) {
|
||||
oldEntry = oldAvailableLists[assetKey];
|
||||
newEntry = newAvailableLists[assetKey];
|
||||
// List no longer exists. If a stock list, try to convert to
|
||||
// imported list if it was selected.
|
||||
if ( newEntry === undefined ) {
|
||||
µb.removeFilterList(assetKey);
|
||||
if ( assetKey.indexOf('://') === -1 ) {
|
||||
customListFromStockList(assetKey);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ( oldEntry.entryCount !== undefined ) {
|
||||
|
|
|
|||
|
|
@ -650,11 +650,11 @@ vAPI.tabs.onPopupUpdated = (function() {
|
|||
}
|
||||
var re = new RegExp(logData.regex),
|
||||
matches = re.exec(popunderURL);
|
||||
if ( matches === null ) { return ''; }
|
||||
if ( matches === null ) { return 0; }
|
||||
var beg = matches.index,
|
||||
end = beg + matches[0].length,
|
||||
pos = popunderURL.indexOf(popunderHostname);
|
||||
if ( pos === -1 ) { return ''; }
|
||||
if ( pos === -1 ) { return 0; }
|
||||
// https://github.com/gorhill/uBlock/issues/1471
|
||||
// We test whether the opener hostname as at least one character
|
||||
// within matched portion of URL.
|
||||
|
|
@ -749,17 +749,19 @@ vAPI.tabs.onPopupUpdated = (function() {
|
|||
}
|
||||
|
||||
// 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.isEnabled() ) {
|
||||
µb.logger.writeOne(
|
||||
popupType === 'popup' ? openerTabId : targetTabId,
|
||||
'net',
|
||||
logData,
|
||||
result !== 0 ? logData : undefined,
|
||||
popupType,
|
||||
popupType === 'popup' ? targetURL : openerURL,
|
||||
µb.URI.hostnameFromURI(context.rootURL),
|
||||
µb.URI.hostnameFromURI(context.rootURL)
|
||||
);
|
||||
}
|
||||
logData = undefined;
|
||||
|
||||
// Not blocked
|
||||
if ( result !== 1 ) {
|
||||
|
|
@ -901,7 +903,7 @@ vAPI.tabs.registerListeners();
|
|||
if ( vAPI.isBehindTheSceneTabId(tabId) ) {
|
||||
return;
|
||||
}
|
||||
tabIdToTimer[tabId] = vAPI.setTimeout(updateBadge.bind(this, tabId), 666);
|
||||
tabIdToTimer[tabId] = vAPI.setTimeout(updateBadge.bind(this, tabId), 701);
|
||||
};
|
||||
})();
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ var onBeforeBehindTheSceneRequest = function(details) {
|
|||
// working properly, etc.
|
||||
// So we filter if and only if the "advanced user" mode is selected
|
||||
if ( µb.userSettings.advancedUserEnabled ) {
|
||||
result = pageStore.filterRequestNoCache(context);
|
||||
result = pageStore.filterRequest(context);
|
||||
}
|
||||
|
||||
pageStore.journalAddRequest(context.requestHostname, result);
|
||||
|
|
@ -410,15 +410,24 @@ var onHeadersReceived = function(details) {
|
|||
return foilLargeMediaElement(pageStore, details);
|
||||
}
|
||||
|
||||
// https://github.com/gorhill/uBO-Extra/issues/19
|
||||
// Turns out scripts must also be considered as potential embedded
|
||||
// contexts (as workers) and as such we may need to inject content
|
||||
// security policy directives.
|
||||
if ( requestType === 'main_frame' || requestType === 'sub_frame' ) {
|
||||
// https://github.com/gorhill/uBlock/issues/2813
|
||||
// Disable the blocking of large media elements if the document is itself
|
||||
// a media element: the resource was not prevented from loading so no
|
||||
// point to further block large media elements for the current document.
|
||||
if ( requestType === 'main_frame' ) {
|
||||
if ( reMediaContentTypes.test(headerValueFromName('content-type', details.responseHeaders)) ) {
|
||||
pageStore.allowLargeMediaElementsUntil = Date.now() + 86400000;
|
||||
}
|
||||
return injectCSP(pageStore, details);
|
||||
}
|
||||
|
||||
if ( requestType === 'sub_frame' ) {
|
||||
return injectCSP(pageStore, details);
|
||||
}
|
||||
};
|
||||
|
||||
var reMediaContentTypes = /^(?:audio|image|video)\//;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var injectCSP = function(pageStore, details) {
|
||||
|
|
@ -441,7 +450,7 @@ var injectCSP = function(pageStore, details) {
|
|||
|
||||
context.requestType = 'inline-script';
|
||||
context.requestURL = requestURL;
|
||||
if ( pageStore.filterRequestNoCache(context) === 1 ) {
|
||||
if ( pageStore.filterRequest(context) === 1 ) {
|
||||
cspSubsets[0] = "script-src 'unsafe-eval' * blob: data:";
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=669086
|
||||
// TODO: remove when most users are beyond Chromium v56
|
||||
|
|
@ -603,6 +612,11 @@ var headerIndexFromName = function(headerName, headers) {
|
|||
return -1;
|
||||
};
|
||||
|
||||
var headerValueFromName = function(headerName, headers) {
|
||||
var i = headerIndexFromName(headerName, headers);
|
||||
return i !== -1 ? headers[i].value : '';
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
vAPI.net.onBeforeRequest = {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ Naming convention from https://en.wikipedia.org/wiki/URI_scheme#Examples
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
var punycode = self.punycode;
|
||||
|
||||
// Favorite regex tool: http://regex101.com/
|
||||
|
||||
// Ref: <http://tools.ietf.org/html/rfc3986#page-50>
|
||||
|
|
@ -52,6 +54,7 @@ var reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
|
|||
var reOriginFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]+)/;
|
||||
var reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
|
||||
var rePathFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?([^?#]*)/;
|
||||
var reMustNormalizeHostname = /[^0-9a-z._-]/;
|
||||
|
||||
// These are to parse authority field, not parsed by above official regex
|
||||
// IPv6 is seen as an exception: a non-compatible IPv6 is first tried, and
|
||||
|
|
@ -61,11 +64,11 @@ var rePathFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?([^?#]*)/;
|
|||
// https://github.com/gorhill/httpswitchboard/issues/211
|
||||
// "While a hostname may not contain other characters, such as the
|
||||
// "underscore character (_), other DNS names may contain the underscore"
|
||||
var reHostPortFromAuthority = /^(?:[^@]*@)?([0-9a-z._-]*)(:\d*)?$/i;
|
||||
var reHostPortFromAuthority = /^(?:[^@]*@)?([^:]*)(:\d*)?$/;
|
||||
var reIPv6PortFromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]*\])(:\d*)?$/i;
|
||||
|
||||
var reHostFromNakedAuthority = /^[0-9a-z._-]+[0-9a-z]$/i;
|
||||
var reHostFromAuthority = /^(?:[^@]*@)?([0-9a-z._-]+)(?::\d*)?$/i;
|
||||
var reHostFromAuthority = /^(?:[^@]*@)?([^:]+)(?::\d*)?$/;
|
||||
var reIPv6FromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]+\])(?::\d*)?$/i;
|
||||
|
||||
// Coarse (but fast) tests
|
||||
|
|
@ -250,35 +253,34 @@ URI.authorityFromURI = function(uri) {
|
|||
|
||||
// The most used function, so it better be fast.
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/1559
|
||||
// See http://en.wikipedia.org/wiki/FQDN
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1360285
|
||||
// Revisit punycode dependency when above issue is fixed in Firefox.
|
||||
|
||||
URI.hostnameFromURI = function(uri) {
|
||||
var matches = reCommonHostnameFromURL.exec(uri);
|
||||
if ( matches ) {
|
||||
return matches[1];
|
||||
}
|
||||
if ( matches !== null ) { return matches[1]; }
|
||||
matches = reAuthorityFromURI.exec(uri);
|
||||
if ( !matches ) {
|
||||
return '';
|
||||
}
|
||||
if ( matches === null ) { return ''; }
|
||||
var authority = matches[1].slice(2);
|
||||
// Assume very simple authority (most common case for µBlock)
|
||||
if ( reHostFromNakedAuthority.test(authority) ) {
|
||||
return authority.toLowerCase();
|
||||
}
|
||||
matches = reHostFromAuthority.exec(authority);
|
||||
if ( !matches ) {
|
||||
if ( matches === null ) {
|
||||
matches = reIPv6FromAuthority.exec(authority);
|
||||
if ( !matches ) {
|
||||
return '';
|
||||
}
|
||||
if ( matches === null ) { return ''; }
|
||||
}
|
||||
// http://en.wikipedia.org/wiki/FQDN
|
||||
// Also:
|
||||
// - https://github.com/gorhill/uBlock/issues/1559
|
||||
var hostname = matches[1];
|
||||
while ( hostname.endsWith('.') ) {
|
||||
hostname = hostname.slice(0, -1);
|
||||
}
|
||||
return hostname.toLowerCase();
|
||||
if ( reMustNormalizeHostname.test(hostname) ) {
|
||||
hostname = punycode.toASCII(hostname.toLowerCase());
|
||||
}
|
||||
return hostname;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<p id="basicTools">
|
||||
<span id="gotoZap" class="fa tool" data-i18n-tip="popupTipZapper" data-tip-position="under"></span>
|
||||
<span id="gotoPick" class="fa tool" data-i18n-tip="popupTipPicker" data-tip-position="under"></span>
|
||||
<a href="logger-ui.html" class="fa tool enabled" data-i18n-tip="popupTipLog" data-tip-position="under"></a>
|
||||
<a href="dashboard.html" class="fa tool enabled" data-i18n-tip="popupTipDashboard" data-tip-position="under"></a>
|
||||
<a href="logger-ui.html" class="fa tool enabled" data-i18n-tip="popupTipLog" data-tip-position="under" target="uBOLogger"></a>
|
||||
<a href="dashboard.html" class="fa tool enabled" data-i18n-tip="popupTipDashboard" data-tip-position="under" target="uBODashboard"></a>
|
||||
</p>
|
||||
<h2 id="dfToggler" data-i18n="popupBlockedRequestPrompt"> </h2>
|
||||
<p class="statName">
|
||||
|
|
@ -33,10 +33,10 @@
|
|||
<h2 data-i18n="popupHitDomainCountPrompt"> </h2>
|
||||
<p class="statValue" id="popupHitDomainCount"> </p>
|
||||
<div id="extraTools">
|
||||
<span id="no-popups" class="hnSwitch fa" data-i18n-tip="popupTipNoPopups"><span class="badge"></span><span></span></span>
|
||||
<span id="no-large-media" class="hnSwitch fa" data-i18n-tip="popupTipNoLargeMedia"><span class="badge"></span><span></span></span>
|
||||
<span id="no-cosmetic-filtering" class="hnSwitch fa" data-i18n-tip="popupTipNoCosmeticFiltering"><span class="badge"></span><span></span></span>
|
||||
<span id="no-remote-fonts" class="hnSwitch fa" data-i18n-tip="popupTipNoRemoteFonts"><span class="badge"></span><span></span></span>
|
||||
<span id="no-popups" class="hnSwitch fa" data-i18n-tip="popupTipNoPopups"><span class="badge"></span><span><svg viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span></span>
|
||||
<span id="no-large-media" class="hnSwitch fa" data-i18n-tip="popupTipNoLargeMedia"><span class="badge"></span><span><svg viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span></span>
|
||||
<span id="no-cosmetic-filtering" class="hnSwitch fa" data-i18n-tip="popupTipNoCosmeticFiltering"><span class="badge"></span><span><svg viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span></span>
|
||||
<span id="no-remote-fonts" class="hnSwitch fa" data-i18n-tip="popupTipNoRemoteFonts"><span class="badge"></span><span><svg viewBox="0 0 20 20"><path d="M1,1 19,19M1,19 19,1" /></svg></span></span>
|
||||
</div>
|
||||
</div><!-- DO NOT REMOVE --><div class="tooltipContainer">
|
||||
<div id="firewallContainer" class="minimized">
|
||||
|
|
|
|||
83
tools/make-webext-hybrid-meta.py
Normal file
83
tools/make-webext-hybrid-meta.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from io import open as uopen
|
||||
from collections import OrderedDict
|
||||
|
||||
if len(sys.argv) == 1 or not sys.argv[1]:
|
||||
raise SystemExit('Build dir missing.')
|
||||
|
||||
proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..')
|
||||
build_dir = os.path.abspath(sys.argv[1])
|
||||
|
||||
# Import data from chromium platform
|
||||
chromium_manifest = {}
|
||||
webext_manifest = {}
|
||||
|
||||
chromium_manifest_file = os.path.join(proj_dir, 'platform', 'chromium', 'manifest.json')
|
||||
with open(chromium_manifest_file) as f1:
|
||||
chromium_manifest = json.load(f1)
|
||||
|
||||
# WebExtension part
|
||||
webext_manifest_file = os.path.join(build_dir, 'webextension', 'manifest.json')
|
||||
with open(webext_manifest_file) as f2:
|
||||
webext_manifest = json.load(f2)
|
||||
|
||||
webext_manifest['version'] = chromium_manifest['version']
|
||||
|
||||
with open(webext_manifest_file, 'w') as f2:
|
||||
json.dump(webext_manifest, f2, indent=2, separators=(',', ': '), sort_keys=True)
|
||||
f2.write('\n')
|
||||
|
||||
# Legacy part
|
||||
descriptions = OrderedDict({})
|
||||
source_locale_dir = os.path.join(build_dir, 'webextension', '_locales')
|
||||
for alpha2 in sorted(os.listdir(source_locale_dir)):
|
||||
locale_path = os.path.join(source_locale_dir, alpha2, 'messages.json')
|
||||
with uopen(locale_path, encoding='utf-8') as f:
|
||||
strings = json.load(f, object_pairs_hook=OrderedDict)
|
||||
alpha2 = alpha2.replace('_', '-')
|
||||
descriptions[alpha2] = strings['extShortDesc']['message']
|
||||
|
||||
webext_manifest['author'] = chromium_manifest['author'];
|
||||
webext_manifest['name'] = chromium_manifest['name'] + '/webext-hybrid'
|
||||
webext_manifest['homepage'] = 'https://github.com/gorhill/uBlock'
|
||||
webext_manifest['description'] = descriptions['en']
|
||||
del descriptions['en']
|
||||
|
||||
match = re.search('^(\d+\.\d+\.\d+)(\.\d+)$', chromium_manifest['version'])
|
||||
if match:
|
||||
buildtype = int(match.group(2)[1:])
|
||||
if buildtype < 100:
|
||||
builttype = 'b' + str(buildtype)
|
||||
else:
|
||||
builttype = 'rc' + str(buildtype - 100)
|
||||
webext_manifest['version'] = match.group(1) + builttype
|
||||
|
||||
webext_manifest['localized'] = []
|
||||
t = ' '
|
||||
t3 = 3 * t
|
||||
for alpha2 in descriptions:
|
||||
if alpha2 == 'en':
|
||||
continue
|
||||
webext_manifest['localized'].append(
|
||||
'\n' + t*2 + '<em:localized><Description>\n' +
|
||||
t3 + '<em:locale>' + alpha2 + '</em:locale>\n' +
|
||||
t3 + '<em:name>' + webext_manifest['name'] + '</em:name>\n' +
|
||||
t3 + '<em:description>' + descriptions[alpha2] + '</em:description>\n' +
|
||||
t3 + '<em:creator>' + webext_manifest['author'] + '</em:creator>\n' +
|
||||
# t3 + '<translator>' + ??? + '</translator>\n' +
|
||||
t3 + '<em:homepageURL>' + webext_manifest['homepage'] + '</em:homepageURL>\n' +
|
||||
t*2 + '</Description></em:localized>'
|
||||
)
|
||||
webext_manifest['localized'] = '\n'.join(webext_manifest['localized'])
|
||||
|
||||
install_rdf = os.path.join(build_dir, 'install.rdf')
|
||||
with uopen(install_rdf, 'r+t', encoding='utf-8', newline='\n') as f:
|
||||
install_rdf = f.read()
|
||||
f.seek(0)
|
||||
f.write(install_rdf.format(**webext_manifest))
|
||||
f.truncate()
|
||||
51
tools/make-webext-hybrid.sh
Executable file
51
tools/make-webext-hybrid.sh
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This script assumes a linux environment
|
||||
|
||||
echo "*** uBlock0.webext-hybrid: Creating web store package"
|
||||
echo "*** uBlock0.webext-hybrid: Copying files"
|
||||
|
||||
DES=dist/build/uBlock0.webext-hybrid
|
||||
rm -rf $DES
|
||||
mkdir -p $DES/webextension
|
||||
|
||||
bash ./tools/make-assets.sh $DES/webextension
|
||||
|
||||
cp -R src/css $DES/webextension/
|
||||
cp -R src/img $DES/webextension/
|
||||
cp -R src/js $DES/webextension/
|
||||
cp -R src/lib $DES/webextension/
|
||||
cp -R src/_locales $DES/webextension/
|
||||
cp -R $DES/webextension/_locales/nb $DES/webextension/_locales/no
|
||||
cp src/*.html $DES/webextension/
|
||||
cp platform/chromium/*.js $DES/webextension/js/
|
||||
cp -R platform/chromium/img $DES/webextension/
|
||||
cp platform/chromium/*.html $DES/webextension/
|
||||
cp platform/chromium/*.json $DES/webextension/
|
||||
cp LICENSE.txt $DES/webextension/
|
||||
|
||||
cp platform/webext/manifest.json $DES/webextension/
|
||||
cp platform/webext/background.html $DES/webextension/
|
||||
cp platform/webext/options_ui.html $DES/webextension/
|
||||
cp platform/webext/polyfill.js $DES/webextension/js/
|
||||
cp platform/webext/vapi-usercss.js $DES/webextension/js/
|
||||
cp platform/webext/vapi-cachestorage.js $DES/webextension/js/
|
||||
cp platform/webext/from-legacy.js $DES/webextension/js/
|
||||
rm $DES/webextension/js/options_ui.js
|
||||
|
||||
cp platform/webext/bootstrap.js $DES/
|
||||
cp platform/webext/chrome.manifest $DES/
|
||||
cp platform/webext/install.rdf $DES/
|
||||
mv $DES/webextension/img/icon_128.png $DES/icon.png
|
||||
|
||||
echo "*** uBlock0.webext-hybrid: Generating meta..."
|
||||
python tools/make-webext-hybrid-meta.py $DES/
|
||||
|
||||
if [ "$1" = all ]; then
|
||||
echo "*** uBlock0.webext-hybrid: Creating package..."
|
||||
pushd $DES > /dev/null
|
||||
zip ../$(basename $DES).xpi -qr *
|
||||
popd > /dev/null
|
||||
fi
|
||||
|
||||
echo "*** uBlock0.webext-hybrid: Package done."
|
||||
|
|
@ -4,8 +4,6 @@ import os
|
|||
import json
|
||||
import re
|
||||
import sys
|
||||
from io import open as uopen
|
||||
from collections import OrderedDict
|
||||
|
||||
if len(sys.argv) == 1 or not sys.argv[1]:
|
||||
raise SystemExit('Build dir missing.')
|
||||
|
|
@ -13,7 +11,7 @@ if len(sys.argv) == 1 or not sys.argv[1]:
|
|||
proj_dir = os.path.join(os.path.split(os.path.abspath(__file__))[0], '..')
|
||||
build_dir = os.path.abspath(sys.argv[1])
|
||||
|
||||
# Import data from chromium platform
|
||||
# Import version number from chromium platform
|
||||
chromium_manifest = {}
|
||||
webext_manifest = {}
|
||||
|
||||
|
|
@ -21,33 +19,10 @@ chromium_manifest_file = os.path.join(proj_dir, 'platform', 'chromium', 'manifes
|
|||
with open(chromium_manifest_file) as f1:
|
||||
chromium_manifest = json.load(f1)
|
||||
|
||||
# WebExtension part
|
||||
webext_manifest_file = os.path.join(build_dir, 'webextension', 'manifest.json')
|
||||
webext_manifest_file = os.path.join(build_dir, 'manifest.json')
|
||||
with open(webext_manifest_file) as f2:
|
||||
webext_manifest = json.load(f2)
|
||||
|
||||
webext_manifest['version'] = chromium_manifest['version']
|
||||
|
||||
with open(webext_manifest_file, 'w') as f2:
|
||||
json.dump(webext_manifest, f2, indent=2, separators=(',', ': '), sort_keys=True)
|
||||
f2.write('\n')
|
||||
|
||||
# Legacy part
|
||||
descriptions = OrderedDict({})
|
||||
source_locale_dir = os.path.join(build_dir, 'webextension', '_locales')
|
||||
for alpha2 in sorted(os.listdir(source_locale_dir)):
|
||||
locale_path = os.path.join(source_locale_dir, alpha2, 'messages.json')
|
||||
with uopen(locale_path, encoding='utf-8') as f:
|
||||
strings = json.load(f, object_pairs_hook=OrderedDict)
|
||||
alpha2 = alpha2.replace('_', '-')
|
||||
descriptions[alpha2] = strings['extShortDesc']['message']
|
||||
|
||||
webext_manifest['author'] = chromium_manifest['author'];
|
||||
webext_manifest['name'] = chromium_manifest['name'] + '/webext';
|
||||
webext_manifest['homepage'] = 'https://github.com/gorhill/uBlock'
|
||||
webext_manifest['description'] = descriptions['en']
|
||||
del descriptions['en']
|
||||
|
||||
match = re.search('^(\d+\.\d+\.\d+)(\.\d+)$', chromium_manifest['version'])
|
||||
if match:
|
||||
buildtype = int(match.group(2)[1:])
|
||||
|
|
@ -56,28 +31,9 @@ if match:
|
|||
else:
|
||||
builttype = 'rc' + str(buildtype - 100)
|
||||
webext_manifest['version'] = match.group(1) + builttype
|
||||
else:
|
||||
webext_manifest['version'] = chromium_manifest['version']
|
||||
|
||||
webext_manifest['localized'] = []
|
||||
t = ' '
|
||||
t3 = 3 * t
|
||||
for alpha2 in descriptions:
|
||||
if alpha2 == 'en':
|
||||
continue
|
||||
webext_manifest['localized'].append(
|
||||
'\n' + t*2 + '<em:localized><Description>\n' +
|
||||
t3 + '<em:locale>' + alpha2 + '</em:locale>\n' +
|
||||
t3 + '<em:name>' + webext_manifest['name'] + '</em:name>\n' +
|
||||
t3 + '<em:description>' + descriptions[alpha2] + '</em:description>\n' +
|
||||
t3 + '<em:creator>' + webext_manifest['author'] + '</em:creator>\n' +
|
||||
# t3 + '<translator>' + ??? + '</translator>\n' +
|
||||
t3 + '<em:homepageURL>' + webext_manifest['homepage'] + '</em:homepageURL>\n' +
|
||||
t*2 + '</Description></em:localized>'
|
||||
)
|
||||
webext_manifest['localized'] = '\n'.join(webext_manifest['localized'])
|
||||
|
||||
install_rdf = os.path.join(build_dir, 'install.rdf')
|
||||
with uopen(install_rdf, 'r+t', encoding='utf-8', newline='\n') as f:
|
||||
install_rdf = f.read()
|
||||
f.seek(0)
|
||||
f.write(install_rdf.format(**webext_manifest))
|
||||
f.truncate()
|
||||
with open(webext_manifest_file, 'w') as f2:
|
||||
json.dump(webext_manifest, f2, indent=2, separators=(',', ': '), sort_keys=True)
|
||||
f2.write('\n')
|
||||
|
|
|
|||
|
|
@ -7,31 +7,30 @@ echo "*** uBlock0.webext: Copying files"
|
|||
|
||||
DES=dist/build/uBlock0.webext
|
||||
rm -rf $DES
|
||||
mkdir -p $DES/webextension
|
||||
mkdir -p $DES
|
||||
|
||||
bash ./tools/make-assets.sh $DES/webextension
|
||||
bash ./tools/make-assets.sh $DES
|
||||
|
||||
cp -R src/css $DES/webextension/
|
||||
cp -R src/img $DES/webextension/
|
||||
cp -R src/js $DES/webextension/
|
||||
cp -R src/lib $DES/webextension/
|
||||
cp -R src/_locales $DES/webextension/
|
||||
cp -R $DES/webextension/_locales/nb $DES/webextension/_locales/no
|
||||
cp src/*.html $DES/webextension/
|
||||
cp platform/chromium/*.js $DES/webextension/js/
|
||||
cp -R platform/chromium/img $DES/webextension/
|
||||
cp platform/chromium/*.html $DES/webextension/
|
||||
cp platform/chromium/*.json $DES/webextension/
|
||||
cp platform/webext/polyfill.js $DES/webextension/js/
|
||||
cp LICENSE.txt $DES/webextension/
|
||||
|
||||
cp platform/webext/background.html $DES/webextension/
|
||||
cp platform/webext/from-legacy.js $DES/webextension/js/
|
||||
cp platform/webext/manifest.json $DES/webextension/
|
||||
cp platform/webext/bootstrap.js $DES/
|
||||
cp platform/webext/chrome.manifest $DES/
|
||||
cp platform/webext/install.rdf $DES/
|
||||
mv $DES/webextension/img/icon_128.png $DES/icon.png
|
||||
cp -R src/css $DES/
|
||||
cp -R src/img $DES/
|
||||
cp -R src/js $DES/
|
||||
cp -R src/lib $DES/
|
||||
cp -R src/_locales $DES/
|
||||
cp -R $DES/_locales/nb $DES/_locales/no
|
||||
cp src/*.html $DES/
|
||||
cp platform/chromium/*.js $DES/js/
|
||||
cp -R platform/chromium/img $DES/
|
||||
cp platform/chromium/*.html $DES/
|
||||
cp platform/chromium/*.json $DES/
|
||||
cp LICENSE.txt $DES/
|
||||
|
||||
cp platform/webext/manifest.json $DES/
|
||||
cp platform/webext/options_ui.html $DES/
|
||||
cp platform/webext/polyfill.js $DES/js/
|
||||
cp platform/webext/vapi-webrequest.js $DES/js/
|
||||
cp platform/webext/vapi-cachestorage.js $DES/js/
|
||||
cp platform/webext/vapi-usercss.js $DES/js/
|
||||
rm $DES/js/options_ui.js
|
||||
|
||||
echo "*** uBlock0.webext: Generating meta..."
|
||||
python tools/make-webext-meta.py $DES/
|
||||
|
|
|
|||
Loading…
Reference in a new issue