├── .github
├── ISSUE_TEMPLATE.TXT
├── PULL_REQUEST_TEMPLATE.TXT
└── workflows
│ └── lock.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.MD
├── docs
├── index.css
└── index.html
├── list
├── 1-header.txt
├── 2-integration.txt
├── 3-rules.txt
├── 4-generichide.txt
├── 5-whitelist.txt
└── 6-other.txt
├── notes
├── extension-development.md
└── issue-reporter.md
├── src
├── background
│ ├── core.js
│ ├── debug.js
│ └── rules.js
├── common.js
├── content
│ ├── core.js
│ ├── debug.js
│ ├── rules-common.js
│ ├── rules-specific.js
│ ├── rules-sticky.js
│ └── ubo-extra.js
├── icon128.png
├── libdom.js
├── manifest.json
├── platform
│ ├── chromium-vars.js
│ ├── edge-content.js
│ ├── edge-vars.js
│ ├── firefox-background.js
│ ├── firefox-content.js
│ └── firefox-vars.js
├── popup
│ ├── index.css
│ ├── index.html
│ └── index.js
├── reporter
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── paper.js
└── resources
│ ├── blank.mp4
│ ├── fw.js
│ ├── ima3.js
│ └── jquery.js
├── tests
├── check-syntax.js
├── promise-fs.js
└── tests-main.js
└── uBlockProtectorList.txt
/.github/ISSUE_TEMPLATE.TXT:
--------------------------------------------------------------------------------
1 |
5 | ### Test link (required):
6 |
9 |
10 |
11 | ### Screenshot of the web page (including address bar and extension icons) (required):
12 |
16 |
17 |
18 | ### Screenshot of the console (press `F12` to bring up the console) (required):
19 |
22 |
23 |
24 | ### Explain what was not right (optional if obvious):
25 |
26 |
27 | ### Reproduction steps (optional if trivial):
28 |
29 |
30 | ### Environment (Required):
31 |
32 | - Operating System and Version:
33 | - Browser and Version:
34 | - Adblocker and Version:
35 | - Nano Defender Version:
36 |
37 |
38 | #### Your filter lists (Required):
39 |
42 |
43 |
44 | #### Your custom filters (Required if you have any):
45 |
46 |
47 | #### Your other extensions (Required if you have any):
48 |
49 |
50 | ### Add everything else that you believe to be useful below (optional):
51 |
52 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.TXT:
--------------------------------------------------------------------------------
1 | ### Explain why is this change needed (required):
2 |
3 |
4 | ### Test link (if applicable):
5 |
6 |
7 | ### Screenshots and reproduction steps (if applicable):
8 |
9 |
10 | ### Issues that are related (if applicable):
11 |
12 |
13 | ### Add everything else that you believe to be useful below (optional):
14 |
15 |
--------------------------------------------------------------------------------
/.github/workflows/lock.yml:
--------------------------------------------------------------------------------
1 | name: 'Lock Old Threads'
2 |
3 | on:
4 | schedule:
5 | - cron: '0 */6 * * *'
6 |
7 | jobs:
8 | lock:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 120
11 | steps:
12 | - uses: dessant/lock-threads@v2
13 | with:
14 | github-token: ${{ github.token }}
15 | issue-lock-inactive-days: '14'
16 | issue-lock-labels: 'Archived'
17 | issue-lock-reason: ''
18 | pr-lock-inactive-days: '28'
19 | pr-lock-labels: 'Archived'
20 | pr-lock-reason: ''
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | git:
2 | depth: 1
3 | language: node_js
4 | node_js: node
5 | cache:
6 | directories:
7 | - node_modules
8 | before_script:
9 | - npm install esprima
10 | script:
11 | - npm ls
12 | - node ./tests/tests-main.js
13 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # Important Announcements Regarding Recent Changes
2 |
3 | Please read important announcements here: https://github.com/NanoAdblocker/NanoCore/issues/362
4 |
5 | # Nano Defender [](https://travis-ci.org/jspenguin2017/uBlockProtector)
6 |
7 | An anti-adblock defuser for Nano Adblocker and uBlock Origin
8 |
9 | 
10 |
11 | ### [Get it Now](http://jspenguin2017.github.io/uBlockProtector/)
12 |
13 | *Formerly uBlock Protector. Repository name will not be updated as it would
14 | break too many links.*
15 |
16 | ## Building
17 |
18 | Nano Defender is built using
19 | [Nano Build](https://github.com/NanoAdblocker/NanoBuild).
20 |
21 | ## Credits
22 |
23 | Nano Defender uses open source code from the following projects (alphabetical):
24 |
25 | [reek/anti-adblock-killer](https://github.com/reek/anti-adblock-killer)
26 |
27 | [primer/octicons](https://github.com/primer/octicons/)
28 |
29 | [uBlockOrigin/uAssets](https://github.com/uBlockOrigin/uAssets)
30 |
31 | [gorhill/uBlock](https://github.com/gorhill/uBlock)
32 |
33 | [gorhill/uBO-Extra](https://github.com/gorhill/uBO-Extra)
34 |
35 | ## Special Thanks
36 |
37 | Nano Defender is developed by **@jspenguin2017** with the help of the following
38 | individuals (alphabetical):
39 |
40 | **@lain566**
41 |
--------------------------------------------------------------------------------
/docs/index.css:
--------------------------------------------------------------------------------
1 | code {
2 | background-color: rgba(255, 255, 255, 0.8);
3 | border-radius: 20px;
4 | font-family: Consolas, monospace;
5 | padding: 0px 8px 0px 8px;
6 | }
7 |
8 | p {
9 | line-height: 1.3em;
10 | }
11 |
12 | p.red {
13 | padding: 5px;
14 | }
15 |
16 | div.scroll {
17 | max-width: 100%;
18 | overflow-x: auto;
19 | }
20 |
21 | p.no-bot {
22 | margin-bottom: 0px;
23 | }
24 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /;
93 | const adsTimerDefinition = "00:00:05 ";
94 |
95 | let adsTimerPrompt;
96 | let adsSkipPrompt;
97 | if (beta) {
98 | adsTimerPrompt = /\w\.innerHTML=''\+window\._molSettings\.skipText.*?"<\/p>"/g;
99 | adsSkipPrompt = /\w\.innerHTML=window\._molSettings\.skipButtonText/g;
100 | } else {
101 | adsTimerPrompt = /\w\.innerHTML="\u5ee3\u544a.*?\u6d88\u9664\u5ee3\u544a.*?\uff1f"/;
102 | adsSkipPrompt = /\w\.innerHTML="\u9ede\u6b64\u8df3\u904e\u5ee3\u544a"/;
103 | }
104 |
105 | const req = new _XMLHttpRequest();
106 | req.onreadystatechange = () => {
107 | if (req.readyState === 4) {
108 | let payload = req.responseText;
109 | try {
110 | payload = payload.replace(adsTimerOffset, '');
111 | payload = payload.replace(adsTimerDefinition, "00:00:00 ");
112 | payload = payload.replace(adsSkipPrompt, [
113 | "$('.vast-skip-button')[0].click()",
114 | "$('#ani_video_html5_api').show()",
115 | "$('#ani_video_html5_api').prop('muted', false)",
116 | ].join(","));
117 | payload = payload.replace(adsTimerPrompt, (match) => {
118 | return "(" + [
119 | match,
120 | "$('#ani_video_html5_api').hide()",
121 | "$('#ani_video_html5_api').prop('muted', true)",
122 | ].join(",") + ")";
123 | });
124 | } catch (err) { }
125 | const script = window.document.createElement("script");
126 | script.textContent = payload;
127 | window.document.body.append(script);
128 | }
129 | };
130 | req.open("GET", src);
131 | req.send();
132 | };
133 |
134 | const _appendChild = window.Element.prototype.appendChild;
135 | window.Element.prototype.appendChild = function (elem) {
136 | if (
137 | elem.tagName === "SCRIPT" &&
138 | elem.src &&
139 | elem.src.startsWith("https://i2.bahamut.com.tw/build/js/animeplayer")
140 | ) {
141 | return void patchPlayer(elem.src, elem.src.includes("beta"));
142 | }
143 | return _appendChild.apply(this, arguments);
144 | };
145 | });
146 | }
147 |
148 | // ------------------------------------------------------------------------------------------------------------- //
149 |
150 | }
151 |
152 | // ----------------------------------------------------------------------------------------------------------------- //
153 |
154 | //@pragma-end-if
155 |
156 | // ----------------------------------------------------------------------------------------------------------------- //
157 |
--------------------------------------------------------------------------------
/src/content/rules-common.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Handle whitelist and initialize generic content solutions. Then apply common content rules
22 | //
23 | // Solutions from Anti-Adblock Killer (by Reek) are modified to fit the content core library
24 | //
25 | // Anti-Adblock Killer Repository (contains original source code and license):
26 | // https://github.com/reek/anti-adblock-killer
27 |
28 | // ----------------------------------------------------------------------------------------------------------------- //
29 |
30 | "use strict";
31 |
32 | // ----------------------------------------------------------------------------------------------------------------- //
33 |
34 | {
35 |
36 | // ------------------------------------------------------------------------------------------------------------- //
37 |
38 | a.init();
39 |
40 | // ------------------------------------------------------------------------------------------------------------- //
41 |
42 | const domCmpWhitelist = [
43 |
44 | // --------------------------------------------------------------------------------------------------------- //
45 |
46 | // Local network
47 | "127.0.0.1",
48 | "local",
49 |
50 | // Reserved TLDs
51 | "example",
52 | "invalid",
53 | "localhost",
54 | "test",
55 |
56 | // --------------------------------------------------------------------------------------------------------- //
57 |
58 | // Baidu
59 | "baidu.com",
60 |
61 | // Google
62 | "google.it.ao",
63 | "google.ne.jp",
64 | "google.off.ai",
65 |
66 | // PayPal
67 | "paypal.com",
68 | "paypal.me",
69 |
70 | // Twitch
71 | "twitch.tv",
72 |
73 | // Wikipedia
74 | "wikipedia.org",
75 |
76 | // YouTube
77 | "youtu.be",
78 | "youtube.com",
79 |
80 | // --------------------------------------------------------------------------------------------------------- //
81 |
82 | // Advanced tools (for performance)
83 | "lab.wolframcloud.com",
84 |
85 | // Image hosts (for performance)
86 | "flickr.com",
87 | "imgbox.com",
88 | "imgur.com",
89 |
90 | // JavaScript playgrounds (for performance)
91 | "ask.com",
92 | "codepen.io",
93 | "jsbin.com",
94 | "jsfiddle.net",
95 | "plnkr.co",
96 | "preloaders.net",
97 | "stackoverflow.com",
98 | "w3schools.com",
99 |
100 | // Media sites (for performance)
101 | "calm.com",
102 | "vimeo.com",
103 | "xemvtv.net",
104 | "yandex.ru",
105 |
106 | // Social networks (for performance)
107 | "bufferapp.com",
108 | "chatango.com",
109 | "facebook.com",
110 | "instagram.com",
111 | "linkedin.com",
112 | "messenger.com",
113 | "pinterest.com",
114 | "reddit.com",
115 | "twitter.com",
116 |
117 | // --------------------------------------------------------------------------------------------------------- //
118 |
119 | // Custom FuckAdBlock
120 | "atresplayer.com",
121 | "aviationweek.com",
122 | "futbin.com",
123 | "juprimaulana.com",
124 | "paraedu.id",
125 | "rmcmv.us",
126 | "yuukithemes.com",
127 |
128 | // False positives from Adfly skipper
129 | "programme-tv.net",
130 |
131 | // False positives from legacy BlockAdBlock defuser
132 | "alternativeto.net",
133 |
134 | // Other false positives
135 | "anandabazar.com",
136 | "animesync.tv",
137 | "aternos.org",
138 | "automobile-propre.com",
139 | "avgle.com",
140 | "babbel.com",
141 | "bild.de",
142 | "browserleaks.com",
143 | "bungie.net",
144 | "buxfer.com",
145 | "ccbluex.net",
146 | "cfnc.org",
147 | "dallasnews.com",
148 | "derstandard.at",
149 | "di.fm",
150 | "download.ipeenk.com",
151 | "duellinksmeta.com",
152 | "egy.best",
153 | "filmweb.pl",
154 | "finobe.com",
155 | "gamersclub.com.br",
156 | "gaobook.review",
157 | "hackintosh.computer",
158 | "imdb.com",
159 | "infostrow.pl",
160 | "jazzradio.com",
161 | "lcpdfr.com",
162 | "lemonde.fr",
163 | "linetv.tw",
164 | "lolalytics.com",
165 | "myworkday.com",
166 | "o2.pl",
167 | "ostrzeszowinfo.pl",
168 | "pasty.link",
169 | "pokyun.tv",
170 | "pornhub.com",
171 | "privacy-port.de",
172 | "reevown.com",
173 | "shinden.pl",
174 | "socketloop.com",
175 | "sport-tv-guide.live",
176 | "store.playstation.com",
177 | "strefadb.pl",
178 | "techradar.com",
179 | "tv3sport.dk",
180 | "tvserial.it",
181 | "viasatsport.se",
182 | "viasport.fi",
183 | "viasport.no",
184 | "vod.pl",
185 | "wilmaa.com",
186 | "workday.com",
187 | "wp.pl",
188 | "wstream.video",
189 |
190 | // Handled by a special private extension
191 | "boost.ink",
192 |
193 | // --------------------------------------------------------------------------------------------------------- //
194 |
195 | ];
196 |
197 | const domIncWhitelist = [
198 |
199 | // --------------------------------------------------------------------------------------------------------- //
200 |
201 | // Local network
202 | "192.168.0",
203 | "192.168.1",
204 |
205 | // --------------------------------------------------------------------------------------------------------- //
206 |
207 | // Google
208 | "google",
209 | "google.co",
210 | "google.com",
211 |
212 | // Yahoo
213 | "yahoo",
214 |
215 | // --------------------------------------------------------------------------------------------------------- //
216 |
217 | // Stores (for performance)
218 | "amazon",
219 | "ebay",
220 |
221 | // --------------------------------------------------------------------------------------------------------- //
222 |
223 | // Other false positives
224 | "9anime",
225 | "egybest",
226 | "italiashare",
227 | "imgdew",
228 | "imgfile",
229 | "imgmaze",
230 | "imgoutlet",
231 | "imgrock",
232 | "imgview",
233 | "kickassanime",
234 | "kiss-anime",
235 | "kissanime",
236 | "kissasian",
237 | "oladblock",
238 | "oload",
239 | "openload",
240 | "viafree",
241 |
242 | // --------------------------------------------------------------------------------------------------------- //
243 |
244 | ];
245 |
246 | // ------------------------------------------------------------------------------------------------------------- //
247 |
248 | if (a.domCmp(domCmpWhitelist, true) || a.domInc(domIncWhitelist, true)) {
249 |
250 | console.log("[Nano] Excluded :: All Generically Applied Solutions");
251 |
252 | } else {
253 |
254 | if (false) {
255 | console.log("[Nano] Excluded :: Common Generic Solutions");
256 | } else {
257 | a.generic();
258 | }
259 |
260 | if (a.domCmp([
261 | // https://github.com/NanoMeow/QuickReports/issues/2641
262 | "topadnetworks.net",
263 | "topshort.net",
264 | // https://github.com/NanoMeow/QuickReports/issues/2950
265 | "freealtsgenerator.es",
266 | "uforum.us",
267 | // https://github.com/NanoMeow/QuickReports/issues/3113
268 | "ctrn.cc",
269 | "cutearn.net",
270 | ], true) || a.domInc([
271 | // https://github.com/uBlockOrigin/uAssets/issues/6553
272 | "cutlinks",
273 | ], true)) {
274 | console.log("[Nano] Excluded :: Adfly Skipper");
275 | } else {
276 | a.generic.Adfly();
277 | }
278 |
279 | if (false) {
280 | console.log("[Nano] Excluded :: Adfly Forced Notification Blocker");
281 | } else {
282 | a.generic.AdflyForcedNotification();
283 | }
284 |
285 | if (false) {
286 | console.log("[Nano] Excluded :: app_vars Defuser");
287 | } else {
288 | a.generic.app_vars();
289 | }
290 |
291 | if (false) {
292 | console.log("[Nano] Excluded :: Cloudflare Apps Defuser");
293 | } else {
294 | a.generic.CloudflareApps();
295 | }
296 |
297 | }
298 |
299 | // ------------------------------------------------------------------------------------------------------------- //
300 |
301 | // Deprecated
302 | if (a.domCmp([
303 | "acquavivalive.it",
304 | "beinsports.com",
305 | "listamais.com.br",
306 | "lolskinlistgenerator.com",
307 | "m.delfi.ee",
308 | "memurlar.net",
309 | "molfettalive.it",
310 | "palemoon.org",
311 | "palolive.it",
312 | "passionea300allora.it",
313 | "sledujserialy.sk",
314 | "stocks.cafe",
315 | "uploadboy.com",
316 | "videohelp.com",
317 | "vidoza.net",
318 | "warforum.cz",
319 | "zeiz.me",
320 | ])) {
321 | a.generic.adsjsV2();
322 | }
323 |
324 | // ------------------------------------------------------------------------------------------------------------- //
325 |
326 | if (false) {
327 | a.uBOExtraExcluded = true;
328 | console.log("[Nano] Excluded :: uBO-Extra");
329 | }
330 |
331 | // ------------------------------------------------------------------------------------------------------------- //
332 |
333 | }
334 |
335 | // ----------------------------------------------------------------------------------------------------------------- //
336 |
337 | // a.filter
338 |
339 | if (a.domCmp([
340 | "darmowe-pornosy.pl",
341 | "exrapidleech.info",
342 | "flashx.to",
343 | "flashx.tv",
344 | "linx.cloud",
345 | "urle.co",
346 | "usapoliticstoday.com",
347 | "vidlox.tv",
348 | ])) {
349 | a.filter("eval");
350 | }
351 |
352 | if (a.domCmp([
353 | "cloudwebcopy.com",
354 | "sc2casts.com",
355 | "webqc.org",
356 | ])) {
357 | a.filter("setTimeout");
358 | }
359 |
360 | if (a.domCmp([
361 | "1movies.tv",
362 | "adshort.co",
363 | "adshort.im",
364 | "adshorte.com",
365 | "arenavision.in",
366 | "atdhe.al",
367 | "atdhe.bz",
368 | "atdhe.li",
369 | "atdhe.me",
370 | "atdhe.mx",
371 | "atdhe.ru",
372 | "atdhe.se",
373 | "atdhe.to",
374 | "atdhe.top",
375 | "backin.net",
376 | "coinb.ink",
377 | "ddlfr.pw",
378 | "doramasflv.net",
379 | "firstrow.co",
380 | "firstrow1us.eu",
381 | "firstrows.biz",
382 | "firstrows.co",
383 | "firstrows.org",
384 | "firstrows.ru",
385 | "firstrows.tv",
386 | "firstrowsportes.com",
387 | "firstrowsportes.tv",
388 | "firstrowus.eu",
389 | "firstsrowsports.eu",
390 | "hahasport.me",
391 | "iiv.pl",
392 | "justfirstrowsports.com",
393 | "katfile.com",
394 | "l2s.io",
395 | "linclik.com",
396 | "linkkawy.com",
397 | "linksh.top",
398 | "myp2p.biz",
399 | "myp2p.com",
400 | "myp2p.ec",
401 | "myp2p.eu",
402 | "myp2p.la",
403 | "myp2p.sx",
404 | "myp2p.tv",
405 | "myp2p.ws",
406 | "sawlive.tv",
407 | "shink.me",
408 | "u2s.io",
409 | "ur.ly",
410 | "urle.co",
411 | "videowood.tv",
412 | "vidoza.net",
413 | "wiziwig.ru",
414 | "wiziwig.sx",
415 | "wiziwig.to",
416 | "wiziwig.tv",
417 | "zlshorte.net",
418 | ])) {
419 | a.filter("open");
420 | }
421 |
422 | if (a.domCmp([
423 | "businesstoday.in",
424 | "dl-protect.com",
425 | "doatoolsita.altervista.org",
426 | "drivearabia.com",
427 | "filecom.net",
428 | "free-movie-home.com",
429 | "generatupremium.biz",
430 | "kooora.com",
431 | "mega-debrid.eu",
432 | "newsinlevels.com",
433 | "pc.online143.com",
434 | "pipocas.tv",
435 | "premiumst0re.blogspot.com",
436 | "putlocker.com",
437 | "sockshare.com",
438 | "str3am.altervista.org",
439 | "str3amtv.altervista.org",
440 | "str3amtv.co.nr",
441 | "str3amtv.co.nr",
442 | "vipracing.biz",
443 | ])) {
444 | a.filter("alert");
445 | }
446 |
447 | // ----------------------------------------------------------------------------------------------------------------- //
448 |
449 | // a.readOnly
450 |
451 | if (a.domCmp([
452 | "financialexpress.com",
453 | "indianexpress.com",
454 | "jansatta.com",
455 | "srt.am",
456 | "uskip.me",
457 | ])) {
458 | a.readOnly("RunAds", true);
459 | }
460 |
461 | if (a.domCmp([
462 | "catcatyfaucet.xyz",
463 | "jagranjunction.com",
464 | "nekopoi.bid",
465 | ])) {
466 | a.readOnly("isAdsDisplayed", true);
467 | }
468 |
469 | if (a.domCmp([
470 | "stream.nbcsports.com",
471 | "swissadspaysethfaucet.com",
472 | "swissadspaysfaucet.com",
473 | ])) {
474 | a.readOnly("adBlockEnabled", false);
475 | }
476 |
477 | if (a.domCmp([
478 | "link.tl",
479 | ])) {
480 | a.readOnly("adblocker", false);
481 | }
482 |
483 | if (a.domCmp([
484 | "megogo.net",
485 | ])) {
486 | a.readOnly("adBlock", false);
487 | }
488 |
489 | if (a.domCmp([
490 | "4tests.com",
491 | "8bbit.com",
492 | "alcodistillers.ru",
493 | "angrybirdsnest.com",
494 | "freizeitpartnerweb.de",
495 | "nekopoi.bid",
496 | "outdoorpartner.net",
497 | "translatica.pl",
498 | "urlaubspartner.net",
499 | ])) {
500 | a.readOnly("adblock", false);
501 | }
502 |
503 | if (a.domCmp([
504 | "code.ptcong.com",
505 | "hanime.tv",
506 | "mega-estrenos.com",
507 | "mexashare.com",
508 | "popunderjs.com",
509 | "shortin.ga",
510 | ])) {
511 | a.readOnly("BetterJsPop", "window.Object.freeze({})");
512 | }
513 |
514 | if (a.domCmp([
515 | "he2eini7ka.com",
516 | "youwatch.to",
517 | ])) {
518 | a.readOnly("jsPopunder", () => { });
519 | }
520 |
521 | if (a.domCmp([
522 | "ahzahg6ohb.com",
523 | "ajihezo.info",
524 | "bojem3a.info",
525 | "chefti.info",
526 | "chouhaa.info",
527 | "exashare.com",
528 | "he2eini7ka.com",
529 | "yahmaib3ai.com",
530 | "youwatch.org",
531 | "youwatch.to",
532 | ])) {
533 | a.readOnly("adsShowPopup1", 1);
534 | }
535 |
536 | if (a.domCmp([
537 | "game-debate.com",
538 | "naruto-mx.net",
539 | "onepiece-mx.net",
540 | "scan-mx.com",
541 | ])) {
542 | a.readOnly("ad_block_test", () => { });
543 | }
544 |
545 | if (a.domCmp([
546 | "freebitcoins.nx.tc",
547 | "getbitcoins.nx.tc",
548 | ])) {
549 | a.readOnly("ad_block_test", () => false);
550 | }
551 |
552 | if (a.domCmp([
553 | "1movies.tv",
554 | "xmovies8.es",
555 | ])) {
556 | a.readOnly("check_adblock", true);
557 | }
558 |
559 | if (a.domCmp([
560 | "fourchette-et-bikini.fr",
561 | "meteocity.com",
562 | ])) {
563 | a.readOnly("adProtect", 1);
564 | }
565 |
566 | if (a.domCmp([
567 | "homerun.re",
568 | "securenetsystems.net",
569 | "strikeout.co",
570 | "strikeout.me",
571 | "vipapp.me",
572 | "vipbox.biz",
573 | "vipbox.co",
574 | "vipbox.eu",
575 | "vipbox.nu",
576 | "vipbox.so",
577 | "vipbox.sx",
578 | "vipbox.tv",
579 | "vipboxsa.co",
580 | "vipboxtv.co",
581 | "vipleague.ch",
582 | "vipleague.co",
583 | "vipleague.is",
584 | "vipleague.me",
585 | "vipleague.mobi",
586 | "vipleague.se",
587 | "vipleague.sx",
588 | "vipleague.tv",
589 | "vipleague.ws",
590 | ])) {
591 | a.readOnly("iExist", true);
592 | }
593 |
594 | // ----------------------------------------------------------------------------------------------------------------- //
595 |
596 | // a.noAccess
597 |
598 | if (a.domCmp([
599 | "adshort.co",
600 | "adshorte.com",
601 | "animeforce.org",
602 | "coinb.ink",
603 | "debridnet.com",
604 | "imgrock.info",
605 | "linksh.top",
606 | "srt.am",
607 | ])) {
608 | a.noAccess("_pop");
609 | }
610 |
611 | if (a.domCmp([
612 | "linx.cloud",
613 | ])) {
614 | a.noAccess("popns");
615 | }
616 |
617 | if (a.domCmp([
618 | "adlinkme.com",
619 | "arenabg.ch",
620 | "jzrputtbut.net",
621 | "maango.info",
622 | "psarips.com",
623 | "solidfiles.com",
624 | "streamcloud.eu",
625 | "torrentfunk.com",
626 | "vidfile.net",
627 | ])) {
628 | a.noAccess("open");
629 | }
630 |
631 | // ----------------------------------------------------------------------------------------------------------------- //
632 |
633 | // a.bait
634 |
635 | if (a.domCmp([
636 | "leveldown.fr",
637 | "primeshare.tv",
638 | ])) {
639 | a.bait("div", "#adblock");
640 | }
641 |
642 | if (a.domCmp([
643 | "720pmkv.com",
644 | "psarips.com",
645 | ])) {
646 | a.bait("div", "#advert");
647 | }
648 |
649 | if (a.domCmp([
650 | "bitcoiner.net",
651 | "d3brid4y0u.info",
652 | "dashcatch.xyz",
653 | "dogecatch.website",
654 | "dramapassion.com",
655 | "easybillets.com",
656 | "fileice.net",
657 | "freeallmusic.info",
658 | "litecoiner.net",
659 | "nosteam.ro",
660 | "online.ua",
661 | "openrunner.com",
662 | "osoarcade.com",
663 | "putlocker.com",
664 | "shortify.pw",
665 | "sockshare.com",
666 | "spox.fr",
667 | "tgo-tv.com",
668 | "tv3.co.nz",
669 | "yooclick.com",
670 | "yovoyages.com",
671 | ])) {
672 | a.bait("div", "#tester");
673 | }
674 |
675 | if (a.domCmp([
676 | "alein.org",
677 | ])) {
678 | a.bait("div", "#tester", true);
679 | }
680 |
681 | if (a.domCmp([
682 | "filecom.net",
683 | "globeslot.com",
684 | "mwfiles.net",
685 | "skippyfile.com",
686 | "up-flow.org",
687 | "upshare.org",
688 | ])) {
689 | a.bait("div", "#add");
690 | }
691 |
692 | if (a.domCmp([
693 | "bluesatoshi.com",
694 | "oneadfaucet.com",
695 | "razercrypt.com",
696 | "satoshiempire.com",
697 | ])) {
698 | a.bait("div", "#test");
699 | }
700 |
701 | if (a.domCmp([
702 | "bitcoinaliens.com",
703 | "door2windows.com",
704 | ])) {
705 | a.bait("ins", ".adsbygoogle");
706 | }
707 |
708 | if (a.domCmp([
709 | "hellsmedia.com",
710 | "leaguesecretary.com",
711 | "teknogods.com",
712 | ])) {
713 | a.bait("div", "#adpbtest");
714 | }
715 |
716 | if (a.domCmp([
717 | "freesportsbet.com",
718 | "sportsplays.com",
719 | ])) {
720 | a.bait("div", "#ad-tester");
721 | }
722 |
723 | if (a.domCmp([
724 | "bitcoiner.net",
725 | "litecoiner.net",
726 | ])) {
727 | a.bait("div", "#ad-top");
728 | }
729 |
730 | // ----------------------------------------------------------------------------------------------------------------- //
731 |
--------------------------------------------------------------------------------
/src/content/rules-sticky.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Content rules for sticky websites.
3 | */
4 | "use strict";
5 |
6 | if (a.domCmp(["debridnet.com"])) {
7 | const re = /\.height\(\)/g;
8 | a.beforeScript((script) => {
9 | if (script.textContent) {
10 | script.textContent = script.textContent.replace(re, " && false && 0");
11 | }
12 | });
13 | a.timewarp("setTimeout", a.matchMethod.RegExp, /^\d+000$/, 0.2);
14 | for (let i = 0; i < 15; i++) {
15 | const s = document.createElement("script");
16 | document.documentElement.append(s);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/content/ubo-extra.js:
--------------------------------------------------------------------------------
1 | (() => {
2 | if (a.uBOExtraExcluded) {
3 | return;
4 | }
5 |
6 |
7 |
8 | /*******************************************************************************
9 |
10 | uBO-Extra - A companion extension to uBlock Origin: to gain ability to
11 | foil early hostile anti-user mechanisms working around
12 | content blockers.
13 | Copyright (C) 2016-2018 Raymond Hill
14 |
15 | This program is free software: you can redistribute it and/or modify
16 | it under the terms of the GNU General Public License as published by
17 | the Free Software Foundation, either version 3 of the License, or
18 | (at your option) any later version.
19 |
20 | This program is distributed in the hope that it will be useful,
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 | GNU General Public License for more details.
24 |
25 | You should have received a copy of the GNU General Public License
26 | along with this program. If not, see {http://www.gnu.org/licenses/}.
27 |
28 | Home: https://github.com/gorhill/uBO-WebSocket
29 | */
30 |
31 | 'use strict';
32 |
33 | /* global HTMLDocument, XMLDocument */
34 |
35 | /*******************************************************************************
36 |
37 | All scriptlets to inject: the scriptlets to inject are to foil or work
38 | around hostile anti-user mechanism used by some web sites.
39 |
40 | **/
41 |
42 | var scriptlets = [],
43 | hostname = window.location.hostname,
44 | contentScriptSecret =
45 | String.fromCharCode(Date.now() % 26 + 97) +
46 | Math.floor(Math.random() * 982451653 + 982451653).toString(36);
47 |
48 | /*******************************************************************************
49 |
50 | Don't run on non-HTML documents.
51 |
52 | **/
53 |
54 | var abort = (function() {
55 | var doc = document;
56 | if ( doc instanceof HTMLDocument === false ) {
57 | if (
58 | doc instanceof XMLDocument === false ||
59 | doc.createElement('div') instanceof HTMLDivElement === false
60 | ) {
61 | return true;
62 | }
63 | }
64 | if ( (doc.contentType || '').lastIndexOf('image/', 0) === 0 ) {
65 | return true;
66 | }
67 | return false;
68 | })();
69 |
70 | /*******************************************************************************
71 |
72 | Fetch hostname from ancestors if none available (we could be executed from
73 | inside an anonymous frame).
74 |
75 | **/
76 |
77 | if ( !abort ) {
78 | if ( hostname === '' ) {
79 | hostname = (function() {
80 | var win = window, hn = '', max = 10;
81 | try {
82 | for (;;) {
83 | hn = win.location.hostname;
84 | if ( hn !== '' ) { return hn; }
85 | if ( win.parent === win ) { break; }
86 | win = win.parent;
87 | if ( !win ) { break; }
88 | if ( (max -= 1) === 0 ) { break; }
89 | }
90 | } catch(ex) {
91 | }
92 | return hn;
93 | })();
94 | }
95 | // Don't inject if document is from local network.
96 | abort = /^192\.168\.\d+\.\d+$/.test(hostname);
97 | }
98 |
99 | /*******************************************************************************
100 |
101 | Instart Logic defuser
102 |
103 | **/
104 |
105 | (function() {
106 | if ( abort ) { return; }
107 |
108 | var scriptlet = function() {
109 | var magic = String.fromCharCode(Date.now() % 26 + 97) +
110 | Math.floor(Math.random() * 982451653 + 982451653).toString(36),
111 | targets = [
112 | 'atob',
113 | 'console.error',
114 | 'INSTART',
115 | 'INSTART_TARGET_NAME',
116 | 'navigator.userAgent',
117 | 'performance',
118 | 'require'
119 | ],
120 | reScriptText = /\b(?:Instart-|I10C|I11C|IXC_|INSTART)/,
121 | reScriptSrc = /\babd.*?\/instart.js|\?i10c\./,
122 | thisScript = document.currentScript;
123 | var validate = function() {
124 | var script = document.currentScript;
125 | if ( script instanceof HTMLScriptElement === false ) { return; }
126 | if ( script === thisScript ) { return; }
127 | if ( script.src === '' ) {
128 | if ( reScriptText.test(script.textContent) ) {
129 | throw new ReferenceError(magic);
130 | }
131 | } else if ( reScriptSrc.test(script.src) ) {
132 | throw new ReferenceError(magic);
133 | }
134 | };
135 | var makeGetterSetter = function(owner, prop) {
136 | var value = owner[prop];
137 | return {
138 | get: function() {
139 | validate();
140 | return value;
141 | },
142 | set: function(a) {
143 | validate();
144 | value = a;
145 | }
146 | };
147 | };
148 | var i = targets.length,
149 | owner, target, chain, prop;
150 | while ( i-- ) {
151 | owner = window;
152 | target = targets[i];
153 | chain = target.split('.');
154 | for (;;) {
155 | prop = chain.shift();
156 | if ( chain.length === 0 ) { break; }
157 | owner = owner[prop];
158 | }
159 | Object.defineProperty(owner, prop, makeGetterSetter(owner, prop));
160 | }
161 | var oe = window.onerror;
162 | window.onerror = function(msg) {
163 | if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) {
164 | return true;
165 | }
166 | if ( oe instanceof Function ) {
167 | return oe.apply(this, arguments);
168 | }
169 | }.bind();
170 | };
171 |
172 | scriptlets.push({
173 | scriptlet: scriptlet,
174 | targets: [
175 | 'afterellen.com',
176 | 'americanphotomag.com',
177 | 'atvrider.com',
178 | 'baggersmag.com',
179 | 'baltimoresun.com',
180 | 'boatingmag.com',
181 | 'boston.com',
182 | 'cafemom.com',
183 | 'calgaryherald.com',
184 | 'calgarysun.com',
185 | 'capitalgazette.com',
186 | 'carrollcountytimes.com',
187 | 'cattime.com',
188 | 'cbssports.com',
189 | 'chicagotribune.com',
190 | 'chowhound.com',
191 | 'chron.com',
192 | 'chroniclelive.co.uk',
193 | 'citypaper.com',
194 | 'comingsoon.net',
195 | 'computershopper.com',
196 | 'courant.com',
197 | 'craveonline.com',
198 | 'cruisingworld.com',
199 | 'csgoutpost.com',
200 | 'ctnow.com',
201 | 'cycleworld.com',
202 | 'dailydot.com',
203 | 'dailypress.com',
204 | 'dayzdb.com',
205 | 'deathandtaxesmag.com',
206 | 'delmartimes.net',
207 | 'destinationweddingmag.com',
208 | 'dirtrider.com',
209 | 'diversitybestpractices.com',
210 | 'dogtime.com',
211 | 'dotaoutpost.com',
212 | 'download.cnet.com',
213 | 'edmontonjournal.com',
214 | 'edmontonsun.com',
215 | 'edmunds.com',
216 | 'emedicinehealth.com',
217 | 'esohead.com',
218 | 'everquest.allakhazam.com',
219 | 'extremetech.com',
220 | 'fieldandstream.com',
221 | 'financialpost.com',
222 | 'floridatravellife.com',
223 | 'flyingmag.com',
224 | 'focus.de',
225 | 'foxsports.com.au',
226 | 'gamepedia.com',
227 | 'gamerevolution.com',
228 | 'gamespot.com',
229 | 'geek.com',
230 | 'goal.com',
231 | 'gofugyourself.com',
232 | 'growthspotter.com',
233 | 'hearthhead.com',
234 | 'hockeysfuture.com',
235 | 'hotbikeweb.com',
236 | 'hoylosangeles.com',
237 | 'ibtimes.com',
238 | 'infinitiev.com',
239 | 'islands.com',
240 | 'lajollalight.com',
241 | 'laptopmag.com',
242 | 'latintimes.com',
243 | 'leaderpost.com',
244 | 'legacy.com',
245 | 'lifewire.com',
246 | 'livescience.com',
247 | 'lolking.net',
248 | 'mcall.com',
249 | 'mamaslatinas.com',
250 | 'marlinmag.com',
251 | 'medicaldaily.com',
252 | 'medicinenet.com',
253 | 'metacritic.com',
254 | 'metrolyrics.com',
255 | 'mmo-champion.com',
256 | 'momtastic.com',
257 | 'montrealgazette.com',
258 | 'motorcyclecruiser.com',
259 | 'motorcyclistonline.com',
260 | 'motortrend.com',
261 | 'msn.com',
262 | 'musicfeeds.com.au',
263 | 'mustangandfords.com',
264 | 'mysanantonio.com',
265 | 'nasdaq.com',
266 | 'nationalpost.com',
267 | 'newsarama.com',
268 | 'newsweek.com',
269 | 'orlandosentinel.com',
270 | 'ottawacitizen.com',
271 | 'ottawasun.com',
272 | 'outdoorlife.com',
273 | 'pcmag.com',
274 | 'playstationlifestyle.net',
275 | 'popphoto.com',
276 | 'popsci.com',
277 | 'ranchosantafereview.com',
278 | 'range365.com',
279 | 'ranker.com',
280 | 'ratemyprofessors.com',
281 | 'realclearpolitics.com',
282 | 'realitytea.com',
283 | 'redeyechicago.com',
284 | 'salon.com',
285 | 'saltwatersportsman.com',
286 | 'sandiegouniontribune.com',
287 | 'saveur.com',
288 | 'scubadiving.com',
289 | 'scubadivingintro.com',
290 | 'seattlepi.com',
291 | 'sfgate.com',
292 | 'sherdog.com',
293 | 'slate.com',
294 | 'slickdeals.net',
295 | 'southflorida.com',
296 | 'space.com',
297 | 'spin.com',
298 | 'sporcle.com',
299 | 'sportdiver.com',
300 | 'sportfishingmag.com',
301 | 'sportingnews.com',
302 | 'sportrider.com',
303 | 'spox.com',
304 | 'stereogum.com',
305 | 'streetchopperweb.com',
306 | 'sun-sentinel.com',
307 | 'superherohype.com',
308 | 'superstreetbike.com',
309 | 'tenplay.com.au',
310 | 'tf2outpost.com',
311 | 'thebalance.com',
312 | 'thefashionspot.com',
313 | 'theprovince.com',
314 | 'thespruce.com',
315 | 'thestarphoenix.com',
316 | 'thoughtcatalog.com',
317 | 'thoughtco.com',
318 | 'timeanddate.com',
319 | 'timesunion.com',
320 | 'tomsguide.com',
321 | 'tomsguide.fr',
322 | 'tomshardware.co.uk',
323 | 'tomshardware.com',
324 | 'tomshardware.de',
325 | 'tomshardware.fr',
326 | 'torontosun.com',
327 | 'totalbeauty.com',
328 | 'trustedreviews.com',
329 | 'tv.com',
330 | 'tvguide.com',
331 | 'tvtropes.org',
332 | 'twincities.com',
333 | 'utvdriver.com',
334 | 'vancouversun.com',
335 | 'vg.no',
336 | 'vibe.com',
337 | 'wakeboardingmag.com',
338 | 'washingtonpost.com',
339 | 'waterskimag.com',
340 | 'wetteronline.de',
341 | 'wibc.com',
342 | 'wikia.com',
343 | 'windowscentral.com',
344 | 'windsorstar.com',
345 | 'winnipegsun.com',
346 | 'workingmother.com',
347 | 'wowhead.com',
348 | 'wrestlezone.com',
349 | 'xda-developers.com',
350 | 'yachtingmagazine.com',
351 | 'zam.com',
352 | ]
353 | });
354 | })();
355 |
356 | /*******************************************************************************
357 |
358 | Instart Logic buster: v2
359 |
360 | https://github.com/uBlockOrigin/uAssets/issues/227#issuecomment-268409666
361 |
362 | **/
363 |
364 | (function() {
365 | if ( abort ) { return; }
366 |
367 | var scriptlet = function() {
368 | var magic = String.fromCharCode(Date.now() % 26 + 97) +
369 | Math.floor(Math.random() * 982451653 + 982451653).toString(36);
370 | var makeNanovisorProxy = function() {
371 | return new Proxy({}, {
372 | get: function(target, name) {
373 | switch ( name ) {
374 | case 'HtmlStreaming':
375 | return {
376 | InsertTags: function(a, b) {
377 | document.write(b); // jshint ignore:line
378 | },
379 | InterceptNode: function() {
380 | },
381 | PatchBegin: function() {
382 | },
383 | PatchEnd: function() {
384 | },
385 | PatchInit: function() {
386 | },
387 | ReloadWithNoHtmlStreaming: function() {
388 | window.location.reload(true);
389 | },
390 | RemoveTags: function() {
391 | },
392 | UpdateAttributes: function() {
393 | }
394 | };
395 | default:
396 | return target[name];
397 | }
398 | },
399 | set: function(target, name, value) {
400 | switch ( name ) {
401 | case 'CanRun':
402 | target.CanRun = function() {
403 | return false;
404 | };
405 | break;
406 | default:
407 | target[name] = value;
408 | }
409 | }
410 | });
411 | };
412 | var instartInit;
413 | window.I10C = window.I11C = makeNanovisorProxy();
414 | window.INSTART = new Proxy({}, {
415 | get: function(target, name) {
416 | switch ( name ) {
417 | case 'Init':
418 | return function(a) {
419 | if (
420 | a instanceof Object &&
421 | typeof a.nanovisorGlobalNameSpace === 'string' &&
422 | a.nanovisorGlobalNameSpace !== ''
423 | ) {
424 | window[a.nanovisorGlobalNameSpace] = makeNanovisorProxy();
425 | }
426 | a.enableHtmlStreaming = false;
427 | a.enableQSCallDiffComputationConfig = false;
428 | a.enableQuerySelectorMonitoring = false;
429 | a.serveNanovisorSameDomain = false;
430 | a.virtualDomains = 0;
431 | a.virtualizeDomains = [];
432 | instartInit(a);
433 | };
434 | default:
435 | if ( target[name] === undefined ) {
436 | throw new Error(magic);
437 | }
438 | return target[name];
439 | }
440 | },
441 | set: function(target, name, value) {
442 | switch ( name ) {
443 | case 'Init':
444 | instartInit = value;
445 | break;
446 | default:
447 | target[name] = value;
448 | }
449 | }
450 | });
451 | var oe = window.error;
452 | window.onerror = function(msg, src, line, col, error) {
453 | if ( msg.indexOf(magic) !== -1 ) {
454 | return true;
455 | }
456 | if ( oe instanceof Function ) {
457 | return oe(msg, src, line, col, error);
458 | }
459 | }.bind();
460 | };
461 |
462 | scriptlets.push({
463 | scriptlet: scriptlet,
464 | targets: [
465 | 'calgaryherald.com',
466 | 'edmontonjournal.com',
467 | 'financialpost.com',
468 | 'leaderpost.com',
469 | 'montrealgazette.com',
470 | 'nationalpost.com',
471 | 'ottawacitizen.com',
472 | 'theprovince.com',
473 | 'thestarphoenix.com',
474 | 'windsorstar.com',
475 | ]
476 | });
477 | })();
478 |
479 | /*******************************************************************************
480 |
481 | Instart Logic console detection defuser.
482 |
483 | To allow using the dev tools to investigate IL's code:
484 | - Un-comment out the block of code
485 | - Add the site you wish to investigate in the `targets` array.
486 |
487 | **/
488 |
489 |
490 | (function() {
491 | if ( abort ) { return; }
492 |
493 | var scriptlet = function() {
494 | var realConsole = console,
495 | realLog = console.log;
496 | console.log = function () {
497 | for ( var i = 0; i < arguments.length; i++ ) {
498 | if ( arguments[i] instanceof HTMLElement ) { return; }
499 | }
500 | return realLog.apply(realConsole, arguments);
501 | }.bind(console);
502 | Object.defineProperty(console.log, 'name', { value: 'log' });
503 | };
504 |
505 | scriptlets.push({
506 | scriptlet: scriptlet,
507 | targets: [
508 | 'laptopmag.com'
509 | ]
510 | });
511 | })();
512 |
513 | /*******************************************************************************
514 |
515 | Upmanager
516 |
517 | https://github.com/uBlockOrigin/uAssets/issues/251#issuecomment-276257642
518 |
519 | **/
520 |
521 | (function() {
522 | if ( abort ) { return; }
523 |
524 | var scriptlet = function() {
525 | var magic = String.fromCharCode(Date.now() % 26 + 97) +
526 | Math.floor(Math.random() * 982451653 + 982451653).toString(36);
527 | var oe = window.error;
528 | window.onerror = function(msg, src, line, col, error) {
529 | if ( msg.indexOf(magic) !== -1 ) { return true; }
530 | if ( oe instanceof Function ) {
531 | return oe(msg, src, line, col, error);
532 | }
533 | }.bind();
534 | Object.defineProperty(window, 'upManager', {
535 | set: function() {
536 | throw new Error(magic);
537 | }
538 | });
539 | };
540 |
541 | scriptlets.push({
542 | scriptlet: scriptlet,
543 | targets: [
544 | '101greatgoals.com',
545 | '4chan.org',
546 | 'allthetests.com',
547 | 'biology-online.org',
548 | 'destructoid.com',
549 | 'eurweb.com',
550 | 'fullmatchesandshows.com',
551 | 'grammarist.com',
552 | 'jerusalemonline.com',
553 | 'lucianne.com',
554 | 'phonesreview.co.uk',
555 | 'thefreethoughtproject.com',
556 | 'veteranstoday.com',
557 | 'walla.co.il',
558 | 'yad2.co.il',
559 | ]
560 | });
561 | })();
562 |
563 | /*******************************************************************************
564 |
565 | Collate and add scriptlets to document.
566 |
567 | **/
568 |
569 | (function() {
570 | if ( scriptlets.length === 0 ) { return; }
571 |
572 | var restrFromString = function(s) {
573 | return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
574 | };
575 |
576 | var reFromArray = function(aa) {
577 | return new RegExp('(^|\\.)(' + aa.map(restrFromString).join('|') + ')$');
578 | };
579 |
580 | var scriptText = [], entry, re;
581 |
582 | while ( (entry = scriptlets.shift()) ) {
583 | if ( Array.isArray(entry.targets) ) {
584 | re = reFromArray(entry.targets);
585 | if ( re.test(hostname) === false ) { continue; }
586 | } else if ( Array.isArray(entry.exceptions) ) {
587 | re = reFromArray(entry.exceptions);
588 | if ( re.test(hostname) ) { continue; }
589 | }
590 | scriptText.push('(' + entry.scriptlet.toString() + ')("' + contentScriptSecret + '");');
591 | }
592 |
593 | if ( scriptText.length === 0 ) { return; }
594 |
595 | var elem = document.createElement('script');
596 | elem.appendChild(document.createTextNode(scriptText.join('\n')));
597 | try {
598 | (document.head || document.documentElement).appendChild(elem);
599 | } catch(ex) {
600 | }
601 | // Remove the script tag once executed (leave a clean DOM behind).
602 | elem.textContent = '';
603 | if ( elem.parentNode ) {
604 | elem.parentNode.removeChild(elem);
605 | }
606 | })();
607 |
608 |
609 |
610 | })();
611 |
--------------------------------------------------------------------------------
/src/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspenguin2017/uBlockProtector/0552c9ba7535678aea73b82a9f0639f992d29143/src/icon128.png
--------------------------------------------------------------------------------
/src/libdom.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A lightweight DOM manipulation library, will be expanded as needed.
3 | * Behaves quite differently than jQuery.
4 | */
5 | "use strict";
6 |
7 |
8 | /**
9 | * Shortcut for new $.Selection(input).
10 | * @function
11 | * @param {string} input - The query selector.
12 | * @return {$.Selection} The selection object.
13 | */
14 | var $ = input => new $.Selection(input);
15 |
16 | /**
17 | * Selection class.
18 | * Unless otherwise specified, all methods return the keyword this.
19 | * @class
20 | */
21 | $.Selection = class {
22 | /**
23 | * Constructor.
24 | * @constructor
25 | * @param {string} selector - The query selector.
26 | * @param {Array.} [override=undefined] - If this parameter
27 | * is present, current selection will be set to it and the query selector
28 | * will be ignored.
29 | */
30 | constructor(selector, override) {
31 | /**
32 | * The selected elements.
33 | * @member {Array.}
34 | */
35 | this.selection = override ? override : Array.from(document.querySelectorAll(selector));
36 | /**
37 | * The amount of selected elements.
38 | * @member {integer}
39 | */
40 | this.length = this.selection.length;
41 | }
42 |
43 |
44 | /**
45 | * Set or update CSS of all selected elements.
46 | * @method
47 | * @param {string} key - The key of the style, use "maxHeight" instead of
48 | * "max-height", similar for other keys with dashes in them.
49 | * @param {string} val - The value to set.
50 | */
51 | css(key, val) {
52 | for (let s of this.selection) {
53 | s.style[key] = val;
54 | }
55 | return this;
56 | }
57 | /**
58 | * Show all selected elements.
59 | * @method
60 | * @param {string} [state="block"] - The state to apply, defaults to
61 | * "block".
62 | */
63 | show(state = "block") {
64 | return this.css("display", state);
65 | }
66 | /**
67 | * Hide all selected elements. Current display mode will not be saved.
68 | * Things may break if you try to show them again.
69 | * @method
70 | */
71 | hide() {
72 | return this.css("display", "none");
73 | }
74 | /**
75 | * Remove all selected elements from DOM.
76 | * @method
77 | */
78 | remove() {
79 | for (let s of this.selection) {
80 | s.remove();
81 | }
82 | return this;
83 | }
84 | /**
85 | * Add classes to all selected elements.
86 | * @method
87 | * @param {string} ...args - Classes to add.
88 | */
89 | addClass(...args) {
90 | for (let s of this.selection) {
91 | s.classList.add(...args);
92 | }
93 | return this;
94 | }
95 | /**
96 | * Remove classes from all selected elements.
97 | * @method
98 | * @param {string} [...args=[]] - Classes to remove, omit to remove all.
99 | */
100 | rmClass(...args) {
101 | if (args.length) {
102 | for (let s of this.selection) {
103 | s.classList.remove(...args);
104 | }
105 | } else {
106 | for (let s of this.selection) {
107 | s.className = "";
108 | }
109 | }
110 | return this;
111 | }
112 |
113 |
114 | /**
115 | * Copy current selection, this is useful when you do not want selection
116 | * methods to update current selection.
117 | * @method
118 | * @return {$.Selection} The new Selection object.
119 | */
120 | copy() {
121 | return new $.Selection(null, this.selection.slice());
122 | }
123 | /**
124 | * Update current selection, only keep the selected element with given
125 | * index.
126 | * Clear current selection if no selected element has that index.
127 | * @method
128 | * @param {integer} i - The index, give a negative number to count from
129 | * end.
130 | */
131 | eq(i) {
132 | if (this.selection.length) {
133 | if (i < 0) {
134 | i += this.selection.length;
135 | }
136 | if (i >= 0 && i < this.selection.length) {
137 | this.selection = [this.selection[i]];
138 | this.length = 1;
139 | } else {
140 | this.selection = [];
141 | this.length = 0;
142 | }
143 | }
144 | return this;
145 | }
146 | /**
147 | * Update current selection, only keep the first selected element.
148 | * @method
149 | */
150 | first() {
151 | return this.eq(0);
152 | }
153 | /**
154 | * Update current selection, only keep the last selected element.
155 | * @method
156 | */
157 | last() {
158 | return this.eq(-1);
159 | }
160 | /**
161 | * Update current selection, set it to children of each selected elements
162 | * that match the new selector.
163 | * @method
164 | * @param {string} selector - The new query selector.
165 | */
166 | find(selector) {
167 | let newSelection = [];
168 | for (const s of this.selection) {
169 | const elems = s.querySelectorAll(selector);
170 | // newSelection = newSelection.concat(elems); also works, but this
171 | // creates a new array every time, so it may not be faster
172 | //
173 | // Note that the number of arguments is capped at around 30,000
174 | // depending on the browser, but there should not be that many
175 | // elements in the document
176 | newSelection.push(...elems);
177 | }
178 | this.selection = newSelection;
179 | this.length = newSelection.length;
180 | return this;
181 | }
182 | /**
183 | * Update current selection, set it to immediate children of each selected
184 | * elements that match the new selector.
185 | * @method
186 | * @param {string} selector - The new query selector.
187 | */
188 | children(selector) {
189 | return this.find(":scope > " + selector);
190 | }
191 | /**
192 | * Update current selection, set it to the parent of each selected
193 | * elements if exist.
194 | * Elements that do not have a parent will not be updated.
195 | * @method
196 | */
197 | parent() {
198 | for (let i = 0; i < this.selection.length; i++) {
199 | const elem = this.selection[i].parentNode;
200 | if (elem) {
201 | this.selection[i] = elem;
202 | }
203 | }
204 | return this;
205 | }
206 | /**
207 | * Update current selection, only keep elements that have children
208 | * matching a given selector.
209 | * @method
210 | * @param {string} selector - The query selector.
211 | * @param {boolean} [match=true] - Set to false to only keep elements
212 | * that do not have children matching the selector.
213 | */
214 | filter(selector, match = true) {
215 | let newSelection = [];
216 | for (const s of this.selection) {
217 | if (match === Boolean(s.querySelector(selector))) {
218 | newSelection.push(s);
219 | }
220 | }
221 | this.selection = newSelection;
222 | this.length = newSelection.length;
223 | return this;
224 | }
225 | /**
226 | * Update current selection, only keep elements that have the matcher
227 | * string in their textContent.
228 | * @method
229 | * @param {string} matcher - The matcher string.
230 | */
231 | includes(matcher) {
232 | let newSelection = [];
233 | for (const s of this.selection) {
234 | if (s.textContent.includes(matcher)) {
235 | newSelection.push(s);
236 | }
237 | }
238 | this.selection = newSelection;
239 | this.length = newSelection.length;
240 | return this;
241 | }
242 | /**
243 | * Update current selection, only keep elements that have the matcher
244 | * string as the beginning of their textContent.
245 | * @method
246 | * @param {string} matcher - The matcher string.
247 | */
248 | startsWith(matcher) {
249 | let newSelection = [];
250 | for (const s of this.selection) {
251 | if (s.textContent.startsWith(matcher)) {
252 | newSelection.push(s);
253 | }
254 | }
255 | this.selection = newSelection;
256 | this.length = newSelection.length;
257 | return this;
258 | }
259 | /**
260 | * Update current selection, only keep elements that have the matcher
261 | * string as the ending of their textContent.
262 | * @method
263 | * @param {string} matcher - The matcher string.
264 | */
265 | endsWith(matcher) {
266 | let newSelection = [];
267 | for (const s of this.selection) {
268 | if (s.textContent.endsWith(matcher)) {
269 | newSelection.push(s);
270 | }
271 | }
272 | this.selection = newSelection;
273 | this.length = newSelection.length;
274 | return this;
275 | }
276 | /**
277 | * Update current selection, only keep elements that have the matcher
278 | * string as their textContent.
279 | * @method
280 | * @param {string} matcher - The matcher string.
281 | */
282 | textIs(matcher) {
283 | let newSelection = [];
284 | for (const s of this.selection) {
285 | if (matcher === s.textContent) {
286 | newSelection.push(s);
287 | }
288 | }
289 | this.selection = newSelection;
290 | this.length = newSelection.length;
291 | return this;
292 | }
293 |
294 |
295 | /**
296 | * Add an event listener to all selected elements.
297 | * @param {string} ...args - Listener details
298 | * @param {Event} e - The appropriate event object.
299 | */
300 | on(...args) {
301 | for (let s of this.selection) {
302 | s.addEventListener(...args);
303 | }
304 | return this;
305 | }
306 | /**
307 | * Trigger a click event to all selected elements.
308 | * @method
309 | */
310 | click() {
311 | for (let s of this.selection) {
312 | s.click();
313 | }
314 | return this;
315 | }
316 |
317 |
318 | /**
319 | * Get or set textContent. Affects only the first element on get mode,
320 | * but affects all selected elements in set mode.
321 | * @method
322 | * @param {string} [text=undefined] - The text to set, omit to get.
323 | * @return {string|this} String in get mode, the keyword this in set mode.
324 | * An empty string will be returned if the textContent cannot be
325 | * retrieved.
326 | */
327 | text(text) {
328 | if (text === undefined) {
329 | return this.selection.length ? this.selection[0].textContent : "";
330 | } else {
331 | for (let s of this.selection) {
332 | s.textContent = text;
333 | }
334 | return this;
335 | }
336 | }
337 | /**
338 | * Get or set innerHTML. Affects only the first element on get mode, but
339 | * affects all selected elements in set mode.
340 | * @method
341 | * @param {DOMString} [html=undefined] - The DOM string to set, omit to
342 | * get.
343 | * @return {DOMString|this} DOM string in get mode, the keyword this in
344 | * set mode. An empty string will be returned if the innerHTML cannot
345 | * be retrieved.
346 | */
347 | html(html) {
348 | if (html === undefined) {
349 | return this.selection.length ? this.selection[0].innerHTML : "";
350 | } else {
351 | for (let s of this.selection) {
352 | s.innerHTML = html;
353 | }
354 | return this;
355 | }
356 | }
357 | /**
358 | * Get or set data. Affects only the first element on get mode, but
359 | * affects all selected elements in set mode.
360 | * @method
361 | * @param {string} name - The name of the data entry.
362 | * @param {string} [val=undefined] - The value to set, omit to get.
363 | * @return {Any|this} The data in get mode, the keyword this in set mode.
364 | * Undefined will be returned if the data cannot be retrieved.
365 | */
366 | data(name, val) {
367 | if (val === undefined) {
368 | return this.selection.length ? this.selection[0].dataset[name] : undefined;
369 | } else {
370 | for (let s of this.selection) {
371 | s.dataset[name] = val;
372 | }
373 | return this;
374 | }
375 | }
376 | /**
377 | * Get or set attribute. Affect only the first element on get mode, but
378 | * affect all selected elements in set mode.
379 | * @method
380 | * @param {string} name - The name of the attribute.
381 | * @param {string} [val=undefined] - The value to set, omit to get.
382 | * @return {Any|this} The attribute in get mode, the keyword this in set
383 | * mode. Undefined will be returned if the attribute cannot be retrieved.
384 | */
385 | attr(name, val) {
386 | if (val === undefined) {
387 | return this.selection.length ? this.selection[0].getAttribute(name) : undefined;
388 | } else {
389 | for (let s of this.selection) {
390 | s.setAttribute(name, val);
391 | }
392 | return this;
393 | }
394 | }
395 | /**
396 | * Delete an attribute.
397 | * @method
398 | * @param {string} name - The name of the attribute.
399 | */
400 | rmAttr(name) {
401 | for (let s of this.selection) {
402 | s.removeAttribute(name);
403 | }
404 | return this;
405 | }
406 | /**
407 | * Get or set property. Affect only the first element on get mode, but
408 | * affect all selected elements in set mode.
409 | * @method
410 | * @param {string} name - The name of the property.
411 | * @param {string} [val=undefined] - The value to set, omit to get.
412 | * @return {Any|this} The property in get mode, the keyword this in set
413 | * mode. Undefined will be returned if the property cannot be retrieved.
414 | */
415 | prop(name, val) {
416 | if (val === undefined) {
417 | return this.selection.length ? this.selection[0][name] : undefined;
418 | } else {
419 | for (let s of this.selection) {
420 | s[name] = val;
421 | }
422 | return this;
423 | }
424 | }
425 |
426 |
427 | /**
428 | * Insert HTML before the beginning of each selected elements if possible.
429 | * @method
430 | * @param {DOMString} input - The DOM string to insert.
431 | */
432 | before(input) {
433 | for (let s of this.selection) {
434 | // Must have parent node in this insert mode
435 | if (s.parentNode) {
436 | s.insertAdjacentHTML("beforebegin", input);
437 | }
438 | }
439 | return this;
440 | }
441 | /**
442 | * Insert HTML after the beginning of each selected elements.
443 | * @method
444 | * @param {DOMString} input - The DOM string to insert.
445 | */
446 | prepend(input) {
447 | for (let s of this.selection) {
448 | s.insertAdjacentHTML("afterbegin", input);
449 | }
450 | return this;
451 | }
452 | /**
453 | * Insert HTML before the end of each selected elements.
454 | * @method
455 | * @param {DOMString} input - The DOM string to insert.
456 | */
457 | append(input) {
458 | for (let s of this.selection) {
459 | s.insertAdjacentHTML("beforeend", input);
460 | }
461 | return this;
462 | }
463 | /**
464 | * Insert HTML after the end of each selected elements if possible.
465 | * @method
466 | * @param {DOMString} input - The DOM string to insert.
467 | */
468 | after(input) {
469 | for (let s of this.selection) {
470 | // Must have parent node in this insert mode
471 | if (s.parentNode) {
472 | s.insertAdjacentHTML("afterend", input);
473 | }
474 | }
475 | return this;
476 | }
477 |
478 |
479 | /**
480 | * Get offsetWidth of the first selected element.
481 | * @method
482 | * @return {integer} The offsetWidth, or -1 if the offsetWidth cannot be
483 | * retrieved.
484 | */
485 | width() {
486 | return this.selection.length ? this.selection[0].offsetWidth : -1;
487 | }
488 | /**
489 | * Get offsetHeight of the first selected element.
490 | * @method
491 | * @return {integer} The offsetHeight, or -1 if the offsetHeight cannot be
492 | * retrieved.
493 | */
494 | height() {
495 | return this.selection.length ? this.selection[0].offsetHeight : -1;
496 | }
497 | /**
498 | * Loop though each selected element.
499 | * @method
500 | * @param {Function} func - The handler.
501 | * @param {DOMElement} elem - The current DOM element.
502 | */
503 | each(func) {
504 | for (let s of this.selection) {
505 | func(s);
506 | }
507 | return this;
508 | }
509 | };
510 |
511 |
512 | /**
513 | * Send a XMLHttpRequest.
514 | * @function
515 | * @param {Object} details - Details about this request.
516 | * @param {string} method - The method of the request, usually "GET" or
517 | * "POST".
518 | * @param {string} url - The URL of the request.
519 | * @param {Object|undefined} [headers=undefined] - The headers of the
520 | * request.
521 | * @param {string|null} [payload=null] - The payload of the request.
522 | * @param {Function} onload - The load event handler.
523 | * @param {string} response - The response text.
524 | * @param {Function} onerror - The error event handler.
525 | */
526 | $.request = (details, onload, onerror) => {
527 | let req = new XMLHttpRequest();
528 |
529 | req.onreadystatechange = () => {
530 | if (req.readyState === XMLHttpRequest.DONE) {
531 | if (req.status === 200) {
532 | onload(req.responseText);
533 | } else {
534 | onerror();
535 | }
536 | }
537 | };
538 |
539 | req.open(details.method, details.url);
540 |
541 | if (details.headers) {
542 | for (const key in details.headers) {
543 | if (details.headers.hasOwnProperty(key)) {
544 | req.setRequestHeader(key, details.headers[key]);
545 | }
546 | }
547 | }
548 |
549 | req.send(details.payload || null);
550 | };
551 |
--------------------------------------------------------------------------------
/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Nano Defender Contributors",
3 | "background": {
4 | "scripts": [
5 | "common.js",
6 | "platform/chromium-vars.js",
7 | "background/core.js",
8 | "background/rules.js",
9 | "background/debug.js"
10 | ]
11 | },
12 | "browser_action": {
13 | "default_icon": {
14 | "128": "icon128.png"
15 | },
16 | "default_popup": "popup/index.html",
17 | "default_title": "Nano Defender Debug"
18 | },
19 | "content_scripts": [
20 | {
21 | "all_frames": true,
22 | "js": [
23 | "common.js",
24 | "libdom.js",
25 | "content/core.js",
26 | "content/rules-common.js",
27 | "content/rules-specific.js",
28 | "content/rules-sticky.js",
29 | "content/debug.js",
30 | "content/ubo-extra.js"
31 | ],
32 | "match_about_blank": true,
33 | "matches": [
34 | "http://*/*",
35 | "https://*/*"
36 | ],
37 | "run_at": "document_start"
38 | }
39 | ],
40 | "description": "Companion extension for Nano Adblocker",
41 | "homepage_url": "https://jspenguin2017.github.io/uBlockProtector/",
42 | "icons": {
43 | "128": "icon128.png"
44 | },
45 | "incognito": "split",
46 | "manifest_version": 2,
47 | "minimum_chrome_version": "69.0",
48 | "name": "Nano Defender Debug",
49 | "permissions": [
50 | "http://*/*",
51 | "https://*/*",
52 | "tabs",
53 | "webNavigation",
54 | "webRequest",
55 | "webRequestBlocking"
56 | ],
57 | "version": "15.0.0.205",
58 | "web_accessible_resources": [
59 | "resources/*"
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/src/platform/chromium-vars.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Platform constants for Chromium
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | a.NanoAdblockerExtensionID = "gabbbocakeomblphkmmnoamkioajlkfo";
30 |
31 | if (navigator.userAgent.includes(" Edg/"))
32 | a.NanoAdblockerExtensionID = "epbkapkgcmdmfpogenoebpdeibmfinpf";
33 |
34 | // ----------------------------------------------------------------------------------------------------------------- //
35 |
--------------------------------------------------------------------------------
/src/platform/edge-content.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Special content script for legacy Edge
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | if (a.domCmp(["windowscentral.com"])) {
30 | a.noAccess("adonisHash");
31 | a.beforeScript((script) => {
32 | if (script.textContent && script.textContent.includes("adBlocker")) {
33 | script.remove();
34 | }
35 | });
36 | }
37 |
38 | // ----------------------------------------------------------------------------------------------------------------- //
39 |
--------------------------------------------------------------------------------
/src/platform/edge-vars.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Platform constants for legacy Edge
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | a.NanoAdblockerExtensionID = "EdgeExtension_23837jspenguin2017NanoAdblocker_aegazecm1370c";
30 |
31 | // ----------------------------------------------------------------------------------------------------------------- //
32 |
--------------------------------------------------------------------------------
/src/platform/firefox-background.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Special background script for Firefox
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | //@pragma-if-debug
30 |
31 | // Debug rules
32 |
33 | if (a.debugMode) {
34 |
35 | {
36 | // https://github.com/uBlockOrigin/uAssets/issues/772
37 |
38 | a.dynamicServer(
39 | [
40 | "*://*.uplynk.com/preplay/*",
41 | ],
42 | [
43 | "xmlhttprequest",
44 | ],
45 | (details) => {
46 | let payload = "";
47 |
48 | const filter = browser.webRequest.filterResponseData(details.requestId);
49 | const decoder = new TextDecoder("utf-8");
50 | const encoder = new TextEncoder();
51 |
52 | filter.ondata = (e) => {
53 | payload += decoder.decode(e.data, { stream: true });
54 | };
55 | filter.onstop = () => {
56 | try {
57 | payload = JSON.parse(payload);
58 | } catch (err) {
59 | filter.write(encoder.encode(payload));
60 | filter.disconnect();
61 | return;
62 | }
63 |
64 | // Debug log
65 | console.log(payload.ads);
66 |
67 | payload.ads = {
68 | breakOffsets: [],
69 | breaks: [],
70 | placeholderOffsets: [],
71 | };
72 |
73 | filter.write(encoder.encode(JSON.stringify(payload)));
74 | filter.disconnect();
75 | };
76 | },
77 | [
78 | "fox.com",
79 | ],
80 | true,
81 | );
82 | }
83 |
84 | }
85 |
86 | //@pragma-end-if
87 |
88 | // ----------------------------------------------------------------------------------------------------------------- //
89 |
--------------------------------------------------------------------------------
/src/platform/firefox-content.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Special content script for Firefox
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | // Simply removing the node does not prevent execution of the script
30 |
31 | {
32 | const _remove = Element.prototype.remove;
33 | const remove = function () {
34 | if (this.tagName === "SCRIPT") {
35 | this.textContent = "";
36 | }
37 | _remove.call(this);
38 | };
39 | Element.prototype.remove = remove;
40 | }
41 |
42 | // ----------------------------------------------------------------------------------------------------------------- //
43 |
--------------------------------------------------------------------------------
/src/platform/firefox-vars.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Platform constants for Firefox
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | a.NanoAdblockerExtensionID = "{acf5b849-adb0-4004-b4ff-7f5332f48567}";
30 |
31 | // ----------------------------------------------------------------------------------------------------------------- //
32 |
--------------------------------------------------------------------------------
/src/popup/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0px;
3 | min-width: 250px;
4 | width: auto;
5 | user-select: none;
6 | }
7 |
8 | .title {
9 | background-color: #444444;
10 | color: #FFFFFF;
11 | font-size: 12px;
12 | text-align: center;
13 | padding: 5px;
14 | }
15 |
16 | .title > p {
17 | margin: 0px;
18 | }
19 |
20 | .wrapper {
21 | padding: 6px;
22 | }
23 |
24 | .wrapper:hover {
25 | background-color: #EEEEEE;
26 | }
27 |
28 | .wrapper > svg {
29 | margin-right: 3px;
30 | position: relative;
31 | top: 1px;
32 | width: 16px;
33 | }
34 |
35 | .wrapper > span {
36 | font-size: 14px;
37 | position: relative;
38 | top: -2px;
39 | }
40 |
41 | .separator.dashed {
42 | border-bottom: 1px dashed #CCCCCC;
43 | }
44 |
45 | .separator.solid {
46 | border-bottom: 1px solid #444444;
47 | }
48 |
--------------------------------------------------------------------------------
/src/popup/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Nano Defender Popup Panel
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
Home Page
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
Announcements
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
Troubleshooting
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
FAQ
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
Known Issues
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
Report an Issue
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
Quick Issue Reporter (Beta)
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
Source Code
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
License
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
Credits
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/popup/index.js:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 |
3 | Nano Defender - An anti-adblock defuser
4 | Copyright (C) 2016-2018 Nano Defender contributors
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 |
19 | *******************************************************************************
20 |
21 | Popup panel script.
22 |
23 | ******************************************************************************/
24 |
25 | "use strict";
26 |
27 | /*****************************************************************************/
28 |
29 | /**
30 | * Homepage links.
31 | * @const {Map}
32 | */
33 | const home = [
34 | "",
35 | "https://jspenguin2017.github.io/uBlockProtector/",
36 | "https://github.com/jspenguin2017/uBlockProtector",
37 | chrome.runtime.getURL("/reporter/index.html"),
38 | ];
39 |
40 | /*****************************************************************************/
41 |
42 | {
43 | const manifest = chrome.runtime.getManifest();
44 | $(".title > p").text(manifest.name + " " + manifest.version);
45 | }
46 |
47 | /*****************************************************************************/
48 |
49 | chrome.tabs.query({
50 | active: true,
51 | currentWindow: true,
52 | }, (tabs) => {
53 | if (chrome.runtime.lastError || tabs.length === 0)
54 | return;
55 |
56 | home[3] = home[3] + "?" + tabs[0].id;
57 | });
58 |
59 | /*****************************************************************************/
60 |
61 | $(".wrapper").on("click", function () {
62 | const url = home[this.dataset.home] + this.dataset.href;
63 | chrome.tabs.create({ url: url });
64 | });
65 |
66 | /*****************************************************************************/
67 |
--------------------------------------------------------------------------------
/src/reporter/index.css:
--------------------------------------------------------------------------------
1 | /* General */
2 | * {
3 | appearance: none;
4 | -moz-appearance: none;
5 | -webkit-appearance: none;
6 | font-family: Arial, sans-serif;
7 | }
8 |
9 | body {
10 | font-size: 100%;
11 | margin: 0px;
12 | }
13 |
14 | input[type="text"], textarea {
15 | border: none;
16 | margin: 0px;
17 | width: 100%;
18 | }
19 |
20 | textarea {
21 | resize: vertical;
22 | }
23 |
24 | select {
25 | border: 0px;
26 | padding: 1px 0px 1px 0px;
27 | width: 100%;
28 | }
29 |
30 | @media (min-width: 600px) {
31 | h1 {
32 | font-size: 3em;
33 | }
34 |
35 | h2 {
36 | font-size: 2.25em;
37 | }
38 |
39 | h3 {
40 | font-size: 1.755em;
41 | }
42 |
43 | h4 {
44 | font-size: 1.5em;
45 | }
46 |
47 | h5 {
48 | font-size: 1.245em;
49 | }
50 |
51 | h6 {
52 | font-size: 1.005em;
53 | }
54 |
55 | label {
56 | font-size: 1.5em;
57 | }
58 |
59 | p {
60 | font-size: 1.5em;
61 | }
62 |
63 | input[type="text"], textarea, select {
64 | font-size: 1.25em;
65 | }
66 | }
67 |
68 | /* Basic */
69 | .hidden {
70 | display: none;
71 | }
72 |
73 | .bold {
74 | font-weight: bold;
75 | }
76 |
77 | .float-left {
78 | float: left;
79 | }
80 |
81 | .float-right {
82 | float: right;
83 | }
84 |
85 | .clear-both {
86 | clear: both;
87 | }
88 |
89 | /* Colors */
90 | .green {
91 | background-color: #009323;
92 | color: #FFFFFF;
93 | }
94 |
95 | .blue {
96 | background-color: #2463C9;
97 | color: #FFFFFF;
98 | }
99 |
100 | .red {
101 | background-color: #FF5555;
102 | color: #FFFFFF;
103 | }
104 |
105 | /* Buttons */
106 | button {
107 | border: none;
108 | font-weight: bold;
109 | height: 35px;
110 | margin: 0px;
111 | opacity: 0.7;
112 | padding: 0px 15px;
113 | }
114 |
115 | button:focus {
116 | outline: none;
117 | }
118 |
119 | button:hover {
120 | opacity: 0.85;
121 | }
122 |
123 | button:active {
124 | opacity: 1;
125 | }
126 |
127 | @media (min-width: 600px) {
128 | button {
129 | font-size: 1.5em;
130 | height: 60px;
131 | padding: 0px 25px;
132 | }
133 | }
134 |
135 | /* Containers */
136 | .container {
137 | background-color: #EEEEEE;
138 | padding: 10px;
139 | margin: 20px 0px;
140 | }
141 |
142 | @media (min-width: 600px) {
143 | .container {
144 | padding-left: 10%;
145 | padding-right: 10%;
146 | }
147 | }
148 |
149 | .container.footer {
150 | background-color: #FFFFFF;
151 | padding-bottom: 0px;
152 | padding-top: 0px;
153 | margin: 0px;
154 | }
155 |
156 | .container.footer p {
157 | color: #808080;
158 | font-size: 0.8em;
159 | }
160 |
161 | /* Popups */
162 | .popup-container {
163 | background-color: rgba(0, 0, 0, 0.33);
164 | display: none;
165 | height: 100%;
166 | left: 0px;
167 | position: fixed;
168 | top: 0px;
169 | width: 100%;
170 | }
171 |
172 | .popup-container.open {
173 | display: block;
174 | }
175 |
176 | .popup {
177 | background-color: #FFFFFF;
178 | margin: 40px auto;
179 | opacity: 1;
180 | padding: 25px;
181 | width: 80%;
182 | }
183 |
184 | .popup h1, .popup h2, .popup h3, .popup h4, .popup h5, .popup h6 {
185 | border-bottom: 1px solid #808080;
186 | margin: 0px;
187 | padding-bottom: 3px;
188 | }
189 |
190 | @media (min-width: 600px) {
191 | .popup {
192 | width: 60%;
193 | }
194 |
195 | .popup button {
196 | transform: scale(0.75);
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/reporter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Quick Issue Reporter
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Quick Issue Reporter (Beta)
19 |
Have you checked the troubleshooting guide ?
20 |
Also, please check for open reports in the reports tracker before submitting new reports. Duplicate reports may be ignored.
21 |
Do not attempt to submit spam or illegal content, or you will be blocked from sending new reports.
22 |
23 |
Issue type:
24 |
25 |
26 | Choose one...
27 | Anti-adblock
28 | Ads or popups not blocked
29 | Blocking too much
30 | Other issue (no Internet URL)
31 | Other issue
32 |
33 |
34 |
35 |
URL where this issue occure:
36 |
37 |
38 |
39 |
40 |
41 | Additional details (optional):
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
By clicking "Send", you consent to the Privacy Policy .
50 |
Send
51 |
52 |
53 |
54 |
55 |
61 |
62 |
70 |
71 |
77 |
78 |
87 |
88 |
96 |
97 |
107 |
108 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/src/reporter/index.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------------------------------------------- //
2 |
3 | // Nano Defender - An anti-adblock defuser
4 | // Copyright (C) 2016-2019 Nano Defender contributors
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU General Public License as published by
8 | // the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU General Public License
17 | // along with this program. If not, see .
18 |
19 | // ----------------------------------------------------------------------------------------------------------------- //
20 |
21 | // Script for quick issue reporter
22 |
23 | // ----------------------------------------------------------------------------------------------------------------- //
24 |
25 | "use strict";
26 |
27 | // ----------------------------------------------------------------------------------------------------------------- //
28 |
29 | const knownGood = [
30 | // Wrong page
31 | "addons.mozilla.org",
32 | "chrome.google.com",
33 | "hugoxu.com",
34 | "github.com",
35 | "jspenguin2017.github.io",
36 | "local.ntp",
37 | "www.microsoft.com", // Do not remove "www"
38 |
39 | // Bad installation
40 | "blockadblock.com",
41 | "detectadblock.com",
42 |
43 | // Other known good
44 | "youtube.com",
45 | ];
46 |
47 | const knownBad = [
48 | // https://github.com/NanoMeow/QuickReports/issues/903
49 | "browserleaks.com",
50 | ];
51 |
52 | // ----------------------------------------------------------------------------------------------------------------- //
53 |
54 | let initialUrl = "";
55 |
56 | // ----------------------------------------------------------------------------------------------------------------- //
57 |
58 | const lastReportStorageKey = "quick-issue-reporter-last-report";
59 | const bugReportDomainSuffix = "-nanobugreport.hugoxu.com";
60 |
61 | const reportsRateLimit = 900000; // 15 minutes
62 | const detailsLengthLimit = 3072;
63 |
64 | const updateDetailsLengthDisplay = () => {
65 | const length = $("#details").prop("value").length;
66 |
67 | $("#character-count").text(length.toString() + "/" + detailsLengthLimit.toString());
68 |
69 | if (length > detailsLengthLimit)
70 | $("#character-count").addClass("red");
71 | else
72 | $("#character-count").rmClass("red");
73 | };
74 |
75 | // ----------------------------------------------------------------------------------------------------------------- //
76 |
77 | const appName = (() => {
78 | const manifest = chrome.runtime.getManifest();
79 | return manifest.name + " " + manifest.version;
80 | })();
81 |
82 | const showMessage = (msg) => {
83 | $("#msg-specific-error p").html(msg);
84 | $("#msg-specific-error").addClass("open");
85 | };
86 |
87 | const domCmp = (domain, matchers) => {
88 | if (domain.endsWith(bugReportDomainSuffix))
89 | return false;
90 |
91 | for (const d of matchers) {
92 | if (domain.endsWith(d) && (domain.length === d.length || domain.charAt(domain.length - d.length - 1) === "."))
93 | return true;
94 | }
95 | return false;
96 | };
97 |
98 | const randId = () => {
99 | const r = Math.random();
100 | return r.toString(16).substring(2);
101 | };
102 |
103 | // ----------------------------------------------------------------------------------------------------------------- //
104 |
105 | $("#category").on("change", function () {
106 | if (this.value === "Ads") {
107 | showMessage(
108 | "For missed ads and popups, please report to the EasyList Forum " +
109 | "first.",
110 | );
111 | }
112 |
113 | if (this.value === "Bug")
114 | $("#url").prop("value", "https://" + randId() + bugReportDomainSuffix + "/").attr("disabled", "");
115 | else
116 | $("#url").prop("value", initialUrl).rmAttr("disabled");
117 | });
118 |
119 | $("#details").on("input", updateDetailsLengthDisplay);
120 | updateDetailsLengthDisplay();
121 |
122 | $("#send").on("click", async () => {
123 | const category = $("#category").prop("value");
124 | const url = $("#url").prop("value").trim();
125 | const details = $("#details").prop("value");
126 |
127 | if (!category)
128 | return void showMessage("Please select an issue type.");
129 |
130 | let domain = /^https?:\/\/([^/]+)/.exec(url);
131 | if (!domain)
132 | return void showMessage("Please enter a valid URL.");
133 |
134 | domain = domain[1];
135 | if (domCmp(domain, knownGood))
136 | return void $("#msg-known-good").addClass("open");
137 | if (domCmp(domain, knownBad))
138 | return void $("#msg-known-bad").addClass("open");
139 |
140 | if (category === "Other" && details.length < 10) {
141 | return void showMessage(
142 | "Please add a quick explanation for the "Other issue" category that you have chosen " +
143 | "(minimum 10 characters).",
144 | );
145 | }
146 | if (category === "Bug" && details.length < 100) {
147 | return void showMessage(
148 | "Please incude a detailed step-by-step reproduction guide for this issue (minimum 100 characters).",
149 | );
150 | }
151 |
152 | if (details.length > detailsLengthLimit) {
153 | return void showMessage(
154 | "Additional details can be at most " + detailsLengthLimit.toString() + " characters long.",
155 | );
156 | }
157 |
158 | const payload = [
159 | "send",
160 | "Quick Issue Reporter",
161 | navigator.userAgent,
162 | appName,
163 | "",
164 | "[" + category + "] " + url,
165 | "",
166 | ];
167 | if (url !== initialUrl) {
168 | payload.push(
169 | "Original URL: `" + initialUrl + "`",
170 | "",
171 | );
172 | }
173 | payload.push(details);
174 |
175 | let response;
176 | try {
177 | response = await post(payload.join("\n"));
178 | } catch (err) {
179 | return void $("#msg-generic-error").addClass("open");
180 | }
181 |
182 | if (response === "ok") {
183 | localStorage.setItem(lastReportStorageKey, Date.now());
184 | $("#msg-report-sent").addClass("open");
185 | $("#main").addClass("hidden");
186 | } else {
187 | console.error(response);
188 | $("#msg-generic-error").addClass("open");
189 | }
190 | });
191 |
192 | $(".popup-container button.float-right").on("click", function () {
193 | this.parentNode.parentNode.classList.remove("open");
194 | });
195 |
196 | // ----------------------------------------------------------------------------------------------------------------- //
197 |
198 | const init = () => {
199 | let lastReport = localStorage.getItem(lastReportStorageKey);
200 |
201 | // Maximum accuracy of integer is about 16 digits
202 | // Cap at 15 digits to be safe, which is still more than enough to represent the next 30 thousand years
203 | if (/^\d{13,15}$/.test(lastReport))
204 | lastReport = parseInt(lastReport);
205 |
206 | const now = Date.now();
207 | if (typeof lastReport === "number" && lastReport + reportsRateLimit > now)
208 | $("#msg-rate-limited").addClass("open");
209 | else
210 | $("#main").rmClass("hidden");
211 | };
212 |
213 | if (/^\?\d{1,15}$/.test(location.search)) {
214 | chrome.tabs.get(parseInt(location.search.substring(1)), (tab) => {
215 | if (!chrome.runtime.lastError) {
216 | initialUrl = tab.url;
217 | if ($("#url").prop("value").trim() === "")
218 | $("#url").prop("value", tab.url);
219 | }
220 |
221 | init();
222 | });
223 | } else {
224 | init();
225 | }
226 |
227 | // ----------------------------------------------------------------------------------------------------------------- //
228 |
--------------------------------------------------------------------------------
/src/reporter/paper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Paper library.
3 | */
4 | "use strict";
5 |
6 | /**
7 | * Toggle wait screen.
8 | * @function
9 | */
10 | const wait = (() => {
11 | const $popup = document.getElementById("paper-wait");
12 |
13 | let state = false;
14 | return () => {
15 | if (state) {
16 | $popup.classList.remove("open");
17 | } else {
18 | $popup.classList.add("open");
19 | }
20 |
21 | state = !state;
22 | };
23 | })();
24 |
25 | /**
26 | * Send a POST request to the standard API endpoint.
27 | * @async @function
28 | * @param {string} payload - The payload to send.
29 | * @return {string} The response text when successful.
30 | * @throws {XMLHttpRequest} The XMLHttpRequest instance when not successful.
31 | */
32 | const post = (payload) => {
33 | return new Promise((resolve, reject) => {
34 | wait();
35 |
36 | let req = new XMLHttpRequest();
37 |
38 | req.onreadystatechange = () => {
39 | if (req.readyState === XMLHttpRequest.DONE) {
40 | wait();
41 |
42 | if (req.status === 200) {
43 | resolve(req.responseText);
44 | } else {
45 | reject(req);
46 | }
47 | }
48 | };
49 |
50 | req.open("POST", "https://legacy.hugoxu.com/PrivateMessage/Report.php");
51 | req.send(payload);
52 | });
53 | };
54 |
--------------------------------------------------------------------------------
/src/resources/blank.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jspenguin2017/uBlockProtector/0552c9ba7535678aea73b82a9f0639f992d29143/src/resources/blank.mp4
--------------------------------------------------------------------------------
/src/resources/fw.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Moat FreeWheel JSPEM surrogate.
3 | */
4 | ; (() => {
5 | "use strict";
6 |
7 | try {
8 | window.console.error("[Nano] Surrogate Injected :: FreeWheel SDK");
9 | } catch (err) { }
10 |
11 | window.MoatFreeWheelJSPEM = class {
12 | init() { }
13 | dispose() { }
14 | };
15 | })();
16 |
--------------------------------------------------------------------------------
/src/resources/ima3.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Interactive Media Ads Software Development Kit surrogate.
3 | * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis
4 | */
5 | ; (() => {
6 | "use strict";
7 |
8 | try {
9 | window.console.error("[Nano] Surrogate Injected :: IMA SDK");
10 | } catch (err) { }
11 |
12 | let warnCount = 0;
13 |
14 | window.google = window.google || {};
15 |
16 | // Interfaces are not implemented
17 | window.google.ima = {
18 | AdDisplayContainer: class {
19 | // constructor(container, video, click) { }
20 | initialize() { }
21 | destroy() { }
22 | },
23 |
24 | AdError: class {
25 | constructor(message, code, type) {
26 | this._message = message;
27 | this._code = code;
28 | this._type = type;
29 | }
30 | getErrorCode() {
31 | return this._code;
32 | }
33 | getInnerError() {
34 | return null;
35 | }
36 | getMessage() {
37 | return this._message;
38 | }
39 | getType() {
40 | return this._type;
41 | }
42 | getVastErrorCode() {
43 | return window.google.ima.AdError.ErrorCode.UNKNOWN_ERROR;
44 | }
45 | toString() {
46 | return "AdError " + this._code + ": " + this._message + ".";
47 | }
48 | },
49 |
50 | AdErrorEvent: class extends ErrorEvent {
51 | constructor(error, context) {
52 | super(error);
53 | this._errObj = error;
54 | this._context = context;
55 | }
56 | getError() {
57 | return this._errObj;
58 | }
59 | getUserRequestContext() {
60 | return this._context;
61 | }
62 | },
63 |
64 | AdEvent: class extends Event {
65 | constructor(type, ad, adData) {
66 | super(type);
67 | this._ad = ad;
68 | this._adData = adData;
69 | }
70 | getAd() {
71 | return this._ad;
72 | }
73 | getAdData() {
74 | return this._adData;
75 | }
76 | },
77 |
78 | AdsLoader: class {
79 | constructor() {
80 | this._onError = [];
81 | this._onErrorScope = [];
82 | this._error = new window.google.ima.AdErrorEvent(
83 | new window.google.ima.AdError(
84 | "No ads available",
85 | window.google.ima.AdError.ErrorCode.VAST_NO_ADS_AFTER_WRAPPER,
86 | window.google.ima.AdError.Type.AD_LOAD,
87 | ),
88 | {},
89 | );
90 | }
91 | addEventListener(event, handler, capture, scope) {
92 | // The real SDK should also always return error
93 | if (event === window.google.ima.AdErrorEvent.Type.AD_ERROR) {
94 | this._onError.push(handler);
95 | this._onErrorScope.push(scope);
96 | } else if (warnCount < 10) {
97 | warnCount++;
98 | try {
99 | window.console.warn("[Nano] IMA Event Ignored :: " + event);
100 | } catch (err) { }
101 | }
102 | }
103 | removeEventListener(event, handler) {
104 | // Capture and scope are not checked
105 | if (event === window.google.ima.AdErrorEvent.Type.AD_ERROR) {
106 | for (let i = 0; i < this._onError.length; i++) {
107 | // This should be good enough
108 | if (this._onError[i] === handler) {
109 | this._onError.splice(i, 1);
110 | this._onErrorScope.splice(i, 1);
111 | i--;
112 | }
113 | }
114 | }
115 | // Ignore otherwise
116 | }
117 | _dispatchError() {
118 | for (let i = 0; i < this._onError.length; i++) {
119 | if (this._onErrorScope[i]) {
120 | this._onError[i].call(this._onErrorScope[i], this._error);
121 | } else {
122 | this._onError[i](this._error);
123 | }
124 | }
125 | }
126 |
127 | contentComplete() { }
128 | destroy() { }
129 | getSettings() {
130 | return window.google.ima.settings;
131 | }
132 | requestAds() {
133 | window.setTimeout(this._dispatchError.bind(this), 10);
134 | }
135 | },
136 |
137 | AdsManagerLoadedEvent: class extends Event {
138 | constructor() {
139 | // Not implemented
140 | throw new window.Error("[Nano] Not Implemented :: Neutralized AdsManager");
141 | }
142 | },
143 |
144 | AdsRenderingSettings: class {
145 | // Not implemented
146 | // constructor() { }
147 | },
148 |
149 | AdsRequest: class {
150 | // Partially implemented
151 | // constructor() { }
152 | setAdWillAutoPlay() { }
153 | setAdWillPlayMuted() { }
154 | },
155 |
156 | CompanionAdSelectionSettings: class {
157 | // Not implemented
158 | // constructor() { }
159 | },
160 |
161 | ImaSdkSettings: class {
162 | // Partially implemented
163 | // constructor() { }
164 | getCompanionBackfill() {
165 | return window.google.ima.ImaSdkSettings.CompanionBackfillMode.ALWAYS;
166 | }
167 | getDisableCustomPlaybackForIOS10Plus() {
168 | return false;
169 | }
170 | getDisableFlashAds() {
171 | return true;
172 | }
173 | getLocale() {
174 | return "en-CA";
175 | }
176 | getNumRedirects() {
177 | return 1;
178 | }
179 | getPlayerType() {
180 | return "Unknown";
181 | }
182 | getPlayerVersion() {
183 | return "1.0.0";
184 | }
185 | getPpid() {
186 | return "2GjCgoECAP0IbU";
187 | }
188 |
189 | setAutoPlayAdBreaks() { }
190 | setCompanionBackfill() { }
191 | setDisableCustomPlaybackForIOS10Plus() { }
192 | setDisableFlashAds() { }
193 | setLocale() { }
194 | setNumRedirects() { }
195 | setPlayerType() { }
196 | setPlayerVersion() { }
197 | setPpid() { }
198 | setVpaidAllowed() { }
199 | setVpaidMode() { }
200 | },
201 |
202 | UiElements: {
203 | COUNTDOWN: "countdown",
204 | },
205 |
206 | ViewMode: {
207 | FULLSCREEN: "fullscreen",
208 | NORMAL: "normal",
209 | },
210 |
211 | VERSION: "3.173.4",
212 | };
213 |
214 | window.google.ima.AdError.ErrorCode = {
215 | VIDEO_PLAY_ERROR: 400,
216 | FAILED_TO_REQUEST_ADS: 1005,
217 | REQUIRED_LISTENERS_NOT_ADDED: 900,
218 | VAST_LOAD_TIMEOUT: 301,
219 | VAST_NO_ADS_AFTER_WRAPPER: 303,
220 | VAST_MEDIA_LOAD_TIMEOUT: 402,
221 | VAST_TOO_MANY_REDIRECTS: 302,
222 | VAST_ASSET_MISMATCH: 403,
223 | VAST_LINEAR_ASSET_MISMATCH: 403,
224 | VAST_NONLINEAR_ASSET_MISMATCH: 503,
225 | VAST_ASSET_NOT_FOUND: 1007,
226 | VAST_UNSUPPORTED_VERSION: 102,
227 | VAST_SCHEMA_VALIDATION_ERROR: 101,
228 | VAST_TRAFFICKING_ERROR: 200,
229 | VAST_UNEXPECTED_LINEARITY: 201,
230 | VAST_UNEXPECTED_DURATION_ERROR: 202,
231 | VAST_WRAPPER_ERROR: 300,
232 | NONLINEAR_DIMENSIONS_ERROR: 501,
233 | COMPANION_REQUIRED_ERROR: 602,
234 | VAST_EMPTY_RESPONSE: 1009,
235 | UNSUPPORTED_LOCALE: 1011,
236 | INVALID_ADX_EXTENSION: 1105,
237 | INVALID_ARGUMENTS: 1101,
238 | UNKNOWN_AD_RESPONSE: 1010,
239 | UNKNOWN_ERROR: 900,
240 | OVERLAY_AD_PLAYING_FAILED: 500,
241 | VIDEO_ELEMENT_USED: -1,
242 | VIDEO_ELEMENT_REQUIRED: -1,
243 | VAST_MEDIA_ERROR: -1,
244 | ADSLOT_NOT_VISIBLE: -1,
245 | OVERLAY_AD_LOADING_FAILED: -1,
246 | VAST_MALFORMED_RESPONSE: -1,
247 | COMPANION_AD_LOADING_FAILED: -1,
248 | };
249 |
250 | window.google.ima.AdError.Type = {
251 | AD_LOAD: "adLoadError",
252 | AD_PLAY: "adPlayError",
253 | };
254 |
255 | window.google.ima.AdErrorEvent.Type = {
256 | AD_ERROR: "adError",
257 | };
258 |
259 | window.google.ima.AdEvent.Type = {
260 | CONTENT_RESUME_REQUESTED: "contentResumeRequested",
261 | CONTENT_PAUSE_REQUESTED: "contentPauseRequested",
262 | CLICK: "click",
263 | DURATION_CHANGE: "durationChange",
264 | EXPANDED_CHANGED: "expandedChanged",
265 | STARTED: "start",
266 | IMPRESSION: "impression",
267 | PAUSED: "pause",
268 | RESUMED: "resume",
269 | FIRST_QUARTILE: "firstquartile",
270 | MIDPOINT: "midpoint",
271 | THIRD_QUARTILE: "thirdquartile",
272 | COMPLETE: "complete",
273 | USER_CLOSE: "userClose",
274 | LINEAR_CHANGED: "linearChanged",
275 | LOADED: "loaded",
276 | AD_CAN_PLAY: "adCanPlay",
277 | AD_METADATA: "adMetadata",
278 | AD_BREAK_READY: "adBreakReady",
279 | INTERACTION: "interaction",
280 | ALL_ADS_COMPLETED: "allAdsCompleted",
281 | SKIPPED: "skip",
282 | SKIPPABLE_STATE_CHANGED: "skippableStateChanged",
283 | LOG: "log",
284 | VIEWABLE_IMPRESSION: "viewable_impression",
285 | VOLUME_CHANGED: "volumeChange",
286 | VOLUME_MUTED: "mute",
287 | };
288 |
289 | window.google.ima.AdsManagerLoadedEvent.Type = {
290 | ADS_MANAGER_LOADED: "adsManagerLoaded",
291 | };
292 |
293 | window.google.ima.CompanionAdSelectionSettings.CreativeType = {
294 | ALL: "All",
295 | FLASH: "Flash",
296 | IMAGE: "Image",
297 | };
298 |
299 | window.google.ima.CompanionAdSelectionSettings.ResourceType = {
300 | ALL: "All",
301 | HTML: "Html",
302 | IFRAME: "IFrame",
303 | STATIC: "Static",
304 | };
305 |
306 | window.google.ima.CompanionAdSelectionSettings.SizeCriteria = {
307 | IGNORE: "IgnoreSize",
308 | SELECT_EXACT_MATCH: "SelectExactMatch",
309 | SELECT_NEAR_MATCH: "SelectNearMatch",
310 | };
311 |
312 | window.google.ima.ImaSdkSettings.CompanionBackfillMode = {
313 | ALWAYS: "always",
314 | ON_MASTER_AD: "on_master_ad",
315 | };
316 |
317 | window.google.ima.ImaSdkSettings.VpaidMode = {
318 | DISABLED: 0,
319 | ENABLED: 1,
320 | INSECURE: 2,
321 | };
322 |
323 | window.google.ima.settings = new window.google.ima.ImaSdkSettings();
324 | })();
325 |
--------------------------------------------------------------------------------
/src/resources/jquery.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery Anti-adblock plugin defuser.
3 | */
4 | ; (() => {
5 | "use strict";
6 |
7 | try {
8 | window.console.error("[Nano] Generic Solution Triggered :: jQuery Plugin");
9 | } catch (err) { }
10 |
11 | try {
12 | window.$.adblock = false;
13 | } catch (err) { }
14 | try {
15 | window.jQuery.adblock = false;
16 | } catch (err) { }
17 | })();
18 |
--------------------------------------------------------------------------------
/tests/check-syntax.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Check for syntax error.
3 | */
4 | "use strict";
5 |
6 | /**
7 | * Load modules.
8 | * @const {Module}
9 | */
10 | const assert = require("assert");
11 | const esprima = require("esprima");
12 | const fs = require("./promise-fs.js");
13 |
14 | /**
15 | * Validate syntax of a JavaScript file.
16 | * @async @function
17 | * @param {string} file - The path to the file to check.
18 | */
19 | const validateJS = async (file) => {
20 | const data = await fs.readFile(file, "utf8");
21 | esprima.parse(data);
22 | };
23 | /**
24 | * Validate syntax of a JSON file.
25 | * @async @function
26 | * @param {string} file - The path to the file to check.
27 | */
28 | const validateJSON = async (file) => {
29 | const data = await fs.readFile(file, "utf8");
30 | JSON.parse(data);
31 | };
32 |
33 | /**
34 | * Check syntax recursively for one directory.
35 | * @async @function
36 | * @param {string} directory - The path to the directory to check.
37 | */
38 | exports.validateDirectory = async (directory) => {
39 | const files = await fs.readdir(directory);
40 |
41 | let tasks = [];
42 | for (const file of files) {
43 | tasks.push(fs.lstat(directory + "/" + file));
44 | }
45 | tasks = await Promise.all(tasks);
46 | assert(files.length === tasks.length);
47 |
48 | let validateTasks = [];
49 | for (let i = 0; i < files.length; i++) {
50 | assert(!tasks[i].isSymbolicLink());
51 |
52 | if (tasks[i].isDirectory()) {
53 | // One directory at a time to make sure things will not get
54 | // overloaded
55 | await exports.validateDirectory(directory + "/" + files[i]);
56 | continue;
57 | }
58 |
59 | assert(tasks[i].isFile());
60 | if (files[i].endsWith(".js")) {
61 | validateTasks.push(validateJS(directory + "/" + files[i]));
62 | } else if (files[i].endsWith(".json")) {
63 | validateTasks.push(validateJSON(directory + "/" + files[i]));
64 | }
65 | }
66 | await Promise.all(validateTasks);
67 | };
68 |
--------------------------------------------------------------------------------
/tests/promise-fs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Promisified file system module.
3 | *
4 | * Watches for "--trace-fs" command line argument, if exists
5 | * file system calls are logged.
6 | */
7 | "use strict";
8 |
9 |
10 | /**
11 | * Load modules.
12 | * @const {Module}
13 | */
14 | const fs = require("fs");
15 | const util = require("util");
16 |
17 | /**
18 | * The new file system namespace, functions are added as needed.
19 | * @const {Namespace}
20 | */
21 | const newfs = {
22 | appendFile: util.promisify(fs.appendFile),
23 | copyFile: util.promisify(fs.copyFile),
24 | createReadStream: fs.createReadStream,
25 | createWriteStream: fs.createWriteStream,
26 | lstat: util.promisify(fs.lstat),
27 | mkdir: util.promisify(fs.mkdir),
28 | readdir: util.promisify(fs.readdir),
29 | readFile: util.promisify(fs.readFile),
30 | writeFile: util.promisify(fs.writeFile),
31 | };
32 |
33 | /**
34 | * Print variables, truncate long strings.
35 | * @function
36 | * @param {Any} ...args - Variables to print.
37 | */
38 | const varDump = (...args) => {
39 | let out = [];
40 | for (const arg of args) {
41 | if (typeof arg === "string" && arg.length > 200) {
42 | out.push("");
43 | } else {
44 | out.push(arg);
45 | }
46 | }
47 | console.log(...out);
48 | };
49 | /**
50 | * Make a file system access tracer.
51 | * @function
52 | * @param {string} name - The function to intercept.
53 | * @return {Function} The tracer.
54 | */
55 | const makeTracer = (name) => {
56 | return (...args) => {
57 | varDump("fs." + name, ...args);
58 | return newfs[name](...args);
59 | };
60 | };
61 |
62 |
63 | if (process.argv.includes("--trace-fs")) {
64 | module.exports = {};
65 | for (const key in newfs) {
66 | if (newfs.hasOwnProperty(key)) {
67 | module.exports[key] = makeTracer(key);
68 | }
69 | }
70 | } else {
71 | module.exports = newfs;
72 | }
73 |
--------------------------------------------------------------------------------
/tests/tests-main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Tests entry point.
3 | */
4 | "use strict";
5 |
6 |
7 | /**
8 | * Load modules.
9 | * @const {Module}
10 | */
11 | const assert = require("assert");
12 | const checkSyntax = require("./check-syntax.js");
13 |
14 |
15 | process.on("unhandledRejection", (e) => {
16 | throw e;
17 | });
18 |
19 | assert(/[\\/]uBlockProtector$/.test(process.cwd()));
20 |
21 | (async () => {
22 | await checkSyntax.validateDirectory("./src");
23 | })();
24 |
--------------------------------------------------------------------------------